字节一面:你负责的业务系统,流量突然提升100倍QPS,你怎么办?

前言

大家好,我是田螺

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

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

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

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

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

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

1.1 限流

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

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

  • 可以使用GuavaRateLimiter单机版限流,也可以使用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挂了,如何兜底呢?是否有乐观锁兜底,是否有降级?是否有数据核对方案?

——转载自:捡田螺的小男孩

#牛客在线求职答疑中心#
全部评论
太长了 放个链接给我
点赞 回复 分享
发布于 今天 02:21 湖南

相关推荐

1. Java 基础与数据结构Java 面向对象有哪四个特性?Java 常见数据类型有哪些?HashMap 的底层实现是什么?为什么链表会转成红黑树?红黑树的时间复杂度是多少?数组插入、链表插入的时间复杂度对比?常见排序算法及时间复杂度(快排的原理和复杂度)。Set 的底层结构是什么?和 HashMap 的区别?线程安全的集合有哪些?ConcurrentHashMap 的实现方式(Segment 锁、CAS 乐观锁)。CAS 是什么?如果版本号不一致会怎样处理?2. 多线程与并发Java 中的线程与操作系统中的线程是否相同?多线程同步的手段有哪些?GC 的作用是什么?常用垃圾回收算法有哪些?Java 中默认使用的垃圾回收器及特点。变量存在堆还是栈的条件?方法内局部变量存放位置。3. 网络与协议你们项目是否是微服务架构?用的 RPC 还是 HTTP?TCP 的可靠性如何保证?为什么挥手要比握手多一次?如果不多一次会出现什么问题?UDP 和 TCP 的区别,为什么游戏可以使用 UDP?为什么需要 HTTP 协议?HTTP 和 TCP 的关系。HTTP 长连接与短连接的区别和好处。4. 项目场景题在支付项目中,如何保证交易的一致性?什么是一致性(你们系统中指的是什么和什么一致)?如何防止重复支付(尤其在数据未落库时的并发情况)?分布式锁的实现方式(Redis setNX、过期时间、续租机制)。Redis 除了做锁,还常用于哪些功能?Redis 常见数据结构(string、list、set、zset 等)及底层实现。为什么同一数据结构在数据量大小不同的情况下会使用不同的底层结构?跳表的原理和时间复杂度,为什么还需要字典结构配合?5. 算法题二叉树路径和等于 targetSum 的路径数(路径可以不从根节点开始,方向必须向下)。要求写出解题思路和代码,并分析时间复杂度。
查看29道真题和解析
点赞 评论 收藏
分享
昨天 22:55
已编辑
南京大学 Java
面试时间:95分钟——————非技术——————1. 自我介绍2. 为什么从字节离职?3. 提转正了吗4. 字节和美团实习感受的区别?5. 开始挖美团的实习,和一面不同,这次是聚焦于一个工作展开延伸,而且问的很深,更多不是技术方面而是问为什么要做这个、如果xx怎么办,以及我自己工作中的感受和思考,是否感兴趣等等6. 自己有明确的想法吗?想做什么不想做什么7. 你认为你在美团实习的表现怎样?——————技术——————8. 抽象类和接口的区别?9. 你在实际开发中是怎么应用java的面向对象特性的?10. java并发编程中,需要前置的一些线程进行处理完之后再进行后续线程调度,怎么做?11. 自己在开发过程中用到的数据结构(说了字典树),追问其概念12. 学生考试,每个学生每门课都有考试成绩,设计库表(说了减少冗余的范式设计和留冗余换查询性能的反范式设计,追问后者具体怎么设计,答以学生id和考试id两个字段作为主键构建表,查询考生成绩时无需联表)13. sql题,查每门课的平均成绩14. 如果sql查询非常慢该怎么排查你应该知道吧(刚准备回答面试官就默认我知道直接pass了)——————代码——————15. 手撕:二叉树序列化和反序列化(之前看过一眼但很久没碰了,打算参考k神的思路做层序遍历,但是写的过程中面试官觉得我的思路不对(实际上是可以的),最后因为时间原因并没有完全写完,面试官说明白我的思路了先到这里)——————闲聊——————16. 平时是怎么学习新知识的?17. 聊了下rag18. 哪些事情会让你有热情反问:对校招生的期待,然后围绕这个又聊了一会,面试官也反向问了我对即将从事的工作的期待面试官态度非常和善,和他讲话会进行点头反馈,语气方面也不压力,体验很好。不过面试官为了控制时间,基本上问的技术问题一看我会就不让我继续说了hhh(不然我总是围着一个问题延伸出来扯好几分钟)。不过没想到的是问了很多非技术方面的问题,也没有事先特意准备过,所以基本上就是现场快速思考快速组织语言
查看18道真题和解析
点赞 评论 收藏
分享
评论
2
12
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务