2013 年左右,我司业务发展迅速,每天晚上都会面临服务器濒临崩溃情况。 我相信每个高速发展的互联网企业在某个阶段都会面临这样的情形,比如去年爆红的「足迹」。 过程往往是:线上出现故障,手机会收到报警,然后登录到服务器上去解决问题。 处理这种问题工种现在有一个时髦的名称,叫做「SRE(Site Reliability Engineer)」系统可用性工程师。
虽然我常常救火,但是我还是想尽可能避免线上发生故障。「最好的消息,就是没有消息。」 减少故障出现概率,增强系统可用性,降低故障处理时间是 SRE 的最大课题。 在这里有最常用的两个手段,一个是优化性能,一个是做好容量规划和扩展。 这里我着重讨论后者「容量规划」。
^ 看我的一堆报警消息
面临的问题
面对暴涨流量,一边是业务方的满心欢喜,一边就是工程师的烦恼和压力了。 也许是一个受欢迎的功能上线了,或者是某个社会活动导致流量爆发,系统开始出现高延迟,磁盘 IO 不够用了。 也许是 DB 第一个倒下,也许是 RPC 系统第一个倒下…… 呃,大神可能会说,我艹,RPC 系统第一个倒下还搞个屁啊,赶紧倒闭算了。
核心的问题就是,在现有性能下面,在面临可能的大流量冲击时候,如何做到不慌不忙,能够 handle 住突如其来的流量?
设定容量目标
在解决这个问题之前,我们得先考虑清楚,我们到底要多强的流量处理能力。 如果今天我们只是一个两三台服务器的小团队,却企图设计一个能够抗住 1 亿 pv 访问的系统, 显然是不现实的,至少是不经济的。
衡量系统容量的指标可以简化为在什么流量下面,提供什么样的可用性保证。 一个实际的样例是,在 1 亿 pv 下面,提供 99.99% 的可用性, 其可用性的评判标准是「服务器在 200ms 内返回正确的数据」。
这里有一个重要的概念,可用性保证,术语是服务等级协议(SLA)。 这个指标可以从大部分标准云供应商的标准条款里看到,比如我司机房供应商提供的可用性保证是 99.9%。 阿里云 ECS 的 SLA 是「99.95%」,统计周期是 1 个月 (如果故障时间低于 5 min,不计入故障时间,云供应商都这样,特别霸权)。
一个对 SLA 的直观认识是(具体数据来自 High availability - Wikipedia, the free encyclopedia):
- 99.0% 意味着一年有 87 天不可用
- 99.5% 意味着一年 1.83 天不可用
- 99.9% 意味着一年 8.76 小时不可用
- 99.99% 意味着一年 52.56 分钟不可用
- 99.999% 意味着一年 5 分 15 秒不可用,这是高可用的一般标准
设定越高的 SLA 的成本越高,具体 SLA 的设定是成本、收益、期望的平衡。 不同的业务需要的 SLA 也不一样,一般认为 99.9% 基本可用,99.99% 可用性较高, 99.999% 为高可用。
有些云供应商号称 8 个 9,9 个 9,那往往都是对于存储服务里面的数据不丢失这个指标。 除了忽悠忽悠人,这个 SLA 没什么用的。
测量
做一件伟大事情时候,先有目标,下一步如果是迈出脚步出去闯荡,那么往往换来的是一个身心疲惫的自己。 更稳当的做法是,先摸摸清楚,自己有几把刷子,是不是还要再练练,有没有资格上战场。 没有 Profiling,就是瞎子,根本不用谈优化和容量规划。
对于一般的业务场景而言,常见的测量指标分为三类:
- 服务器的硬件指标(CPU、内存、硬盘 IO、硬盘容量、网络)
- 服务的软件指标(QPS / latency / pool)
- 业务的数据指标(核心业务指标,比如注册数,核心动作次数)
我司的实践情况是这样的,我们使用 Zabbix 测量服务器,用自己设计的系统收集服务数据,使用 Grafana 呈现。 后者被设计到 RPC 系统内部,数据是全量收集。 我司在业务层面的数据监控做的还不足,这种不足不仅仅体现在数据的全面性上面,还体现在相关成员(比如产品汪)对数据的利用率上面。
除了测量线上的实施数据,了解某个设施的性能极限也是很重要,目前常见的测量方式是:
- 模拟流量进行测试
- 在线上进行测试,并实时跟踪进展情况,出现异常时候,停止流量切入
- 从线上引入流量到测试环境进行测试
我发现,第一种方法往往不准,第三种方法对于小团队来说,成本太高。第二种方法是最粗暴和有效的。
预警和提醒
仅仅知道当前系统的性能表现是不足的,重要的如何将这些数据利用起来,对未来系统增长进行预估。 流量增长 vs 资源消耗,这个曲线大部分情况是线性的,有些情况确实指数增长的。
常见的做法是,给核心指标设置一个阈值(比如 80% 磁盘使用率,40% 磁盘 IO 利用率),当监控的数据到达这个阈值时候。 就必须进行容量扩充,进行负载均衡。
一个从运维同学身上学到的是,提前采购一些设备放到机房里面,比如硬盘、内存,别到时候供应商来不及供货。 必要库存可以降低 MTBF。
除了设定阈值报警,应当定期跑一些脚本获得数据。定期检查报警系统,避免报警系统失效。
必选项 - Scalable
上文写到,「必要时候进行容量扩充,进行负载均衡」。 这点的提出,意味这需要保证基础设施是可扩展的,支持负载均衡,支持硬件扩容。
Web 系统比较容易做到横向扩容,使用 Nginx / LVS 等负载均衡即可。 中间件服务一般也是在设计时候就考虑了扩展。(什么?你们家 RPC 系统设计调用不支持扩展?什么脑残设计?!)
DB 级别的服务,往往就要花一些心思了,一些技术(比如 MySQL)想要做到横向扩展, 需要进行提前设计。而一些设施虽然容易进行扩展,比如 ES / Kafka 等现代化设施, 但在部署的时候仍然要进行一些提前准备。
除了提前做好 Scalable,还有几个和部署相关的 tips 可以供参考:
- 使用工具:自动化部署,现在有太多工具可以供选择,比如 ansible 就是一个很好的工具
- automatic everything:避免登录服务器操作才能保证未来自动化
- 工程化:用最佳实践去维护部署系统,用工程化的态度去写部署代码
- 保持同质,避免花样:避免使用 shell 级别的操作原语操作部署系统,使用预设的 module 去操作
End
好了,现在去预测一下当大流量来临之际,你的服务会在哪些环节失败。 想不出来的话,就一点点去测量各个环节性能,然后做一把容量规划吧。
调优和增加容量,这是两个手段,这两个手段互相作用,互相影响。使用时候需要根据成本和收益进行选择。
关于容量规划的更多细节,可以看看 Web容量规划的艺术 (豆瓣) 这里看看。只是这本书写在 2010 年,并且作者介绍的过于传统运维视角一些。
原文链接: 搞定暴涨的流量 | Log4D
3a1ff193cee606bd1e2ea554a16353ee
欢迎关注我的微信公众号:窥豹