<audio id="audio" title="春节特别策划 | 我们如何准备抵抗流量峰值？" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/ee/e6/eeeeddba9908501f1a98314c1ab601e6.mp3"></audio>

你好，我是唐扬，今天这一期加餐，我想跟你聊一聊如何准备抵抗流量峰值。

如果你是后端技术团队的负责人，那么在日常工作中，除了要完成产品提出的功能需求点之外，通常还要思考如何让系统平稳度过流量的高峰期。也许你会问，我的系统用户量级也不大，平时的并发量也不高，难道也需要考虑如何抵抗流量峰值吗？

在我看来，你当然需要，主要有两点原因：

一个原因是，我们应该未雨绸缪，让技术走在业务前面，因为运营团队一次成功的活动就可以给系统带来比较大的流量，如果你在技术上没有准备好，就会拖了业务的后腿。比如我之前维护的一个直播系统，平时的DAU只有十万左右，8台云服务器就可以支撑了，然而有一天，我们邀请了姚晨、郑爽等明星来做直播，大量的粉丝涌入直播间和她们互动，给系统带来了极大的冲击。那么，如果你遇到这种情况，该如何准备呢？

另一方面，你的系统也是不断发展的，系统的流量更不可能一成不变，你需要为系统的发展做准备。

而我们一般需要应对多种场景下的流量高峰，比如秒杀活动，还有就是我刚刚提到的明星空降直播间的活动，再比如特殊的节日（春节、元旦等等），也会让系统的流量高于日常的流量。那么我们在这些活动、节日来临之前，要做哪些事情应对可能到来的峰值流量呢？这就需要你做一些预案。

之前的课程主要涉及了在设计高并发系统时的一些方法，但无论你的系统设计得有多健壮，为了确保系统能够万无一失，我们还是需要在之前做一些预案的。

## 如何确定系统的瓶颈点？

在准备预案的时候，首先要梳理系统的调用链路。你要记住，我们需要保证整个系统的可用性，所以，你不能认为自己不用担心负载均衡服务器、数据库、缓存这些组件，因为它们是系统的一部分，你有责任主动地帮助发现问题和思考如何解决问题。

还是以我目前维护的系统为例，我们的系统刚刚完成了往公有云的迁移，但是原有自建机房服务的机器以及依赖的存储资源还没有完全下线。原本我们想使用公有云来支撑春节的峰值流量，但是由于服务刚刚迁移完成，公有云上的一些组件还不是很成熟，所以我们担心云上的服务在支撑高并发流量的时候会出现问题，就考虑使用公有云和自建机房一同支撑流量。经过我们对整条链路的梳理，下面就是一个简单版本的部署图。

<img src="https://static001.geekbang.org/resource/image/eb/0c/ebc74ac7f512f2704af5225fd08a080c.jpg" alt="">

你发现了吗，这不就是我们在[28讲](https://time.geekbang.org/column/article/171115)中讲到的同城双活方案吗？事实上，云机房与自建机房确实在同一个城市，经过我们的测试，两个机房之间的延迟在3ms左右，是可以使用同城双活的部署方案的。不过，这里有一个小小不同之处，那就是自建机房依赖的数据库与公有云上的主库之间有一个主主同步，而不是主从同步，这是使用公有云上的工具来实现的。这么部署的主要原因在于，我们期望在自建机房保留完整的存储服务配置（主从配置），这样一旦云上服务出现问题时，我们可以随时把全部流量都切回到自建机房中。

有了部署图之后，我们就需要逐一地来观察数据流转的链路上是不是存在瓶颈点，以上面的案例来看，你主要需要考虑以下几点：

首先，对于入口的LVS服务，主要考虑入口和出口带宽上是否可能存在瓶颈。我们在之前的某一次流量高峰时就是这一层的带宽达到了上限，从而导致客户端访问服务的时候出现了大量的请求失败的情况，最后也是通过客户端的监控及时发现了问题。

其次，在系统出现性能问题时，我们需要尽快确定瓶颈点是在LVS、Nginx还是在服务层。一个简单的做法是收集这三层的访问日志，从中计算出请求量、响应时间以及慢请求数量，而问题一定出现在出现慢请求的最下一层上。比如，如果服务没有慢请求，但是Nginx有慢请求，那么就很有可能是Nginx有了问题。我们之前就遇到过类似的情况，后续果然是部署Nginx的云服务器挂载的云盘带宽到达了瓶颈，影响了服务器的I/O，造成了服务的不稳定。

再者，你需要关注链路上的网络带宽以及线路的稳定性。无论是在自建机房还是云机房，机房网络的拓扑结构都会是比较复杂的，任何一段线路或者是网络设备都有可能出现问题，而一旦它们出现问题，你的服务也会随之受到影响。比如我的公司自建机房有多个，几个机房之间以专线相连，那么当服务存在跨机房的服务调用时（当然，你需要首先了解系统依赖的服务部署在哪个机房），就要关注专线的带宽和稳定性了。

当然，如果想要系统化地了解系统中可能出现的问题点，全链路压力测试依然是最主要的一个途径。

## 如何制定抵御高并发流量的预案

了解了系统的瓶颈点之后，我们就可以有针对性地制定预案了。在我看来，在不对系统架构做大调整的前提下，我们能够采用的方案并不多，总结起来主要有以下几点。

**切流，也就是把流量从一个机房切换到另一个机房。** 这种方法比较通用，你的服务或者依赖的组件出现容量问题时都可以采用这种方法，但前提是你的服务是多机房部署的。**切流的方式一般有两种：**

一种是全部流量流经一个机房的入口，然后在入口下面的某一层负载均衡层转到另一个机房，这种方式优点是流量的切换比较快速，基本上可以在秒级就完成，而缺点则是需要依赖专线，这是因为流量从一个机房转到另一个机房需要跨专线，如果专线的稳定性存在问题，那么流量的切换也会有问题。另外，跨专线之后也会增加服务接口的响应时间。

另一种方式是从域名解析也就是流量的最前端切换，我们可以配置某些地区或者全部地区的一定百分比的流量切换到另一个机房，这种方式的优点是不依赖机房之间的专线，当然了，服务响应时间不会增加，缺点则是流量不会被及时的切换过去，这是因为由于DNS缓存的存在，DNS更改的生效时间会在小时级别。在我看来，如果你部署的专线稳定性可以保证，也能够忍受服务接口的平均响应时间增加几毫秒，那么就可以采用第一种切流方式。

**扩容，也就是通过增加冗余或者提升配置的方式，提升系统或者组件的流量承载能力。** 这里不仅仅包括横向扩展服务器的数量来提升服务的请求处理能力，还包括我们使用的组件的扩容。比如说，我们可以通过增加MySQL、Redis的从库来提升组件处理查询请求的能力，再比如我们可以增加多组Memcached的副本来提升Memcached抗并发的能力。

**有一点你可能没有想到的就是专线的扩容，** 比如提升专线的带宽或者是部署双专线来提升专线的可用性。这里需要强调的是，需要扩容的资源一定要提前准备好，或者是提前扩容好，这样可以避免出现问题再扩容时的忙中出错。

**降级，** 即暂时关闭次要功能来保障系统整体的稳定性，这种方式我们在课程的[34讲](https://time.geekbang.org/column/article/176917)中有过详细的介绍，这里就不再多说了。不过我需要强调的一点是，降级策略一定要经过验证，你可以在测试环境验证，也可以在业务低峰期验证。

**限流。** 这一部分内容在[35讲](https://time.geekbang.org/column/article/177796)中也有过介绍，你可以提前在系统中埋下限流的代码，在系统遇到超过预期的流量，而你又没有办法通过切流或者扩容的方式解决的时候，启用限流的策略。

以上几点就是几种常见的抵御非正常峰值流量的方法，你在实际的工作中可以灵活地使用。形象点儿说，系统的维护其实就是流量的操控艺术，你或是将流量切向别处（切流），或是提升流量处理能力（扩容），或是截断流量（降级），又或是限制丢弃流量（限流），直到你的系统能够处理分配给它的所有流量为止。

## 课程小结

以上就是本讲的全部内容了。本讲我带你了解了在峰值流量到来的时候，如何迅速确定系统的瓶颈点，并制定相应的预案。这里你需要了解的几个重点是：

<li>
梳理数据流经的链路可以帮助你了解系统的全貌，也能够让你避免因遗漏了某些组件而没有制定相应的预案；
</li>
<li>
在高并发流量流经你的系统时，线路上的每一个组件、设备、线路都有可能成为你的系统的瓶颈点，你一定要小心评估，避免遗漏；
</li>
<li>
切流、扩容、降级和限流是几种常见的抵御高并发冲击的方案，你可以结合你的项目来灵活使用。
</li>

总之，预案是你针对活动或者节日突发流量的准备，关系到你的系统的生命线，因此你在制定预案的时候一定要考虑全面而仔细，不放过每一个可能出现问题的点，并且将压测作为发现问题的常规手段，不断地调整和完善，这样你在经历流量高峰的时候，才能够真正做到“泰山崩于前而色不变，麋鹿兴于左而目不瞬”。

## 一课一思

结合实际工作谈一谈你在面对突发的流量冲击的时候是如何制定预案的呢？欢迎在留言区和我一起讨论，或者将你的实战经验分享给更多的人。

最后，感谢你的阅读，虽然课程结束了，但我一直关注着留言，与你同在。
