前言
互联网架构设计有三高分别是,高可用,高扩展,高并发,本文主要以高并发设计为主来和大家分享互联网架构中的常用高并发手段。
高并发的考核指标
对于高并发的衡量有两个重要的指标:
吞吐量:表示架构每秒能抗多少并发
响应延迟:表示每个请求多久可以得到响应
系统性能优化的目标就是:缩短响应时间,提高并发数,让系统处于合理的状态
系统性能优化手段
空间换时间
这种针对的是系统时间是瓶颈应用, 我们希望缓存复用计算结果,降低时间开销,因为CPU时间较内存容量更加昂贵
比如:我们知道在实际的系统里面,我们一定都会请求数据库,请求完数据库以后,我们往往会把结果缓存起来,如果每次请求数据库不把结果缓存起来,实时的查询数据库,一定会造成每次的计算时间变长,针对这种情况我们可以吧计算的结果缓存到cache里面,这就是空间换时间的一个基本的方法
缓存复用计算结果,降低时间开销,因为CPU时间较内存容量更加昂贵
时间换空间
这个时候我们的空间已经很大了,数据大小是瓶颈,我们就希望通过一些计算,让我们的空间使用量变低
例如一:网络传输是瓶颈,使用系统时间换取传输的空间,使用HTTP的gzip压缩算法,这样本来是1M的数据,通过gzip算法压缩之后就剩下100k的数据量,就是增加了发送端的CPU压缩和接收端的解压缩操作,是生产过程中用的比较多的操作
例如二:App的请求分类接口,使用版本号判断哪些数据更新,只下载更新的数据,比如我的业务是一个前端页面,每次用户打开都需要频繁的拉取数据,占用大量的资源,通过在服务器请求增加版本号判断和用户本地的资源是否一致,如果一致就不需要拉取资源,如果不一致就拉取资源,这样版本号计算降低需要频繁拉取的数据的问题,也是生产过程中用的比较多的操作
找到系统瓶颈
分析系统业务流程,找到关键路径并分解优化,通常业务流程本身的优化,可以解决系统本身80%的性能问题
通常:一个服务集群4w的QPS,调用量前5的接口贡献了3.5w的QPS,对关键路径的代码优化收益最大,当然系统剩下的部分也不能忽视,比如剩下5kqps接口若性能有问题也可能把整体服务性能拖垮
系统性能优化层次
做高并发的优化层次:从整体到细节,从全局角度到局部视角
架构设计优化方面
高并发的架构设计方面应该考虑,如何拆分系统,如何使各部分系统整体负载更加均衡,充分发挥硬件设施性能优势,减少系统内部开销,常用方法如下:
1、系统微服务化,无状态化设计,动态水平弹性扩展
2、调用链路梳理,热点数据尽量靠近用户
3、分布式cache、多级多类型缓存
4、容量规划
5、分库分表,读写分离,数据分片
算法逻辑方面
算法逻辑方面,关注算法选择是否高效,算法逻辑优化,空间时间优化任务并行处理,使用无锁数据结构等,通过算法可以对并发量提高很多,举例如下:
1、当系统时间是瓶颈,采取空间换时间的逻辑算法,分配更多空间节省系统时间
(1)缓存复用计算结果,降低时间开销,CPU时间较内存容量更加昂贵
(2)比如像java的ThreadLocal,将数据存在线程的jvm里面,需要的时候直接来拿
2、当系统空间容量是瓶颈,采取时间换空间算法策略
(1)比如网络传输是瓶颈,使用系统时间换取空间的压缩方式,HTTP的gzip压缩算法
(2)APP的请求分类接口,使用版本号判断哪些数据更新,只下载更新的数据,使用更多的代码逻辑处理更细粒度的数据
3、并行执行,比如一段逻辑调用了多了RPC接口,而这些接口之间没有数据依赖,则可以考虑并行调用,降低响应时间
4、异步执行,分析业务流程中的主次流程,把次要流程拆分出来异步执行,更进一步可以拆分到单独的模块去执行,比如使用消息队列,彻底和核心流程解耦,提高核心流程的稳定性以及降低响应时间
5、增量式算法,复用之前的计算结果,比如一个报表服务,要从全量数据中生成报表数据量很大,但是每次增量的数据较少,则可以考虑只计算增量数据和之前计算结果合并,这样处理的数据量就小很多
代码优化层次
关注代码细节优化,代码实现是否合理,是否创建了过多的对象,循环遍历是否高效,cache使用的是否合理,是否重用计算结果等
1、循环遍历是否合理高效,不要在循环里调RPC接口、查询分布式缓存、执行SQL等
一个先组装好批量,在开始调用的例子:比如我要查询100个商品,有了商品id,但是代码通过商品id查询了100次的数据库才得到结果,这样就会导致系统的性能很慢,因为网络请求的成本是昂贵的,这个时候我可以通过一个批量调用的方式,一次传100个id,查询我的数据库,一次就获取到数据
2、代码逻辑避免生成过多对象或无效对象
比如我们在输出debug的时候,可以通过直接修改参数进行输出,但是一个同学呢,往往就会通过添加一个if判断的方式,来判断debug这个日志级别是否存在,这样每次调用都会创建一个新的无效对象,一个是浪费空间,一个是浪费时间
3、数据结果和集合类,ArrayList、HashMap初始容量设置是否合理
如果数据结构设置不合理,那么它一定会频繁的扩容,一旦频繁的扩容,他的代价是很高的
4、对数据对象是否合理重用,比如通过RPC查到的数据能复用则必须复用,没必要每次执行,比如通过DB查询到的数据放到缓存中
5、根据数据访问特性选择合适的数据结构,比如读多写少,考虑CopyOnWriteArrayList(写时Copy副本)
6、拼接字符串的时候是使用String相加还是使用StringBuilder进行append(在StringBuilder的容量预分配的情况下,StringBuilder的性能比String 相加性能高15倍左右)
7、是否正确初始化数据。有些全局共享的数据,饿汉式模式,在用户访问之前先初始化好中,这样用户访问的时候就不用在获取了,节约用户的访问时间
8、扩大到一般场景,业务系统使用缓存降低响应时间提高性能,比如提高缓存命中率,但是也有一些场景不适合使用cache,比如读写比例相当,或者写多读少
9、很聚焦的高频访问,时效性要求不高很适合缓存提升性能,很聚焦的高频访问业务如banner,广告位,时效性要求不是特别高,比如更新了可以不用实时体现,很适合使用缓存提升性能
10、如果对数据实时性要求高,比如严格的时效性,需要慎重考虑更新缓存带来的一致性问题
11、时效性和缓存的冲突,比如商品服务队商品进行了缓存,由于更新缓存和更新商品不是同一个事物,则对数据时效性要求高的如交易,就只能从数据库查询商品信息
结束
其实对于高并发架构来说,能用机器的硬件来搞定,就用机器的硬件来搞,这样是最划算的,把机器的性能优化到极致当然是可以的,但是这样对于很多公司来说,投资回报率都没有直接升级硬件来的高
转载请注明:西门飞冰的博客 » 互联网高并发架构设计手段