摘要:本文介绍高并发系统的度量指标,讲述高并发系统的设计思路,再梳理高并发的关键技术,最后结合做者的经验作一些延伸探讨。
当前,数字化在给企业带来业务创新,推进企业高速发展的同时,也给企业的IT软件系统带来了严峻的挑战。面对流量高峰,不一样的企业是如何经过技术手段解决高并发难题的呢?程序员
软件系统有三个追求:高性能、高并发、高可用,俗称三高。三者既有区别也有联系,门门道道不少,全面讨论须要三天三夜,本篇讨论高并发。面试
高并发(High Concurrency)。并发是操做系统领域的一个概念,指的是一段时间内多任务流交替执行的现象,后来这个概念被泛化,高并发用来指大流量、高请求的业务情景,好比春运抢票,电商双十一,秒杀大促等场景。算法
不少程序员天天忙着搬砖,平时接触不到高并发,哪天受不了跑去面试,还经常会被面试官犀利的高并发问题直接KO,其实吧,高并发系统也不高深,我保证任何一个智商在线的看过这篇文章后,都能打败恐惧,重拾生活的信心。数据库
本文先介绍高并发系统的度量指标,而后讲述高并发系统的设计思路,再梳理高并发的关键技术,最后结合做者的经验作一些延伸探讨。编程
既然是高并发系统,那并发必定要高,否则就名存实亡。并发的指标通常有QPS、TPS、IOPS,这几个指标都是可归为系统吞吐率,QPS越高系统能hold住的请求数越多,但光关注这几个指标不够,咱们还须要关注RT,即响应时间,也就是从发出request到收到response的时延,这个指标跟吞吐每每是此消彼长的,咱们追求的是必定时延下的高吞吐。segmentfault
好比有100万次请求,99万次请求都在10毫秒内响应,其余次数10秒才响应,平均时延不高,但时延高的用户受不了,因此,就有了TP90/TP99指标,这个指标不是求平均,而是把时延从小到大排序,取排名90%/99%的时延,这个指标越大,对慢请求越敏感。后端
除此以外,有时候,咱们也会关注可用性指标,这可归到稳定性。缓存
通常而言,用户感知友好的高并发系统,时延应该控制在250毫秒之内。安全
什么样的系统才能称为高并发?这个很差回答,由于它取决于系统或者业务的类型。不过我能够告诉你一些众所周知的指标,这样能帮助你下次在跟人扯淡的时候稍微靠点儿谱,不至于贻笑大方。性能优化
一般,数据库单机每秒也就能抗住几千这个量级,而作逻辑处理的服务单台每秒抗几万、甚至几十万都有可能,而消息队列等中间件单机每秒处理个几万没问题,因此咱们常常听到每秒处理数百万、数千万的消息中间件集群,而像阿某的API网关,每日百亿请求也有可能。
高并发的设计思路有两个方向:
提高单机处理能力又可分为硬件和软件两个方面:
为了解决分布式系统的复杂性问题,通常会用到架构分层和服务拆分,经过分层作隔离,经过微服务解耦。
这个理论上没有上限,只要作好层次和服务划分,加机器扩容就能知足需求,但实际上并不是如此,一方面分布式会增长系统复杂性,另外一方面集群规模上去以后,也会引入一堆AIOps、服务发现、服务治理的新问题。
由于垂直向的限制,因此,咱们一般更关注水平扩展,高并发系统的实施也主要围绕水平方向展开。
玩具式的网络服务程序,用户能够直连服务器,甚至不须要数据库,直接写磁盘文件。但春运购票系统显然不能这么作,它确定扛不住这个压力,那通常的高并发系统是怎么作呢?好比某宝这样的正经系统是怎么处理高并发的呢?
其实大的思路都差很少,层次划分 + 功能划分。能够把层次划分理解为水平方向的划分,而功能划分理解为垂直方向的划分。
首先,用户不能直连服务器,要作分布式就要解决“分”的问题,有多个服务实例就须要作负载均衡,有不一样服务类型就须要服务发现。
负载均衡就是把负载(request)均衡分配到不一样的服务实例,利用集群的能力去对抗高并发,负载均衡是服务集群化的实施要素,它分3种:
因此,完整的负载均衡链路是 client <-> DNS负载均衡 -> F5 -> LVS/SLB -> NGINX
无论选择哪一种LB策略,或者组合LB策略,逻辑上,咱们均可以视为负载均衡层,经过添加负载均衡层,咱们将负载均匀分散到了后面的服务集群,具有基础的高并发能力,但这只是万里长征第一步。
前面经过负载均衡解决了无状态服务的水平扩展问题,但咱们的系统不全是无状态的,后面一般还有有状态的数据库,因此解决了前面的问题,存储有可能成为系统的瓶颈,咱们须要对有状态存储作分片路由。
数据库的单机QPS通常不高,也就几千,显然知足不了高并发的要求。
因此,咱们须要作分库分表 + 读写分离。
就是把一个库分红多个库,部署在多个数据库服务上,主库承载写请求,从库承载读请求。从库能够挂载多个,由于不少场景写的请求远少于读的请求,这样就把对单个库的压力降下来了。
若是写的请求上升就继续分库分表,若是读的请求上升就挂更多的从库,但数据库天生不是很适合高并发,并且数据库对机器配置的要求通常很高,致使单位服务成本高,因此,这样加机器抗压力成本过高,还得另外想招。
缓存的理论依据是局部性原理。
通常系统的写入请求远少于读请求,针对写少读多的场景,很适合引入缓存集群。
在写数据库的时候同时写一份数据到缓存集群里,而后用缓存集群来承载大部分的读请求,由于缓存集群很容易作到高性能,因此,这样的话,经过缓存集群,就能够用更少的机器资源承载更高的并发。
缓存的命中率通常能作到很高,并且速度很快,处理能力也强(单机很容易作到几万并发),是理想的解决方案。
CDN本质上就是缓存,被用户大量访问的静态资源缓存在CDN中是目前的通用作法。
但缓存是针对读,若是写的压力很大,怎么办?
同理,经过跟主库加机器,耗费的机器资源是很大的,这个就是数据库系统的特色所决定的。
相同的资源下,数据库系统过重太复杂,因此并发承载能力就在几千/s的量级,因此此时你须要引入别的一些技术。
好比说消息中间件技术,也就是MQ集群,它是很是好的作写请求异步化处理,实现削峰填谷的效果。
消息队列能作解耦,在只须要最终一致性的场景下,很适合用来配合作流控。
假如说,每秒是1万次写请求,其中好比5千次请求是必须请求过来立马写入数据库中的,可是另外5千次写请求是能够容许异步化等待个几十秒,甚至几分钟后才落入数据库内的。
那么此时彻底能够引入消息中间件集群,把容许异步化的每秒5千次请求写入MQ,而后基于MQ作一个削峰填谷。好比就以平稳的1000/s的速度消费出来而后落入数据库中便可,此时就会大幅度下降数据库的写入压力。
业界有不少著名的消息中间件,好比ZeroMQ,rabbitMQ,kafka等。
消息队列自己也跟缓存系统同样,能够用不多的资源支撑很高的并发请求,用它来支撑部分容许异步化的高并发写入是很合适的,比使用数据库直接支撑那部分高并发请求要减小不少的机器使用量。
再强大的系统,也怕流量短事件内集中爆发,就像银行怕挤兑同样,因此,高并发另外一个必不可少的模块就是流控。
流控的关键是流控算法,有4种常见的流控算法。
接入-逻辑-存储是经典的互联网后端分层,但随着业务规模的提升,逻辑层的复杂度也上升了,因此,针对逻辑层的架构设计也出现不少新的技术和思路,常见的作法包括系统拆分,微服务。
除此以外,也有不少业界的优秀实践,包括某信服务器经过协程(无侵入,已开源libco)改造,极大的提升了系统的并发度和稳定性,另外,缓存预热,预计算,批量读写(减小IO),池技术等也普遍应用在实践中,有效的提高了系统并发能力。
为了提高并发能力,逻辑后端对请求的处理,通常会用到生产者-消费者多线程模型,即I/O线程负责网络IO,协议编解码,网络字节流被解码后产生的协议对象,会被包装成task投入到task queue,而后worker线程会从该队列取出task执行,有些系统会用多进程而非多线程,经过共享存储,维护2个方向的shm queue,一个input q,一个output q,为了提升并发度,有时候会引入协程,协程是用户线程态的多执行流,它的切换成本更低,一般有更好的调度效率。
另外,构建漏斗型业务或者系统,从客户端请求到接入层,到逻辑层,到DB层,层层递减,过滤掉请求,Fail Fast(尽早发现尽早过滤),嘴大屁眼小,哈哈。
漏斗型系统不只仅是一个技术模型,它也能够是一个产品思惟,配合产品的用户分流,逻辑分离,能够构建全方位的立体模型。
莫让浮云遮望眼,除去繁华识真颜。咱们不能掌握了大方案,吹完了牛皮,而忽视了编程最本质的东西,掌握最基本最核心的编程能力,好比数据架构和算法,设计,惯用法,培养技术的审美,也是很重要的,既要致高远,又要尽精微。