能力:你有木有高并发设计经验的能力,在系统到达百万级别出现瓶颈的时候,有什么优化的思路
其他知识
1: 消息队列是高并发系统常见的一种组件,明白其中的实质,不能光知道有什么特点,真正的应用到实际的生产环境中,首先解耦
是最大的特点,在高并发中,消息中间件是最重要的法宝
2 缓存技术是空间换时间的思想
3 压缩是时间换空间的思想
将类似追逐摩尔定律不断提升 CPU 性能的方案叫做 Scale-up(纵向扩展),把类似 CPU 多核心的方案叫做 Scale-out
是一种常见的高并发设计方法,我们在很多文章和演讲中都能听到这个名词,与之共同出现的还有它的反义词:同步。比如分布式服务框架 Dubbo 中有同步方法调用和异步方法调用,IO 模型中有同步 IO 和异步 IO。
采用异步方式,后端处理会把请求丢到消息队列中,同时快速响应用户,告诉用户我们正在排队处理,然后释放资源来处理更多的请求,订票请求处理完之后,在通知用户订票成功或者失败
如果访问量增加,你的网站打开速度就会很慢,对于小型的可以,但是要求打开快的网站就有限制
流量分为两种:
优化原则:
紧跟需要
】在优化过程中,时刻了解你的优化让响应时间减少了多少,提升了多少吞吐量
需要不断的测试,找原因,制定优化方案,直到最后达到目标为止
度量性能指标的响应时间
一般用吞吐量||响应时间来衡量并发和流量注意:单次的响应时间是木有意义的,你需要知道一段时间是的性能情况是什么样的通常有一下集中进行衡量
概念:执行的任务的响应时间都在10ms,他的吞吐量是在每秒100次,那么我们怎样来优化性能从而提升系统的并发能力?
主要有两种思路: 1:提高系统的处理核心数, 2:另一种是减少单词任务的响应时间: 首先确定系统CPU密集型合适IO密集型的,
优化的方向:
1:采用非阻塞的RPC远程调用 2:将计算密集和io密集的逻辑分开,单独的线程池,调正线程比例压榨单机性能 3:做缓存,io消耗的缓存和计算耗时的缓存(多级缓存,数据压缩降低宽带【水龙头端口大小】)
4:采用享元模式,用好对象池和本地线程池空间,尽量减少对象创建和消耗,提高服用
5: 业务拆分,像状态变化后的外部通知,业务监控,通过es或者solr等副本同步数据,无需在主流程中做的事情都拆掉,走cannel监听表数据变化,推MQ保证最终一致的方式从业务完全解耦
6:fork_join 分而治之的处理大任务,并发编程,采用多线程并发的方式处理业务。
7:数据库配置优化,查询优化。
问题:将问题丢该线程池,出现阻塞的问题,这个时候由可能会出现线程池中的核心数量和最大线程数过小,会出现这样的情况
池化的优点:1:池子的最大值和最小值设置非常重要.有的时候需要根据实际场景进行设置 2:池子中的对象先先进行初始化完成,这叫做池子的预热,比方说使用线程池时就需要预先初始化所有的核心线程。如果池子未经过预热,就有可能在系统在刚开始重启的时候请求会出现请求慢的情况 3:池化技术:核心是一种空间换时间的思想,我们需要时刻的关注空间内存的变化,避免出现内存占满的情况,导致JVM一直GC的出现
线程池中提供了预热线程的方法:ThreadpoolExecutor提供了prestartAllCoreThreads方法可以预先启动核心线程
单机部署的Mysql部署在4核8G的服务器上,大概可以支撑500TPS和10000QPS
主从复制原理:
Mysql主从复制主要依赖于binlog,binlog中Mysql中所有变化并以二进制形式保存在磁盘上二进制日志文件。这个过程是异步的,主库上的操作不会等待binlog同步的完成。
复制流程
:
首先从库在连接到主节点时会创建一个 IO 线程,用以请求主库更新的 binlog,并且把接收到的 binlog 信息写入一个叫做 relay log 的日志文件中,而主库也会创建一个 log dump 线程来发送 binlog 给从库;同时,从库还会创建一个 SQL 线程读取 relay log 中的内容,并且在从库中做回放,最终实现主从的一致性。这是一种比较常见的主从复制方式。分库分表两中:
垂直拆分(常规操作,将表作为操作对象,直接进行表最小单位操作)
:也就是将数据库的表拆分到多个不同的数据库中。垂直拆分的原则一般是按照业务类型来拆分,核心思想是专库专用,将业务耦合度比较高的表拆分到单独的库中。举个形象的例子,就是在整理衣服的时候,将羽绒服、毛衣、T 恤分别放在不同的格子里。这样可以解决我在开篇提到的第三个问题:把不同的业务的数据分拆到不同的数据库节点上,这样一旦数据库发生故障时只会影响到某一个模块的功能,不会影响到整体功能,从而实现了数据层面的故障隔离。缺点
:因为数据库垂直拆分后依然不能解决某一个业务模块的数据大量膨胀的问题
水平拆分(以表中数据为最小单位,操作表中的数据)
:和垂直拆分的关注点不同,垂直拆分的关注点在于业务相关性,而水平拆分指的是将单一数据表按照某一种规则拆分到多个数据库和多个数据表中,关注点在数据的特点。拆分规则有下面两种:
1实体表中ID来进行拆分
===按照某一个字段的哈希值做拆分,这种拆分规则比较适用于实体表,比如说用户表,内容表,我们一般按照这些实体表的 ID 字段来拆分。比如说我们想把用户表拆分成 16 个库,每个库是 64 张表,那么可以先对用户 ID 做哈希,哈希的目的是将 ID 尽量打散,然后再对 16 取余,这样就得到了分库后的索引值;对 64 取余,就得到了分表后的索引值。
2:按照时间进行分表,比如一个月:月表
:. 另一种比较常用的是按照某一个字段的区间来拆分,比较常用的是时间字段。你知道在内容表里面有“创建时间”的字段,而我们也是按照时间来查看一个人发布的内容。我们可能会要看昨天的内容,也可能会看一个月前发布的内容,这时就可以按照创建时间的区间来分库分表,比如说可以把一个月的数据放入一张表中,这样在查询时就可以根据创建时间先定位数据存储在哪个表里面,再按照查询条件来查询。
性能出现问题:所以最合适的思路是你要建立一个昵称和 ID 的映射表,可以使用类似于HashMap的映射表进行关联字典查询
1:使用业务作为主键:比如使用用户手机号或者email或者身份证作为主键
2:使用生成的唯一主键(重要)【雪花算法】
主键使用:1:主键有序会提升数据写入的性能,
现在主流中间件与Mysql搭配使用:
目前的项目就是 MySql 配合 Elasticsearch 使用。Elasticsearch主要是做搜索用,写还是 MySql,同时发Kafka消息,消费端写ES。ES存在丢数据的问题,所以会定时全量/增量从 MySql 中捞数据,覆写 ES,保证数据的一直性。
强调命中率,不要什么都加入都缓存中
】数据库成为瓶颈,动态数据查询要如何加速
DAU:日活跃用户数量
pv:页面访问量
vu:页面去重用户访问量
十几万 DAU
了常见缓存:静态缓存、分布式缓存和热点本地缓存
缓存的意义:1: 缓存可以有多层,比如上面提到的静态缓存处在负载均衡层,分布式缓存处在应用层和数据库层之间,本地缓存处在应用层。我们需要将请求尽量挡在上层,因为越往下层,对于并发的承受能力越差;
2:缓存命中率是我们对于缓存最重要的一个监控项,越是热点的数据,缓存的命中率就越高。
实在不行就需要好好考虑一凡了,缓存穿透怎么解决?缓存击穿怎么解决?缓存雪崩怎么解决?数据不一致性问题怎么解决?数据结构众多怎么选择合适的数据结构?缓存的key:value怎么设计?缓存怎么加载?过期时间怎么设置?补偿机制怎么设计?缓存具体选择什么方案?需不需要多层缓存?多层缓存的复杂度怎么控制?
缓存是否使用
:没有达到需要引用缓存需要的情况下,尽量不要过早使用缓存。
缓存的坑很多,并且维护成本极高。在处理缓存的适合需要多考虑很多问题。
曾经碰到这样的情况:
调用别人写的查询服务,但是查找到的数据却迟迟无法更新为最新数据。最后,重新写了直接查库的接口,才解决问题。
并且,缓存如果频繁更新,频繁失效 反而会带来性能的消耗。再带上杨晓峰老师的一句话:“过早的优化是万恶之源"
总结
:缓存的分类缓存的不足
###### memcache是分布式的,guava是本地的===》这个 类似于HashMap映射集合,下次使用的时候直接引入
核心缓存维持在99%,哪怕1%有时候也会操守致命打击
在写策略中,能否先删除缓存,后更新数据库呢?答案是不行的
假设某个用户的年龄是 20,请求 A 要更新用户年龄为 21,所以它会删除缓存中的内容。这时,另一个请求 B 要读取这个用户的年龄,它查询缓存发现未命中后,会从数据库中读取到年龄为 20,并且写入到缓存中,然后请求 A 继续更改数据库,将用户的年龄更新为 21,这就造成了缓存和数据库的不一致
很好解决数据就近访问问题,加快静态资源访问速度
1:如何将用户的请求映射到 CDN 节点上;
2如何根据用户的地理位置信息选择到比较近的节点。
域名解析过程:
1:一开始,域名解析请求先会检查本机hosts文件,查看当前域名是否有对应ip
2:木有的话,就请求Local DNS 是否有域名解析结果的缓存
3:如果木有开始迭代DNS查询,先请求跟DNS,跟DNS返回顶级DNS的地址,在请求.com顶级DNS得到baidu.com域名服务器地址
特点总结
1.DNS 技术是 CDN 实现中使用的核心技术,可以将用户的请求映射到 CDN 节点上;
2.DNS 解析结果需要做本地缓存,降低 DNS 解析过程的响应时间;
3.GSLB 可以给用户返回一个离着他更近的节点,加快静态资源的访问速度。
缓存穿透:1:在使用过滤器的时候,要关注布隆过滤器对内存空间的消耗