当前位置: 首页 > 科技观察

淘宝的双11高并发架构是如何设计的?看完这篇文章,你就知道了

时间:2023-03-22 00:23:13 科技观察

一、背景介绍这篇文章,说说很多同学问我的一个问题。面试的时候被问到一个很迷惑的问题:你们的系统是怎么支持高并发的?大多数学生被问到这个问题,却不知道如何回答。他们不知道从哪里开始。其实本质就是他们没有体验过一些真正的高并发系统。因为我没有相关的项目经验,所以无法从自己的真实经历和经历中提炼出一套答案,然后系统地说明我这个复杂的系统是如何支持高并发的。因此,本文将从这个角度简单谈谈这个问题,用最简单的思路来回答,大致是怎么处理的。当然,这里先有一个前提:高并发系统不一样。比如每秒百万级并发的中间件系统,每天百亿级请求的网关系统,瞬时每秒数十万级请求的秒杀推广系统。他们在处理高并发的时候,因为系统的特点不同,应对的架构也不同。另外,比如电商平台中的订单系统、商品系统、库存系统在高并发场景下的架构设计是不同的,因为它们背后的业务场景是不同的。所以这篇文章主要是给大家提供一个回答这类问题的思路,不涉及任何复杂的架构设计,让你在面试的时候被问到这个问题的时候不会盯着面试官看。具体来说,如果你在面试的时候真的能回答这个问题,我建议你参考这篇文章的思路,然后对你负责的系统多思考,最好做一些相关的架构实践。2.先考虑最简单的系统架构。假设你的系统一开始部署在一台机器上,后面接了一个数据库,数据库部署在一台服务器上。我们甚至可以更加现实。比如你系统部署的机器是4核8G,数据库服务器是16核32G。此时,假设你的系统总共有100,000个用户,而且用户数量很少。日活用户因系统场景不同而不同。我们取一个比较客观的比例,10%,日活跃用户数为10000。按照28的法则,把他算作每天高峰期4小时,高峰期活跃用户比例达到80%,即4小时内有8000人活跃。然后每个人都向你的系统发起请求,算他一天20次吧。那么高峰期只有8000人发起的16万个请求,4小时内平均每秒10个请求(14400秒)。好的!根本比不上高并发吧?那么在系统层面,每秒有10次请求,每次请求数据库都会需要进行几次数据库操作,比如做crud之类的。那我们就拿一个请求对应3个数据库请求吧。在这种情况下,数据库层每秒只会发出30个请求,对吗?按照这个数据库服务器的配置,支持是绝对没问题的。上述系统用图表示如下:3.系统集群部署假设此时你的用户数开始快速增长,比如注册用户数增长50倍,达到500万。此时日活跃用户数为50万,高峰期每秒对系统的请求为500/s。那么每秒对数据库的请求数是1500/s,这时候会发生什么呢?从上面的机器配置来看,如果你的系统处理了一些比较复杂的业务逻辑,就是一个业务逻辑重的系统,会消耗更多的CPU。这时候,当4核8G的机器每秒请求达到500/s的时候,很可能你会发现你机器的CPU负载很高。然后在数据库层面,基于上面的配置,其实峰值请求压力基本1500/s还是可以接受的。这个主要是观察数据库所在机器的磁盘负载、网络负载、CPU负载、内存负载。根据我们线上的经验,配置的数据库在1500/s的请求压力下是没有问题的。所以这时候你需要做的一件事就是首先支持你系统的集群部署。可以在前面挂一个负载均衡层,将请求平均发送到系统层面,这样系统就可以使用多台机器集群来支撑更高的并发压力。例如,假设系统再部署一台机器,每台机器只会有250/s的请求。这样两台机器的CPU负载都会明显降低。这个最初的“高并发”不是应该先覆盖吗?如果连这个都不做,当单机负载越来越高的时候,极端情况下,机器上部署的系统可能没有足够的资源来响应请求,然后请求就会卡死,甚至系统会宕机。课堂提问。所以,简单总结一下,第一步就是加一个负载均衡层,把请求均匀的发到系统层。系统层采用集群部署多台机器来承受初期的并发压力。此时的架构图变成如下:4.数据库分库分表+读写分离假设此时用户数继续增长,达到1000万注册用户,则日活跃用户为1百万。那么这个时候,系统层面的请求量就会达到每秒1000/s。在系统层面,可以通过集群不断扩容。反正前面的负载均衡层会平均分配流量。但是此时数据库层面接受的请求数会达到3000/s,有点问题。这时候数据库层面的并发请求翻倍了,你肯定会发现线上的数据库负载越来越高。每到高峰期,磁盘IO、网络IO、内存消耗、CPU负载的压力都会很大。大家都很担心数据库服务器能不能承受得住。没错,一般来说,对于常见配置的在线数据库,建议把并发读写加起来。按照我们上面举例的配置,应该不会超过3000/s。因为数据库压力太大,第一个问题就是高峰期可能会降低系统性能,因为数据库负载高会影响性能。还有一个,如果压力太大,你的数据库搞砸了怎么办?所以这时候就得把系统分库分表+读写分离,也就是把一个库拆分成多个库,部署在多个数据库服务上,作为主库来承载写请求。然后每个主库挂载至少一个从库,从库承载读请求。此时假设数据库层面的读写并发为3000/s,其中写并发占1000/s,读并发占2000/s。那么数据库分表后,主库部署在两台数据库服务器上,支持写请求,每台服务器承载的写并发为500/s。每个主库挂载一台服务器部署一个从库,所以两个从库支持的读并发都是1000/s。简单总结一下,当并发量不断增长的时候,我们需要关注数据库层面:分库分表,读写分离。此时的架构图如下:5.引入了缓存集群,之后就好办了。如果你的注册用户越来越大,这个时候你可以继续加机器,比如在系统层面加机器。它可以承载更高的并发请求。然后,如果数据库层面的写并发越来越高,扩容,增加数据库服务器。扩容机可以支持分库分表。如果数据库层面的读并发越来越高,扩容,增加从库。但是这里有个很大的问题:数据库本身并不是用来承载高并发请求的,所以一般来说,单台数据库机器每秒承载的并发量在几千量级,而数据库使用的机器都是比较高配置的,比较贵的机器,性价比非常高。如果只是简单地不断增加机器,其实是错误的。所以在高并发架构中通常会有一个缓存环节。缓存系统的设计是为了承载高并发。所以单机承载的并发量是每秒几万甚至几十万,高并发的承载能力比数据库系统高出一到两个数量级。因此,可以根据系统的业务特点,针对写少读多的请求引入缓存集群。具体来说,就是在写数据库的时候,同时向缓存集群写入一份数据,然后缓存集群来承载大部分的读请求。这样通过缓存集群,可以用更少的机器资源来承载更高的并发。比如上图,读请求目前是2000/s/s,两个从库各抗1000/s的读请求,但是1800/s的读请求可以直接从缓存中读取。改变数据。那么这个时候一旦引入缓存集群,就可以抵抗1800/s的读请求,而数据库层面的读请求是200/s。同样的,这里放一张架构图,大家一起来体验一下:根据上面的架构,它有什么好处呢?未来你的系统可能每秒有几万个读请求,但是其中80%到90%可能是通过缓存集群读取的,而缓存集群中的机器可能可以支持几万个读requestspersecondonasinglemachine,所以它消耗的机器资源非常少,可能两三台机器就够了。如果用数据库来试试,可能要不停地从数据库加到10、20台机器上去抵抗每秒几万的并发读,成本极高。好吧,简单总结一下承载高并发需要考虑的第三点:不要盲目扩容数据库。数据库服务器价格昂贵,不是用来承载高并发的。对于写少读多的请求,引入缓存Clusters,使用缓存集群来抵御大量的读请求第六,引入消息中间件集群接下来我们来看数据库写的压力,其实和读是差不多的。如果你所有的写请求都落在数据库的主库层,当然没有问题,但是写压力越来越大怎么办?例如,每秒需要写入数万条数据。这个时候是不是也在不停的往主库里加机器?当然可以,但是同样的,你会消耗大量的机器资源,这是由数据库系统的特性决定的。同样的资源下,数据库系统过于繁重复杂,并发承载量在几千/s量级,这时候就需要引入一些其他的技术。比如消息中间件技术,也就是MQ集群,非常擅长写请求的异步处理,达到削峰填谷的效果。比如说你每秒有1000/s的写请求,比如500个请求必须请求立即写入数据库,但是另外500个写请求可以让异步等待几十秒,甚至几分钟才可以落入数据库。那么这个时候就可以完全引入一个消息中间件集群,每秒500个允许异步的请求写入MQ,然后基于MQ做削峰填谷。例如,它可以以100/s的稳定速率被消耗,然后落入数据库。这时候数据库的写入压力会大大降低。ps:MQ削峰填谷的概念在公众号之前的消息中间件一文中有详细阐述。如果忘记了,可以复习一下。这时候架构图就变成了如下:看上面的架构图,首先消息中间件系统本身也是为高并发而生的,所以通常单机支持几万甚至几十万并发要求。因此,就像缓存系统本身一样,它可以用很少的资源支持非常高的并发请求。用它来支持一些允许异步的高并发写是没有问题的,这比用数据库直接支持那些高并发请求要好。要求大量减少机器使用。而消息中间件削峰填谷后,比如以100/s的稳定速度写入数据库,那么数据库层面接收到的写入请求的压力就会变成500/s+100/s=600/是什么?大家看看,有没有发现数据库的压力变小了?至此,通过以下手段,我们已经能够让系统架构以尽可能小的机器资源来抵抗最大的请求压力,减轻数据库的负担。系统集群数据库级别的分库分表+读写分离针对读多写少的请求,引入缓存集群来应对高写压力,引入消息中间件集群。至此,一个高并发系统的简单描述就结束了。然而,故事远没有结束。7、现在能hold住高并发面试题吗?看完这篇文章,你觉得你能答对面试中的高并发题吗?不幸的是,答案是否定的。而且我认为你是绝对不可能仅仅靠几篇文章就完全回答这个问题的。这件事情是由很多原因导致的。首先,高并发这个话题本身就很复杂,远不是一些文章能说清楚的。其本质在于,真正支持复杂业务场景的高并发系统架构其实是非常复杂的。例如每秒百万级并发的中间件系统,每天百亿级请求的网关系统,瞬时每秒数十万级请求的闪电促销系统,大型高并发电商平台支持数亿用户的架构等。为了支持高并发请求,在设计系统架构时,会结合具体的业务场景和特点设计各种复杂的架构,这需要大量的底层技术支持,以及成熟的架构和机制设计能力。最终,各种复杂系统所呈现出的架构复杂性,将远远超出大多数没有接触过的同学的想象。但如此复杂的系统架构,很难通过一些文章来解释其中的各种细节和落地生产的过程。其次,高并发这个话题本身包含的远不止本文提到的话题:分库分表、缓存、消息。一个完整复杂的高并发系统架构必然包括各种复杂的自研基础设施系统和各种精巧的架构设计(如热点缓存架构设计、多优先级高吞吐MQ架构设计、系统全链路并发性能优化设计、等),以及各种复杂系统组成的高并发架构的整体技术解决方案,以及NoSQL(Elasticsearch等)/负载均衡/Web服务器等相关技术。所以大家一定要记住对技术要有敬畏之心,这些东西是很难通过一些文章表达清楚的。最后,在真正实现生产的时候,你的系统在高并发场景下会出现很多技术问题。比如消息中间件的吞吐量需要优化,磁盘写压力太大,性能太差,内存消耗太大,容易爆,分库分表中间件不知道为什么数据会丢失,等等。诸如此类的问题太多了,不可能通过文章都说清楚。8、这篇文章能给你带来什么启发?其实这篇文章的定位是对高并发这个面试题目做一个识字测试,因为我发现大部分来问我这个问题的同学可能连最基本的高并发架构演进都不懂在这篇文章中解释。当然,也是因为毕竟没有真正做过高并发系统,没有相关经验。这个问题真的很难理解。所以这篇文章就是让很多没接触过的同学有个初步的认知,这个高并发是怎么回事,系统的压力在哪里,系统架构需要引入什么来更好的支持它。高并发压力。而你也可以沿着本文的思路继续思考,结合一些你熟悉和知道的技术。例如,如果你熟悉Elasticsearch技术,那么你可以想,嗯?高并发架构下,是否可以通过分布式架构ES技术支持高并发搜索?如前所述,要以权引玉。大家平时一定要多思考,自己多画图,盘点一下手头系统的请求压力。计算分配给各个中间件层级的请求压力,如何用最少的机器资源最好的支持更高并发的请求。这是一个很好的高并发架构设计思路。如果达到这个效果,这篇文章就成功了。其他的,我还是建议同学们多想想高并发这个话题,结合自己负责的系统。比如现在的业务场景,你的系统有多大的请求压力?如果请求压力增加10倍,你的架构如何支持?如果请求压力增加100倍,你的架构怎么支持?如果请求压力增加1000倍,你的架构怎么支持?通常,你必须为自己设置一些技术挑战,并督促自己思考自己的系统。写作结构上最好多练习、多实践、多练习,自己实际操作,感悟会更好。然后在面试的过程中,至少我做了一定的深度思考,结合自己负责的系统做了一些实践,这样才能和面试官有一个更清晰系统的交代。虽然大部分同学可能没有机会去体验真正的大型超高并发系统架构的设计,但是如果这篇文章能够让大家对自己的项目多一些思考的话。在面试的过程中,如果有一些系统的想法和阐述,那么本文的目的就达到了。