技术面:如何让你的系统抗住高并发的流量?

前言

如何能让系统抗住高并发流量,要考虑的因素有很多,但是真的让你讲一下都有哪些,很多人肯定就会说,用Redis缓存啦,用MQ做解耦啦,总之就是想起来这一块儿就说一嘴,想起来那一块儿也说一嘴,总之就是说的不能成体系一些。

一般面试官问这种问题的时候,是想看你怎么回答,有没有从架构的思想去思考这个问题,就算有一些具体技术你记得可能不是很熟练了,面试官也会相信你是能够解决问题的。

这一次就整体来说一下如何让你的系统抗住高并发流量。

第一步"拆"

在面对高并发的时候,第一步永远是拆核心,思想就是分而治之。

那具体怎么样拆呢?

服务的拆分与治理

服务拆分

我们可以把庞大的单体架构,根据业务拆分成多个不同的服务,这样哪个服务遇到瓶颈了,可以单独拎出来进行扩容和优化,也不会因为某一个阶段出问题导致整个系统都瘫了。

例如:一个电商系统按照业务领域拆分成用户、订单、支付、库存这些独立的服务。

这样拆分主要是使用分布式架构来降低单点故障的风险,提高系统的可伸缩性和性能。

服务集群部署

虽然说,将单体系统拆分成多个系统,来分摊了单体架构下容易出现的故障风险,但实际上这样的操作只是将单点故障风险分摊到了各个子系统上,这样还是存在单点故障风险的。因此需要进行集群部署:将一个服务通过集群进行部署,来提升系统整体的吞吐量及响应速度,并使用负载均衡技术将请求均衡分配给多个服务器,以提高系统的性能和可用性。

这样集群部署后,让每个服务器都承担一部分的并发和流量,提升整体系统的并发能力。

服务治理

拆服务和集群部署后,原先的单体系统变成了多服务多节点的分布式架构了,那么如果服务A想调用服务B,怎么找到服务B呢?当有几十个服务,上百个节点,并且每个节点的IP变来变去的,该怎么治理这些服务呢?这就需要一个通讯录,用来专门记录,每个服务的地址信息,也就是注册中心。

下面是一些常见的注册中心的对比

注册中心 CAP 模型 健康检查方式 多数据中心 Spring Cloud 集成 典型特点
Eureka AP(可用性优先) 客户端心跳(30s) 不支持 原生支持 轻量、与 Spring Cloud 无缝集成,适合入门和中小型项目
Consul CP(一致性优先) TCP/HTTP/gRPC 主动探测 原生支持 支持 功能最全,支持 KV 存储、ACL、DNS 服务等,适合多语言、多数据中心场景
Zookeeper CP 临时节点存活监听 需额外配置 支持 成熟稳定,强一致性,适合与 Dubbo 等框架配合使用
Nacos AP/CP 可切换 TCP/HTTP/MySQL/自定义 支持 原生支持 阿里开源,集成注册中心+配置中心 + 动态 DNS,适合云原生和 Spring Cloud 项目

那么它们是怎么工作的呢?

这里可以以Nacos为例:服务启动时,后端服务自动把自己的 ip、端口注册到 Nacos。调用方通过 Nacos 获取健康实例列表,再配合 Ribbon 或者 Loadbalancer 做负载均衡。提到 Nacos 时,可以说一下的动态配置管理。高并发下,需要动态调整线程参数或者日志级别,不用重启服务。Nacos 配置一改,全量下发。

Nacos 的"动态配置"指的是:在应用运行期,无需重启服务,即可实时推送并生效配置变更的能力。它把"配置"从代码/包内解耦出来,集中存储在 Nacos Server,并通过 长轮询(Long-Polling)+ 版本号对比 机制,让客户端在毫秒级感知到变化,进而触发本地回调或 Bean 重新绑定,实现"热更新"。

数据的拆分(读写分离、分片)

读写分离

服务进行了拆分,如果数据库还是用一个,那么瓶颈肯定很容易出现在数据库,所以我们可以根据业务场景(读多写少/读少写多)将数据库进行读写分离,这样当读流量大了的时候,也不会影响写的效率。

读场景(商品详情、评论)走只读副本,写场景(下单、支付)走主库。 但是要做好监控,当主从延迟过高时,要及时处理。

垂直拆分

服务进行了拆分,如果数据库还是用一个,那么瓶颈肯定很容易出现在数据库,所以垂直分库是必须的,要做到专库专用,这样可以解决服务太多,数据库连接数太多的问题,减少数据库的压力。

水平拆分

但是如果有的表一年产生上亿条数据,并且保持持续增加。数据量真的太大了,就不要再总纠结什么索引优化、事务优化这种小打小闹的了,这个时候就得上水平分表了,落地工具现在首选是 shardingsphere,再加上一些自己的实现细节。比如我们利用 shardingjdbc 配置好分片键,再通过一致性哈希算法把一张大表拆成一千零二十四张小表,均匀分布在不同的物理磁盘上,这样就把集中的I/O 压力分散了。

当涉及到分库分表,就有一个绕不过去的问题,那就是分布式事务。在单体服务架构下,一个@Transaction注解就能解决的问题,但是在分布式场景下如何解决,这里如果能说明白也是一个加分项。

因为使用了shardingsphere,可以使用数据库的 XA 协议或者引入 Seata,用 AT 模式或者 TCC 模式来解决跨库的事务问题。

第二步"缓"

缓也可以说是缓冲,服务和数据库的拆分只是解决了扩展性的问题,但如果流量瞬间爆发,比如秒杀,节日大促,数据库还是容易会被打挂。

这时候我们就需要第二招,缓冲

具体点说就是流量来了,我们要挡和削,当流量进来的时候,可以通过前置措施先挡住一部分,然后再将大量的并发请求变成有序的排队请求将服务的压力降下来。

读流量处理

当读流量很大时,我们可以先做一些前置缓存,也就是Redis。这一层的核心目标就是过滤无效请求,读取热点数据。请求进来之后,先别去查库,先查 Redis。

比如说秒杀场景,库存没了,直接在 redis 层返回已经售罄,数据库根本感觉不到压力。

因为加了Redis,这个时候,就很容易会被问到,如果Redis挂了怎么办呢?或者有的直接问,缓存穿透、缓存击穿、缓存雪崩怎么处理呢?

  • 缓存穿透
    • 大量的垃圾请求数据,缓存中没有、DB中也没有,查询缓存不存在,则流量直接打到DB。
    • 解决方案:缓存空值,对不存在的数据也缓存一个较短时间;使用布隆过滤器过滤不存在的数据。
  • 缓存击穿
    • 高频热点突然过期,大量请求击穿缓存,请求到DB。
    • 解决方案:一些热点缓存数据可以不设置过期时间或访问后延长过期时间;用一些互斥锁来锁住数据,缓存失效时先锁住,当从DB中加载完新缓存数据后再释放锁。
  • 缓存雪崩
    • 大量数据同时失效或缓存出问题了挂掉了。
    • 解决方案:可以给缓存数据分散的设置过期时间,防止同一时间失效;热点数据可以不设置过期时间;缓存出问题时,不能直接打到DB,做降级处理;缓存集群部署,提升可用性,降低雪崩风险。

写流量处理

有了第Redis的缓冲,接下来就是第二层MQ的缓冲了,因为如果是大量的读请求可以用Redis抗住,但是如果是大量的写请呢?例如:下单请求,你如果直接给打到数据库,那不但数据库会崩了,连请求也都得丢了。

这时就可以引入MQ(消息队列),引入MQ后的逻辑就变成了,用户下单后发出一个消息给MQ,然后立马返回给客户正在排队,这样响应就变快了,用户也能及时看到状态变化。

订单服务根据自己的消费能力,慢慢的从MQ中拉取消息来进行处理,这就把高并发变成了低并发。实际落地选型通常来说比较建议 Kafka 或者是 Rocketmq。但 Kafka 它更加适合像日志采集这些吞吐量极高的场景,更多场景我们会习惯用 Rocketmq,它比较适合金融交易,而且它支持事务消息,可靠性非常的好。

这里在讲到MQ的时候,也有时会被问,MQ消息如何不丢?如何保证不重复消费?

  • 如何不丢消息?发送方只要保证MQ 消息发送成功即可,剩下的由MQ自身保证,MQ会有持久化以及分片副本机制,消息接收方也要保证在真正处理成功消息后再提交offset。
  • 如何不重复消费,可以在发送方发消息时进行一些防止重复发送的处理,消息接收方也要做幂等处理,例如用Redis记录消息ID。

第三步"防"

前面两步是进攻,最后这一步就是防守了。

如果流量真的超过了系统的物理极限或者某个服务代码写的烂报错了怎么办?

我们就需要建立一套多维的防御体系,核心思路就是层层设防,丢卒保帅。

第一道防线:网关层

这是系统的大门,我们在这里可以做一些 ip 维度的限流,比如用 nginx 限流模块限制同一个 ip 每秒只能访问五次,这就能把大部分恶意的爬虫脚本攻击直接挡在门外,根本不让他们消耗后端的资源。

第二道防线:应用层

这就是系统的内功了,流量进了微服务内部,现在推荐可以使用阿里的 Sentinel,它比以前的 Hystrix 更强大,可以支持控制台的可视化配置。

在这里主要做三件事情:限流、熔断、降级

  • 限流:设置当QPS 超过一千直接拒绝,保护服务不被压垮。
  • 熔断:下游支付服务挂了,上游订单服务千万别死等,直接熔断,防止雪崩。
  • 降级:大促高峰期把查看历史订单、商品推荐这些非核心业务直接降级,返回降级提示或缓存数据,把 CPU 和内存全让给下单和支付这些核心业务。

限流 使用Sentinel,说出来常用的两种限流模式

  • 线程数模式:秒杀接口最大 300 并发,超了直接返回"售罄"。
  • QPS 模式:短信接口 1000/s,令牌桶匀速通过。

熔断使用Sentinel

Sentinel 把"统计窗口 + 三态熔断器(CLOSE、OPEN、HALF_OPEN) "做成可插拔的 Slot;业务侧只需定义资源和 fallback,其余状态流转、阈值判断、超时恢复全部由框架完成,真正做到了"零侵入"的熔断保护

在应用层其实还有一招就是异地多活,为了保证更极端的情况,例如:某城市大面积停电或者网络光缆被挖断了。

异地多活

  • 三地五机房,每个库至少两副本,Paxos/Raft 保证一致性。
  • 任何城市级光纤断,30 s 内完成 Leader 重新选主,RPO=0,RTO<30 s。

复盘

高并发架构设计无外乎"拆、缓、防 "三板斧:先通过业务分治、数据分片、集群化部署把系统横向扩展到极致再以多级缓存与消息队列将瞬时峰值削平成可线性增长的消息流最后用限流、熔断、降级以及异地多活等多维防护手段,为系统守住最后的容量边界

三步环环相扣,层层递进,既展示了架构思维的体系化,也体现了在成本、复杂度与可靠性之间的权衡艺术。真正落地时,还需结合业务场景、团队成熟度与运维能力,在"理想设计"与"务实交付"之间找到最适合自己公司的平衡点。

相关推荐
spencer_tseng3 小时前
Unlikely argument type for equals(): JSONObject seems to be unrelated to String
java·equals
爱敲代码的小鱼3 小时前
事务核心概念与隔离级别解析
java·开发语言·数据库
小冷coding3 小时前
【Java】遇到微服务接口报错导致系统部分挂掉时,需要快速响应并恢复,应该怎么做呢?如果支付服务出现异常如何快速处理呢?
java·开发语言·微服务
菜鸟小九4 小时前
redis高级(存储能力问题)
数据库·redis·缓存
一个处女座的程序猿O(∩_∩)O4 小时前
Nacos 中的 Namespace 深度解析:实现多租户隔离的关键机制
java
HeisenbergWDG4 小时前
线程实现runnable和callable接口
java·开发语言
JavaGuide4 小时前
IntelliJ IDEA 2026.1 EAP 发布!拥抱 Java 26,Spring Boot 4 深度支持!
java·后端·mysql·springboot·idea·大厂面试·javaguide
丁一郎学编程4 小时前
测试开发面经
java·开发语言
a程序小傲4 小时前
京东Java面试被问:RPC调用的熔断降级和自适应限流
java·开发语言·算法·面试·职场和发展·rpc·边缘计算