和高并发系统根据PHP实战经验不同。比如每秒百万级并发的中间件系统,每天百亿级请求的网关系统,瞬时每秒数十万级请求的秒杀推广系统。他们在处理高并发的时候,因为系统的特点不同,应对的架构也不同。另外,比如电商平台中的订单系统、商品系统、库存系统在高并发场景下的架构设计是不同的,因为它们背后的业务场景是不同的。最简单的系统架构假设你的系统一开始是部署在一台机器上,后面接一个数据库,数据库部署在一台服务器上。我们甚至可以更加现实。比如你系统部署的机器是4核8G,数据库服务器是16核32G。此时,假设你的系统总共有100,000个用户,而且用户数量很少。日活用户因系统场景不同而不同。我们取一个更客观的比例,10%,日活跃用户数为10000。按照28的规律,每天高峰期4小时算,高峰期活跃用户比例达到80%,即4小时内有8000人活跃。然后每个人都向你的系统发起请求,算他一天20次吧。那么高峰期只有8000人发起的16万个请求,4小时内平均每秒10个请求(14400秒)。出色地!完全不符合高并发吧?然后系统层面每秒10个请求,每次请求数据库都会有几次数据库操作,比如做crud之类的。那我们就拿一个请求对应3个数据库请求吧。在这种情况下,数据库层每秒只有30个请求,对吗?按照这个数据库服务器的配置,支持是绝对没问题的。上述系统,用图表示如下:数据库分库分表+读写分离假设此时用户数继续增长,达到1000万注册用户,然后日活跃用户是100万。那么这个时候系统级别的请求量会达到每秒1000/s。在系统层面,可以通过集群不断扩容。反正前面的负载均衡层会平均分配流量。但是此时数据库层面接受的请求数会达到3000/s,有点问题。这时候数据库层面的并发请求翻倍了,你肯定会发现线上的数据库负载越来越高。每到高峰期,磁盘IO、网络IO、内存消耗、CPU负载的压力都会很大,大家都担心数据库服务器能不能承受得住。没错,一般来说,对于普通配置的在线数据库,建议把并发读写加起来。按照我们上面举例的配置,应该不会超过3000/s。因为数据库压力太大,第一个问题就是高峰期可能会降低系统性能,因为数据库负载高会影响性能。还有一个,你的数据库压力太大挂了怎么办?所以这时候你就得把系统分库分表+读写分离,也就是把一个数据库拆分成多个库,部署在多个数据库中。在数据库服务器上,这是托管写请求的主数据库。然后每个主库挂载至少一个从库,从库承载读请求。此时假设数据库层面的读写并发为3000/s,其中写并发占1000/s,读并发占2000/s。那么数据库分表后,主库部署在两台数据库服务器上,支持写请求,每台服务器承载的写并发为500/s。每个主库挂载一台服务器部署一个从库,所以两个从库支持的读并发都是1000/s。简单总结一下,当并发量不断增长的时候,我们需要关注数据库层面:数据库和表分离,读写分离。此时的架构图如下:引入缓存集群就好办了。如果你注册的用户越来越多,这个时候可以继续加机器。例如,可以在系统级别添加机器。承载更高的并发请求。然后,如果数据库层面的写并发越来越高,扩容,增加数据库服务器。扩容机可以支持分库分表。如果数据库层面的读并发越来越高,扩容,增加从库。但是这里有个很大的问题:数据库本身并不是用来承载高并发请求的,所以一般来说,单台数据库机器每秒承载的并发量在几千量级,而数据库使用的机器都是比较高配置的,比较贵的机器,性价比非常高。如果只是简单地不断增加机器,其实是错误的。所以在高并发架构中通常会有一个缓存环节。缓存系统的设计是为了承载高并发。所以单机承载的并发量是每秒几万甚至几十万,高并发的承载能力比数据库系统高出一到两个数量级。因此,可以根据系统的业务特点,针对写少读多的请求引入缓存集群。具体来说,就是在写数据库的时候,同时向缓存集群写入一份数据,然后缓存集群来承载大部分的读请求。这样通过缓存集群,可以用更少的机器资源来承载更高的并发。比如上图中,读请求目前是2000/s/s,两个从库各抗1000/s的读请求,但是1800/s的读请求可以直接从缓存中读取。改变数据。那么这个时候一旦引入缓存集群,就可以抵抗1800/s的读请求,而数据库层面的读请求是200/s。同样,这里给大家放一张架构图,大家一起感受下:按照上面的架构,它有什么好处呢?可能以后你的系统每秒读请求数万次,但是可能80%~90%是通过缓存集群读取的,缓存集群中的机器可能支持每秒数万次的读请求秒每秒,所以对机器资源的消耗很小,可能两三台机器就够了。如果换个数据库试试看,可能要不停的加从库到10、20台机器才能抵抗每秒几万的并发读,成本极高。好吧,简单总结一下承载高并发需要考虑的第三点:不要盲目扩容数据库。数据库服务器价格昂贵,不是用来承载高并发的。针对写少读多的请求,引入缓存集群来抵抗大量的读请求。介绍消息中间件集群再看数据库写的压力,其实和读的差不多。如果说你所有的写请求都落在数据库的主库层,当然没有问题,但是写压力越来越大怎么办?比如每秒写入数万条数据。这个时候,是不是也马不停蹄?您可以将机器添加到主数据库吗?当然可以,但是同样的,你会消耗大量的机器资源,这是由数据库系统的特性决定的。同样的资源下,数据库系统过于繁重复杂,并发承载量在几千/s量级,这时候就需要引入一些其他的技术。比如消息中间件技术,也就是MQ集群,可以很好的对写请求做异步处理,达到削峰填谷的效果。比如你当前每秒写1000/s的写请求,比如500个请求必须请求立即写入数据库,但是另外500个写请求可以让异步等待几十秒,甚至几秒在进入数据库之前的几分钟。那么这个时候就可以完全引入一个消息中间件集群,每秒500个允许异步的请求写入MQ,然后基于MQ做削峰填谷。例如,它可以以100/s的稳定速率被消耗,然后落入数据库。这时候数据库的写入压力会大大降低。这时候架构图就变成了如下:看上面的架构图,首先消息中间件系统本身也是为高并发而生的,所以通常单机支持几万甚至几十万并发要求。所以,它本身就和缓存系统一样,可以用很少的资源支持非常高的并发请求。用它来支持一些允许异步的高并发写是没有问题的,比直接用数据库来支持那些高并发请求要好。要求大量减少机器使用。而且经过消息中间件削峰填谷之后,比如你写数据库的速度稳定在100/s,那么数据库层面收到的写请求的压力就会变成500/s+100/s=600/s什么?看看,有没有发现数据库的压力变小了?至此,通过以下手段,我们已经能够让系统架构以尽可能小的机器资源来抵抗最大的请求压力,减轻数据库的负担:系统集群。分库分表+数据库级别的读写分离。针对读多写少的请求,引入缓存集群。针对编写压力大,引入了消息中间件集群。至此,一个简单的高并发系统的描述就结束了。然而,故事远没有结束。首先,高并发这个话题本身就很复杂,远不是一些文章能说清楚的。其本质在于,真正支持复杂业务场景的高并发系统架构其实是非常复杂的。例如每秒百万级并发的中间件系统,每天百亿级请求的网关系统,瞬时每秒数十万级请求的闪电促销系统,大型高并发电商平台支持数亿用户的架构等。为了支持高并发请求,在设计系统架构时,会结合具体的业务场景和特点设计各种复杂的架构,这需要大量的底层技术支持,以及成熟的架构和机制设计能力。最终,各种复杂系统所呈现出的架构复杂性,将远远超出大多数没有接触过的同学的想象。但如此复杂的系统架构,很难通过一些文章来解释其中的各种细节和落地生产的过程。其次,高并发这个话题本身包含的远不止本文提到的话题:分库分表、缓存、消息。一个完整复杂的高并发系统架构必然包括:各种复杂的自研基础设施系统。各种精巧的架构设计(如热点缓存架构设计、多优先级高吞吐MQ架构设计、系统全链路并发性能优化设计等)。还有各种复杂系统组成的高并发架构整体技术方案。还有NoSQL(Elasticsearch等)/负载均衡/Web服务器等相关技术。所以大家一定要记住对技术要有敬畏之心,这些东西是很难通过一些文章表达清楚的。最后,在真正实现生产的时候,你的系统在高并发场景下会出现很多技术问题。比如消息中间件的吞吐量需要优化,磁盘写压力太大,性能太差,内存消耗太大,容易爆,分库分表中间件不知道为什么数据会丢失,等等。
