高并发,你真的理解透彻了吗?

前言

高并发,几乎是每一个程序员都想拥有的经验。缘由很简单:随着流量变大,会遇到各类各样的技术问题,好比接口响应超时、CPU load升高、GC频繁、死锁、大数据量存储等等,这些问题能推进咱们在技术深度上不断精进。前端

做为阅读福利,小编也整理一套高并发相关的学习笔记(包含脑图、面试、手写pdf等)如今免费分享给阅读到本篇的Java程序员朋友们,须要的自行领取程序员

最全 高并发 学习笔记+面试真题面试

在过往的面试中,若是候选人作太高并发的项目,我一般会让对方谈谈对于高并发的理解,可是能系统性地回答好此问题的人并很少,大概分红这样几类:redis

一、对数据化的指标没有概念:不清楚选择什么样的指标来衡量高并发系统?分不清并发量和QPS,甚至不知道本身系统的总用户量、活跃用户量,平峰和高峰时的QPS和TPS等关键数据。算法

二、设计了一些方案,可是细节掌握不透彻:讲不出该方案要关注的技术点和可能带来的反作用。好比读性能有瓶颈会引入缓存,可是忽视了缓存命中率、热点key、数据一致性等问题。数据库

三、理解片面,把高并发设计等同于性能优化:大谈并发编程、多级缓存、异步化、水平扩容,却忽视高可用设计、服务治理和运维保障。编程

四、掌握大方案,却忽视最基本的东西:能讲清楚垂直分层、水平分区、缓存等大思路,却没意识去分析数据结构是否合理,算法是否高效,没想过从最根本的IO和计算两个维度去作细节优化。缓存

这篇文章,我想结合本身的高并发项目经验,系统性地总结下高并发须要掌握的知识和实践思路,但愿对你有所帮助。内容分红如下3个部分:性能优化

  • 如何理解高并发?
  • 高并发系统设计的目标是什么?
  • 高并发的实践方案有哪些?

如何理解高并发?

高并发意味着大流量,须要运用技术手段抵抗流量的冲击,这些手段比如操做流量,能让流量更平稳地被系统所处理,带给用户更好的体验。服务器

咱们常见的高并发场景有:淘宝的双十一、春运时的抢票、微博大V的热点新闻等。除了这些典型事情,每秒几十万请求的秒杀系统、天天千万级的订单系统、天天亿级日活的信息流系统等,均可以归为高并发。

很显然,上面谈到的高并发场景,并发量各不相同,那到底多大并发才算高并发呢?

一、不能只看数字,要看具体的业务场景。不能说10W QPS的秒杀是高并发,而1W QPS的信息流就不是高并发。信息流场景涉及复杂的推荐模型和各类人工策略,它的业务逻辑可能比秒杀场景复杂10倍不止。所以,不在同一个维度,没有任何比较意义。

二、业务都是从0到1作起来的,并发量和QPS只是参考指标,最重要的是:在业务量逐渐变成原来的10倍、100倍的过程当中,你是否用到了高并发的处理方法去演进你的系统,从架构设计、编码实现、甚至产品方案等维度去预防和解决高并发引发的问题?而不是一味的升级硬件、加机器作水平扩展。

此外,各个高并发场景的业务特色彻底不一样:有读多写少的信息流场景、有读多写多的交易场景,那是否有通用的技术方案解决不一样场景的高并发问题呢?

我以为大的思路能够借鉴,别人的方案也能够参考,可是真正落地过程当中,细节上还会有无数的坑。另外,因为软硬件环境、技术栈、以及产品逻辑都无法作到彻底一致,这些都会致使一样的业务场景,就算用相同的技术方案也会面临不一样的问题,这些坑还得一个个趟。

所以,这篇文章我会将重点放在基础知识、通用思路、和我曾经实践过的有效经验上,但愿让你对高并发有更深的理解。

高并发系统设计的目标是什么?

先搞清楚高并发系统设计的目标,在此基础上再讨论设计方案和实践经验才有意义和针对性。

2.1 宏观目标

高并发毫不意味着只追求高性能,这是不少人片面的理解。从宏观角度看,高并发系统设计的目标有三个:高性能、高可用,以及高可扩展。

一、高性能:性能体现了系统的并行处理能力,在有限的硬件投入下,提升性能意味着节省成本。同时,性能也反映了用户体验,响应时间分别是100毫秒和1秒,给用户的感觉是彻底不一样的。

二、高可用:表示系统能够正常服务的时间。一个整年不停机、无端障;另外一个隔三差五出线上事故、宕机,用户确定选择前者。另外,若是系统只能作到90%可用,也会大大拖累业务。

三、高扩展:表示系统的扩展能力,流量高峰时可否在短期内完成扩容,更平稳地承接峰值流量,好比双11活动、明星离婚等热点事件。 这3个目标是须要通盘考虑的,由于它们互相关联、甚至也会相互影响。

好比说:考虑系统的扩展能力,你会将服务设计成无状态的,这种集群设计保证了高扩展性,其实也间接提高了系统的性能和可用性。

再好比说:为了保证可用性,一般会对服务接口进行超时设置,以防大量线程阻塞在慢请求上形成系统雪崩,那超时时间设置成多少合理呢?通常,咱们会参考依赖服务的性能表现进行设置。

2.2 微观目标

再从微观角度来看,高性能、高可用和高扩展又有哪些具体的指标来衡量?为何会选择这些指标呢?

2.2.1 性能指标

经过性能指标能够度量目前存在的性能问题,同时做为性能优化的评估依据。通常来讲,会采用一段时间内的接口响应时间做为指标。

一、平均响应时间:最经常使用,可是缺陷很明显,对于慢请求不敏感。好比1万次请求,其中9900次是1ms,100次是100ms,则平均响应时间为1.99ms,虽然平均耗时仅增长了0.99ms,可是1%请求的响应时间已经增长了100倍。

二、TP90、TP99等分位值:将响应时间按照从小到大排序,TP90表示排在第90分位的响应时间, 分位值越大,对慢请求越敏感。 三、吞吐量:和响应时间呈反比,好比响应时间是1ms,则吞吐量为每秒1000次。

一般,设定性能目标时会兼顾吞吐量和响应时间,好比这样表述:在每秒1万次请求下,AVG控制在50ms如下,TP99控制在100ms如下。对于高并发系统,AVG和TP分位值必须同时要考虑。

另外,从用户体验角度来看,200毫秒被认为是第一个分界点,用户感受不到延迟,1秒是第二个分界点,用户能感觉到延迟,可是能够接受。

所以,对于一个健康的高并发系统,TP99应该控制在200毫秒之内,TP999或者TP9999应该控制在1秒之内。

2.2.2 可用性指标

高可用性是指系统具备较高的无端障运行能力,可用性 = 正常运行时间 / 系统总运行时间,通常使用几个9来描述系统的可用性。 对于高并发系统来讲,最基本的要求是:保证3个9或者4个9。缘由很简单,若是你只能作到2个9,意味着有1%的故障时间,像一些大公司每一年动辄千亿以上的GMV或者收入,1%就是10亿级别的业务影响。

2.2.3 可扩展性指标

面对突发流量,不可能临时改造架构,最快的方式就是增长机器来线性提升系统的处理能力。

对于业务集群或者基础组件来讲,扩展性 = 性能提高比例 / 机器增长比例,理想的扩展能力是:资源增长几倍,性能提高几倍。一般来讲,扩展能力要维持在70%以上。

可是从高并发系统的总体架构角度来看,扩展的目标不只仅是把服务设计成无状态就好了,由于当流量增长10倍,业务服务能够快速扩容10倍,可是数据库可能就成为了新的瓶颈。

像MySQL这种有状态的存储服务一般是扩展的技术难点,若是架构上没提早作好规划(垂直和水平拆分),就会涉及到大量数据的迁移。

所以,高扩展性须要考虑:服务集群、数据库、缓存和消息队列等中间件、负载均衡、带宽、依赖的第三方等,当并发达到某一个量级后,上述每一个因素均可能成为扩展的瓶颈点。

高并发的实践方案有哪些?

了解了高并发设计的3大目标后,再系统性总结下高并发的设计方案,会从如下两部分展开:先总结下通用的设计方法,而后再围绕高性能、高可用、高扩展分别给出具体的实践方案。

3.1 通用的设计方法

通用的设计方法主要是从「纵向」和「横向」两个维度出发,俗称高并发处理的两板斧:纵向扩展和横向扩展。

3.1.1 纵向扩展(scale-up)

它的目标是提高单机的处理能力,方案又包括:

一、提高单机的硬件性能:经过增长内存、 CPU核数、存储容量、或者将磁盘 升级成SSD 等堆硬 件 的 方 式 来 提高 。

二、提高单机的软件性能:使用缓存减小IO次数,使用并发或者异步的方式增长吞吐量。

3.1.2 横向扩展(scale-out)

由于单机性能总会存在极限,因此最终还须要引入横向扩展,经过集群部署以进一步提升并发处理能力,又包括如下2个方向:

一、作好分层架构:这是横向扩展的提早,由于高并发系统每每业务复杂,经过分层处理能够简化复杂问题,更容易作到横向扩展。 上面这种图是互联网最多见的分层架构,固然真实的高并发系统架构会在此基础上进一步完善。好比会作动静分离并引入CDN,反向代理层能够是LVS+Nginx,Web层能够是统一的API网关,业务服务层可进一步按垂直业务作微服务化,存储层能够是各类异构数据库。

二、各层进行水平扩展:无状态水平扩容,有状态作分片路由。业务集群一般能设计成无状态的,而数据库和缓存每每是有状态的,所以须要设计分区键作好存储分片,固然也能够经过主从同步、读写分离的方案提高读性能。

3.2 具体的实践方案

下面再结合个人我的经验,针对高性能、高可用、高扩展3个方面,总结下可落地的实践方案。

3.2.1 高性能的实践方案

一、集群部署,经过负载均衡减轻单机压力。

二、多级缓存,包括静态数据使用CDN、本地缓存、分布式缓存等,以及对缓存场景中的热点key、缓存穿透、缓存并发、数据一致性等问题的处理。

三、分库分表和索引优化,以及借助搜索引擎解决复杂查询问题。

四、考虑NoSQL数据库的使用,好比HBase、TiDB等,可是团队必须熟悉这些组件,且有较强的运维能力。

五、异步化,将次要流程经过多线程、MQ、甚至延时任务进行异步处理。

六、限流,须要先考虑业务是否容许限流(好比秒杀场景是容许的),包括前端限流、Nginx接入层的限流、服务端的限流。

七、对流量进行 削峰填谷 ,经过 MQ承接流量。

八、并发处理,经过多线程将串行逻辑并行化。

九、预计算,好比抢红包场景,能够提早计算好红包金额缓存起来,发红包时直接使用便可。

十、 缓存预热 ,经过异步 任务 提早 预热数据到本地缓存或者分布式缓存中。

十一、减小IO次数,好比数据库和缓存的批量读写、RPC的批量接口支持、或者经过冗余数据的方式干掉RPC调用。

十二、减小IO时的数据包大小,包括采用轻量级的通讯协议、合适的数据结构、去掉接口中的多余字段、减小缓存key的大小、压缩缓存value等。

1三、程序逻辑优化,好比将大几率阻断执行流程的判断逻辑前置、For循环的计算逻辑优化,或者采用更高效的算法。

1四、各类池化技术的使用和池大小的设置,包括HTTP请求池、线程池(考虑CPU密集型仍是IO密集型设置核心参数)、数据库和Redis链接池等。

1五、JVM优化,包括新生代和老年代的大小、GC算法的选择等,尽量减小GC频率和耗时。

1六、锁选择,读多写少的场景用乐观锁,或者考虑经过分段锁的方式减小锁冲突。

上述方案无外乎从计算和 IO 两个维度考虑全部可能的优化点,须要有配套的监控系统实时了解当前的性能表现,并支撑你进行性能瓶颈分析,而后再遵循二八原则,抓主要矛盾进行优化。

3.2.2 高可用的实践方案

一、对等节点的故障转移,Nginx和服务治理框架均支持一个节点失败后访问另外一个节点。

二、非对等节点的故障转移,经过心跳检测并实施主备切换(好比redis的哨兵模式或者集群模式、MySQL的主从切换等)。

三、接口层面的超时设置、重试策略和幂等设计。

四、降级处理:保证核心服务,牺牲非核心服务,必要时进行熔断;或者核心链路出问题时,有备选链路。

五、限流处理:对超过系统处理能力的请求直接拒绝或者返回错误码。

六、MQ场景的消息可靠性保证,包括producer端的重试机制、broker侧的持久化、consumer端的ack机制等。

七、灰度发布,能支持按机器维度进行小流量部署,观察系统日志和业务指标,等运行平稳后再推全量。

八、监控报警:全方位的监控体系,包括最基础的CPU、内存、磁盘、网络的监控,以及Web服务器、JVM、数据库、各种中间件的监控和业务指标的监控。

九、灾备演练:相似当前的“混沌工程”,对系统进行一些破坏性手段,观察局部故障是否会引发可用性问题。

高可用的方案主要从冗余、取舍、系统运维3个方向考虑,同时须要有配套的值班机制和故障处理流程,当出现线上问题时,可及时跟进处理。

3.2.3 高扩展的实践方案

一、合理的分层架构:好比上面谈到的互联网最多见的分层架构,另外还能进一步按照数据访问层、业务逻辑层对微服务作更细粒度的分层(可是须要评估性能,会存在网络多一跳的状况)。

二、存储层的拆分:按照业务维度作垂直拆分、按照数据特征维度进一步作水平拆分(分库分表)。

三、业务层的拆分:最多见的是按照业务维度拆(好比电商场景的商品服务、订单服务等),也能够按照核心接口和非核心接口拆,还能够按照请求源拆(好比To C和To B,APP和H5 )。

写在最后

高并发确实是一个复杂且系统性的问题,因为篇幅有限,诸如分布式Trace、全链路压测、柔性事务都是要考虑的技术点。另外,若是业务场景不一样,高并发的落地方案也会存在差别,可是整体的设计思路和可借鉴的方案基本相似。

高并发设计一样要秉承架构设计的3个原则:简单、合适和演进。"过早的优化是万恶之源",不能脱离业务的实际状况,更不要过分设计,合适的方案就是最完美的。

但愿这篇文章能带给你关于高并发更全面的认识,若是你也有可借鉴的经验和深刻的思考,欢迎评论区留言讨论。最后也不要忘记点赞+关注啊,后面也会更新更多的Java相关的知识的!

相关文章
相关标签/搜索