⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 捡田螺的小男孩 「捡田螺的小男孩」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言都将得到认真回复。甚至不知道如何读源码也可以请教噢。
  4. 新的源码解析文章实时收到通知。每周更新一篇左右。
  5. 认真的源码交流微信群。

前言

分享一道字节面试场景题:假设你负责的业务系统,流量突增,比如QPS暴增100倍,你要怎么处理?

有些伙伴一听完题目,就不假思索回答,那就加机器呀、扩容什么的。当然,这个不能算错,但是你只得其中一小点的分数,肯定不及格的。

作为一名优秀的后端开发程序员,我们应当从多个维度去思考这个问题,尽可能回答完整、正确。

  • 紧急响应阶段:快速止血
  • 冷静分析:为什么?暴增的流量合理嘛
  • 健壮设计,增强系统身体素质
  • 压力测试,测试系统抗压能力

1.紧急响应阶段:快速止血

如果我们负责的系统,突发流量洪峰来了,超过系统的承载能力,为了保护我们的系统,需要快速止血!

1.1 限流

我们可以采取限流方案。其实就是保护系统,多余的请求,直接丢弃。

什么是限流:在计算机网络中,限流就是控制网络接口发送或接收请求的速率,它可防止DoS攻击和限制Web爬虫。限流,也称流量控制。是指系统在面临高并发,或者大流量请求的情况下,限制新的请求对系统的访问,从而保证系统的稳定性。

  • 可以使用Guava的RateLimiter单机版限流,也可以使用Redis分布式限流,还可以使用阿里开源组件sentinel限流。
  • 还可以通过令牌桶、漏桶算法限制请求速率,丢弃超出阈值的请求,避免系统过载。
  • 令牌桶算法:系统以固定速率向桶中添加令牌,请求需获取令牌才能被处理。若桶空则触发限流。
  • 漏桶算法:请求像水一样流入漏桶,桶以恒定速率出水(处理请求)。桶满则溢出触发限流。

1.2 降级熔断

熔断降级是保护系统的一种手段。当前互联网系统一般都是分布式部署的。而分布式系统中偶尔会出现某个基础服务不可用,最终导致整个系统不可用的情况, 这种现象被称为服务雪崩效应。

比如分布式调用链路A->B->C....,下图所示:

如果服务C出现问题,比如是因为慢SQL导致调用缓慢,那将导致B也会延迟,从而A也会延迟。堵住的A请求会消耗占用系统的线程、IO、CPU等资源。当请求A的服务越来越多,占用计算机的资源也越来越多,最终会导致系统瓶颈出现,造成其他的请求同样不可用,最后导致业务系统崩溃。

因此,面对突发激增100倍的流量,我们可以采取熔断降级。

  • 熔断:对非核心服务(如推荐、评论)启用熔断机制(如Hystrix),快速失败以释放资源,优先保障核心链路(如支付、下单)。
  • 服务降级:关闭非关键功能(如数据分析、日志记录),返回兜底数据(如缓存中的默认商品信息),降低后端压力。

1.3 弹性扩容

如果是突发的流量高峰,除了降级、限流保证系统不跨,我们还可以采用这两种方案,保证系统尽可能服务用户请求:

  • 扩容:比如增加从库、提升配置的方式,提升系统/组件的流量承载能力。比如增加MySQL、Redis从库来处理查询请求。
  • 切流量:服务多机房部署,如果高并发流量来了,把流量从一个机房切换到另一个机房。

1.4 消息队列,削锋

我们搞一些双十一、双十二等运营活动时,需要避免流量暴涨,打垮应用系统的风险。因此一般会引入消息队列,来应对高并发的场景。

假设你的应用系统每秒最多可以处理2k个请求,每秒却有5k的请求过来,可以引入消息队列,应用系统每秒从消息队列拉2k请求处理得了。

2.冷静分析:为什么?暴增的流量是否合理?

面对突发流量,我们得思考清楚,这个QPS来源是否合理呢?

到底是因为双十一、双十二这些促销活动,还是因为一些异常的流量呢(比如代码产生的bug呀,或者是恶意攻击等等)

  • 我们得分析日志、监控等,如果是bug,得评估影响范围,快速修复。
  • 如果是恶意攻击,我们得限制IP、加入黑名单、风控拦截等等。
  • 如果是正常的促销活动,我们得分析流量暴增的范围、时间,比如单个接口还是所有接口呢?分析系统瓶颈是否符合压测的指标( CPU/内存/磁盘等等),确认是否要采取紧急处理。

3. 设计阶段:健壮设计,增强系统身体素质

回到设计阶段,我们如何避免这些突发的流量倍增呢?

3.1 分而治之,横向扩展

如果你只部署一个应用,只部署一台服务器,那抗住的流量请求是非常有限的。并且,单体的应用,有单点的风险,如果它挂了,那服务就不可用了。

因此,设计一个高并发系统,我们可以分而治之,横向扩展。也就是说,采用分布式部署的方式,部署多台服务器,把流量分流开,让每个服务器都承担一部分的并发和流量,提升整体系统的并发能力。

3.2 微服务拆分(系统拆分)

要提高系统的吞吐,提高系统的处理并发请求的能力。除了采用分布式部署的方式外,还可以做微服务拆分,这样就可以达到分摊请求流量的目的,提高了并发能力。

所谓的微服务拆分,其实就是把一个单体的应用,按功能单一性,拆分为多个服务模块。比如一个电商系统,拆分为用户系统、订单系统、商品系统等等。

3.3 分库分表

当业务量暴增的话,MySQL单机磁盘容量会撑爆。并且,我们知道数据库连接数是有限的。在高并发的场景下,大量请求访问数据库,MySQL单机是扛不住的!高并发(流量倍增)场景下,会出现too many connections报错。

因此,应对流量激增的场景,需要考虑拆分为多个数据库,来抗住高并发的毒打。而假如你的单表数据量非常大,存储和查询的性能就会遇到瓶颈了,如果你做了很多优化之后还是无法提升效率的时候,就需要考虑做分表了。一般千万级别数据量,就需要分表,每个表的数据量少一点,提升SQL查询性能。

3.4 池化技术

在高并发的场景下,数据库连接数可能成为瓶颈,因为连接数是有限的。

我们的请求调用数据库时,都会先获取数据库的连接,然后依靠这个连接来查询数据,搞完收工,最后关闭连接,释放资源。如果我们不用数据库连接池的话,每次执行SQL,都要创建连接和销毁连接,这就会导致每个查询请求都变得更慢了,相应的,系统处理用户请求的能力就降低了。

因此,需要使用池化技术,即数据库连接池、HTTP 连接池、Redis 连接池等等。使用数据库连接池,可以避免每次查询都新建连接,减少不必要的资源开销,通过复用连接池,提高系统处理高并发请求的能力。

3.5 使用缓存

无论是操作系统,浏览器,还是一些复杂的中间件,你都可以看到缓存的影子。我们使用缓存,主要是提升系统接口的性能,这样流量激增的高并发场景,你的系统就可以支持更多的用户同时访问。

常用的缓存包括:Redis缓存,JVM本地缓存,memcached等等。就拿Redis来说,它单机就能轻轻松松应对几万的并发,你读场景的业务,可以用缓存来抗高并发。

3.6 异步

回忆一下什么是同步,什么是异步呢?以方法调用为例,它代表调用方要阻塞等待被调用方法中的逻辑执行完成。这种方式下,当被调用方法响应时间较长时,会造成调用方长久的阻塞,在高并发下会造成整体系统性能下降甚至发生雪崩。异步调用恰恰相反,调用方不需要等待方法逻辑执行完成就可以返回执行其他的逻辑,在被调用方法执行完毕后再通过回调、事件通知等方式将结果反馈给调用方。

因此,设计一个应对激增流量的高并发系统,需要在恰当的场景使用异步。如何使用异步呢?后端可以借用消息队列实现。比如在海量秒杀请求过来时,先放到消息队列中,快速响应用户,告诉用户请求正在处理中,这样就可以释放资源来处理更多的请求。秒杀请求处理完后,通知用户秒杀抢购成功或者失败。

4.压力测试,测试系统抗压能力

压力测试确定系统瓶颈。

设计高并发系统,离不开最重要的一环,就是压力测试。就是在系统上线前,需要对系统进行压力测试,测清楚你的系统支撑的最大并发是多少,确定系统的瓶颈点,让自己心里有底,最好预防措施。

压测完要分析整个调用链路,性能可能出现问题是网络层(如带宽)、Nginx层、服务层、还是数据路缓存等中间件等等。

loadrunner是一款不错的压力测试工具,jmeter则是接口性能测试工具,都可以来做下压测。

5. 最后

假设你负责的业务系统,流量突增100倍。

  • 我们可以通过限流、熔断降级、扩容、流量削峰等手段,快速给系统止血。(快速止血)
  • 我们止血后,我们快速定位问题,分析是bug还是恶意攻击还是正常促销引起的。(分析伤口原因)
  • 我们通过横向扩展、服务拆分、分库分表、池化技术、缓存、异步、压测等手段,增强系统身体素质。

最后补充一句,我们在设计阶段,假设任何环节都会挂,做好兜底方案。

比如你用分布式锁,高并发情况,如果Redis挂了,如何兜底呢?是否有乐观锁兜底,是否有降级?是否有数据核对方案?

文章目录
  1. 1. 前言
  2. 2. 1.紧急响应阶段:快速止血
    1. 2.1. 1.1 限流
    2. 2.2. 1.2 降级熔断
    3. 2.3. 1.3 弹性扩容
    4. 2.4. 1.4 消息队列,削锋
  3. 3. 2.冷静分析:为什么?暴增的流量是否合理?
  4. 4. 3. 设计阶段:健壮设计,增强系统身体素质
    1. 4.1. 3.1 分而治之,横向扩展
    2. 4.2. 3.2 微服务拆分(系统拆分)
    3. 4.3. 3.3 分库分表
    4. 4.4. 3.4 池化技术
    5. 4.5. 3.5 使用缓存
    6. 4.6. 3.6 异步
  5. 5. 4.压力测试,测试系统抗压能力
  6. 6. 5. 最后