记得很久以前,我去面试字节跳动。三个面试官问了一个场景设计的问题:如何设计高并发系统。当时我的回答比较粗略。回想起来,我整理了15条设计高并发系统的技巧。相信对大家阅读会有帮助。如何理解高并发系统所谓高并发系统的设计,就是设计一个能够处理高并发用户请求,承受大流量冲击,同时保证整体可用性的系统。如果我们要设计一个高并发的系统,我们需要处理一些常见的系统瓶颈,比如内存不足、磁盘空间不足、连接数不足、网络带宽不足等,以应对突如其来的流量高峰。1.分而治之,横向扩展如果只部署一个应用和一台服务器,能够抵抗的流量请求是非常有限的。此外,单个应用程序具有单点风险。如果挂起,服务将不可用。所以,设计一个高并发的系统,我们可以分而治之,横向扩展。即采用分布式部署的方式,部署多台服务器,划分流量,让每台服务器承担一部分的并发和流量,提高整个系统的并发能力。2、微服务拆分(系统拆分)应该提高系统吞吐量,提高系统处理并发请求的能力。除了采用分布式部署方式,还可以做微服务拆分,达到分摊请求流量的目的,提高并发能力。所谓微服务拆分,其实就是将单个应用按照功能的单一性拆分成多个服务模块。例如,一个电子商务系统分为用户系统、订单系统、商品系统等。3、分库分??表当业务量激增时,MySQL单机的磁盘容量会爆棚。另外,我们知道数据库连接数是有限制的。在高并发场景下,大量的访问数据库的请求是单台MySQL服务器无法处理的!在高并发场景下,会出现连接过多的错误。所以,一个高并发的系统需要拆分成多个数据库来抵抗高并发的殴打。而如果你的单表数据量很大,那么存储和查询的性能就会遇到瓶颈。如果做了很多优化还是不能提高效率,就需要考虑分表了。一般上千万级的数据量需要分表,每张表的数据量较小,以提高SQL查询性能。面试官让你设计高并发系统的时候,一般都会说到分库分表。4、池化技术在高并发场景下,由于连接数有限,数据库连接数可能成为瓶颈。当我们的请求调用数据库时,我们会先获取到数据库的连接,然后依靠这个连接查询数据,完成工作,最后关闭连接释放资源。如果不使用数据库连接池,每执行一次SQL都要创建和销毁一个连接,这会导致每次查询请求变慢,相应地,系统处理用户请求的能力也会降低。因此需要使用池化技术,即数据库连接池、HTTP连接池、Redis连接池等。使用数据库连接池可以避免每次查询都创建新的连接,减少不必要的资源开销,提高系统的通过重用连接池来处理高并发请求的能力。同样的,我们使用线程池,让任务可以并行处理,更高效的完成任务。5、主从分离一般来说,单机的MySQL服务器可以支持500TPS左右,10000QPS,也就是单机服务器支持的请求访问是有限的。于是你做了分布式部署,部署了多台机器,部署了主库,部署了从库。但是,如果双十一有活动,流量肯定会暴增。如果所有的查询请求都去主库,主库肯定处理不了,因为查询请求量非常非常大。所以一般需要主从分离,然后实时性要求低的读请求到从库,写请求或者实时性要求高的请求到主库。这样既很好的保护了主库,也提高了系统的吞吐量。当然,如果回答的是主从分离,面试官可能会扩展问你主从复制的原理,问你主从延时等等,这个你需要全面复习。6、使用缓存无论是操作系统、浏览器,还是一些复杂的中间件,都可以看到缓存的影子。我们使用缓存主要是为了提高系统界面的性能。在这样的高并发场景下,你的系统可以支持更多的用户同时访问。常用的缓存包括:Redis缓存、JVM本地缓存、memcached等,以Redis为例,单机上万并发轻松应对,读取业务时可以使用缓存来抵御高并发的场景。缓存虽然很好用,但是在使用缓存的过程中要注意一些问题:缓存与数据库的一致性。CacheAvalancheCachePenetrationCacheBreakdown7.CDN,加速静态资源访问产品图片、图标等静态资源,可以修改页面做静态处理,减少访问服务器的请求。如果用户分布在全国各地,有的在上海,有的在深圳,地区相隔较远,网速也不一样。为了让用户尽快访问到页面,可以使用CDN。CDN允许用户就近获取他们需要的内容。什么是CDN?ContentDeliveryNetwork/ContentDistributionNetwork,翻译过来就是内容分发网络,是指将静态资源分发到位于多个地理位置机房的服务器上,使数据就近访问,加快了静态资源的访问速度,从而使系统更有效率。很容易处理正常的其他动态请求。8.消息队列,切前面。我们在进行一些双11、双12等运营活动时,需要避免流量暴涨、应用系统崩溃的风险。所以一般会引入消息队列来应对高并发场景。假设你的应用系统每秒最多可以处理2k个请求,但是每秒有5k个请求,你可以引入消息队列,应用系统每秒可以从消息队列中处理2k个请求。有小伙伴担心消息可能会积压:首先,搞点运营活动,这样就不会一直有那么多请求来到你的系统(除非有人恶意攻击),过了高峰期,请求积压会减慢处理速度;其次,如果消息队列长度超过最大数量,可以直接丢弃用户请求或者跳转到错误页面;9.ElasticSearchElasticsearch,大家用的比较多,用在一般的搜索功能上。它是一个分布式、高扩展性、高实时性的搜索和数据分析引擎,简称ES。都在讲高并发,为什么要讲ES呢?因为ES可以很方便的扩展,自然支持高并发。当数据量很大,不需要加机器扩容、分库等,可以考虑使用ES来支持简单的查询搜索和统计操作。10.退化保险丝降额是一种保护系统的手段。目前的互联网系统普遍采用分布式部署方式。偶尔在分布式系统中,某个基础服务不可用,最终会导致整个系统不可用。这种现象称为服务雪崩效应。比如分布式调用链路A->B->C....,如下图所示:如果服务C出现问题,比如由于SQL慢导致调用缓慢,会导致B要延误,A也要延误。延迟。被阻塞的A请求会消耗线程、IO、CPU等系统资源。当向A请求的服务越来越多时,占用的计算机资源也越来越多,最终会导致系统出现瓶颈,导致其他请求也无法使用,最终导致业务系统崩溃。应对服务雪崩,常见的做法是熔断和降级。最简单的就是添加开关控制。当下游系统出现问题时,打开开关降级,不再调用下游系统。您也可以选择支持的开源组件Hystrix。如果要保证设计的系统能够处理高并发场景,那么就必须考虑断路器降级逻辑。11、限流也是我们应对高并发的一个解决方案。当然,我们希望在高并发、大流量来临时,系统能够正常处理所有的请求。但有时也没办法,系统的CPU、网络带宽、内存、线程等资源都是有限的。因此,我们必须考虑限流。如果你的系统每秒处理一千个请求,如果一秒钟来十万个请求怎么办?从另一个角度来说,当并发量高的时候,流量高峰就来了,超过了系统的承载能力。我应该怎么办?这时候,我们可以采用限流方案。只是为了保护系统,直接丢弃多余的请求。什么是限流:在计算机网络中,限流是控制网络接口发送或接收请求的速率,可以防止DoS攻击和限制网络爬虫。限流,也称为流量控制。意思是当系统面临高并发或大流量请求时,限制新的请求进入系统,以保证系统的稳定性。可以使用Guava的RateLimiter单机版进行限流,也可以使用Redis分布式限流,也可以使用阿里的开源组件Sentinel进行限流。面试的时候有没有说到限流?面试官很可能会问你关于限流算法的问题。所以大家在准备面试的时候,需要复习一下这些经典的限流算法。12.异步回想一下什么是同步什么是异步?以方法调用为例,意味着调用者应该阻塞等待被调用方法中的逻辑执行完成。这样,当被调用的方法响应时间过长时,会导致调用者长时间阻塞,在高并发下,系统整体性能会下降甚至出现雪崩。异步调用正好相反。调用者可以返回执行其他逻辑,而无需等待方法逻辑执行完成。被调用的方法执行后,会通过回调、事件通知等方式将结果反馈给调用者。因此,要设计一个高并发的系统,需要在合适的场景下使用异步。如何使用异步?后端可以使用消息队列来实现。比如当有大量秒杀请求到来时,先放到消息队列中,快速响应用户,并告诉用户请求正在处理中,从而释放资源去处理更多的请求。秒杀请求处理完成后,通知用户秒杀购买成功或失败。13.接口的总体优化要设计一个高并发的系统,设计的接口的性能需要足够好,这样系统才能同时处理更多的请求。说到这个,可以和面试官聊聊界面优化的一些解决方案。14、压力测试决定系统瓶颈设计高并发系统最重要的部分就是压力测试。也就是在系统上线之前,需要对系统进行压力测试,确定你的系统支持的最大并发数,确定系统的瓶颈,让自己知道最好的防范措施。压测结束后,需要对整个调用链路进行分析。性能问题可能是网络层(如带宽)、Nginx层、服务层或数据路径缓存等中间件引起的。Loadrunner是一个很好的压力测试工具,jmeter是一个接口性能测试工具,两者都可以用来做压力测试。15.突发流量高峰的应对:扩容+切流量如果突发流量高峰,除了降级和限流保证系统不跨,我们可以通过这两种方案来保证系统能够服务于用户请求尽可能地:扩容:比如增加从库中改进配置来提高系统/组件的流量承载能力。比如添加MySQL、Redis从库来处理查询请求。流量切换:服务于多机房部署,如果来了高并发流量,将流量从一个机房切换到另一个机房。
