系统稳定性治理最佳实践
系统稳定性治理最佳实践
稳定压倒一切,没有稳定就没有生成。国家是如此,业务系统也是如此。老子说,“治大国若烹小鲜”,治理系统也是要做到同样,要掌握火候,精选食材,用料恰当,辅以煎炒烹炸煮,则方能出一盘好菜。
很多同学优先考虑公务员、教师等职业,其中非常重要的一个因素就是这类职业相对稳定。应用系统稳定性也是如此,是所有因素里的前提。
试想一下,支付宝经常打不开,你还敢存钱进去吗?
试想一下,微信经常卡死,你会不会烦躁想骂人?
试想一下,京东一支付就系统繁忙,你慌不慌?
那么系统稳定性该如何治理?有没有什么标准或者可以放之四海皆准的方法论和实践?
系统稳定性问题
一个系统稳定性取决于很多因素,同样也受制于很多因素。
为什么丰田可以40万公里不修,而某些国产车开了1年,除了喇叭不响,其它地方都会响?
为什么纳智捷不停车邮箱根本加不满?
类似的,一个系统的稳定性也受制于很多方面,总结下来大致是以下几点
硬件及网络影响
这个是指应用的容器层面的影响,包括服务硬件、机房、网络带宽等。这类因素往往对于开发人员来说不可控,比如管道工人挖断光缆、运营商网络抖动或延迟等。
这类问题一般来说很难预期,也很难针对问题进行专项治理。覆盖全世界网络,根本没有人可以保证网络绝对的稳定性,也根本无法保障一台服务器永远不宕机。
高并发大流量
对于一般的系统来说,流量往往不会成为瓶颈,一般的中小企业做的都是垂直类、行业类业务,总体覆盖人群一般不会很多,百万级已经是天大的调用量了,大部分的系统估计只有几十到几百的QPS。针对初级的访问流量,尚且不用做高并发大流量的设计,遵循普通的开发准则即可覆盖99%以上的业务了。
但是针对全球型、全国型的国民级应用,则高并发和大流量是主要要考虑的一个TOPIC,不仅在技术方案上就做重点设计规划,还需要持续关注和治理专项。
比如微信DAU达到了10亿级别,这个量级对所有相关的系统都提出了很大的挑战。一个全员推送不当,可能导致全国人民微信抖三抖。
比如淘宝双十一高峰期需要处理66W笔订单,这个量级是一般的系统根本无法满足的。
方案设计缺陷
方案缺陷指技术方案或者产品逻辑设计有问题,在满足一定的条件时,可能不会出问题,但是走了某个流程或者流量到了某个层次就凸显异常问题。
编码缺陷
这个是最多的一类问题,开发者由于水平层次不一,有的停留在“能运行就赢了”,有的停留在“能在各种入参变化的情况下运行正常”,有的会“极端流量网络异常下依然可以运行”,从“面向正确”到“面向错误”编程。《致命Bug:软件缺陷的灾难与启示》的一书有很多例子,都是因为编码BUG,导致了超乎想象的灾难。比如第一章提到的“0.000000095的误差夺走28条生命”等故障都历历在目。
阿里云也发生过
编码错误类型比较多,通常有以下一些:
- 边界值和异常值未考虑
这是最常见的一个问题,大多数初级开发者,往往仅考虑正确且正常的输入的情况下代码合计,而往往忽略边界条件。比如对入参不做非空校验、价格不做负数校验、不做超过列表长度的取数校验等。这类问题看似很小,但是在极端情况下,往往会引起很多莫名低级的BUG。
还有一类是数据源本身本身就可能是出错的,代码没有对这类数据做处理,则导致在运行期间发生异常。接口设计里有一个很简单的原则“外部输入数据是不可信的”。即在考虑接口设计时,就要充分考虑外部数据的一切可能性,有可能传递数字格式的String类型,偏偏就传递了一个字符串;预期传递一个null的,偏偏传递了一个字符串"null"等。
- 并发异常
这类错误相对来说更为“高端”“隐藏”,在单机的条件下一般不会出现问题,但是到了生产多线程环境可能就会出来。由于在开发过程中,对多线程的测试和调试也相对较少,导致开发和测试期间都不能简单的复现。比如用户加入组织后,组织又立即解散了,在并发的情况下,可能组织先解散,然后再出现用户加入组织的事件,如果不考虑其它因素,代码处理可能就会产生BUG。
- 幂等或事务异常
对需要做唯一性约束的数据没有做约束,比如订单ID不能重复、用户名不能重复等等。很多情况需要对数据一致性要严格保障。其中重要的两个就是幂等和事务,这两个点发生了异常,就会导致很多不一致性,进而产生大量脏数据和错误数据。
稳定性治理
稳定性治理的核心三板斧,监控、压测和演练。
监控
监控如果做到了360无死角,则可以第一时间主动发现系统异常,定位到了解决则是相对明确的。那么稳定性自然也有很高的保障,可以说监控是稳定性保障的前提。
那么如何做监控?做哪些监控?这个是每个工程师要细致思考的问题。监控不仅仅是发一条短信出来,告知工程师“系统异常”,而是应该快速告知工程师,哪个系统的哪个接口出现了什么样的异常,越具体,就能够帮助工程师快速定位问题,也就给工程师止血和恢复提供了更快的可能。
监控的告警方式一般有短信、电话、邮件,或者可以使用钉钉通知、钉钉机器人等方式。
钉钉群机器人接入方式也比较简单,还是非常推荐大家使用的,可以把多个告警源接入到钉钉,统一管理。
应用性能监控
load监控
load监控是对于容器和应用层面的监控,可以监控整个容器水位消耗,对业务负载能够起一个快速的决策。比如正常情况下。
简单来说,对于单核CPU,load为1表示已经满载了,如果超过1意味着好负荷了,有任务已经无法直接占用CPU资源需要一直等待,系统也可能即将崩溃。同理,对于多核CPU,load则对应具体的核数。一般来说4核CPU的话,load为4表示满载。正常情况下,70%的负荷率是比较正常的,即单核CPU的Load要小于等于0.7。
load详解文章:https://www.ruanyifeng.com/blog/2011/07/linux_load_average_explained.html
如上图所示,用TOP命令即可快速查看当前机器的load,图中的0.88则表示当前机器的实际负载,对于4核CPU来说,负载算比较轻的。
java线程数
java中线程是宝贵的资源,各种代码运行后都是以线程的方式来运转,线程是生产实例的最小单位,因此监控线程数就可以监控java应用的实际运行情况。相对load来说,java线程更纯粹,load包含了整个CPU的所有消耗,包括其他系统内置的消耗,而java线程则是统计了实际为应用本身提供服务的情况。
特别在多线程的情况下,可以快速发现是否有线程泄露等问题,这类问题往往通过其他指标无法直接观看。比如发现一个接口的RT已经接近超时,机器load飙升,但是接口本身又没有发现问题,这时候可以看看线程的行为。
GC监控
GC是垃圾收集的意思(GarbageCollection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,Java语言没有提供释放已分配内存的显示操作方法。
简单来说,JAVA运行期间的数据是以对象的方式存在的,而对象又存在生命周期,在时刻运行期间会产生大量的对象占用内存,因此需要有垃圾对象回收的策略,称之为GC。
GC监控可以判断编码中的对象内存泄露,可以对JVM本身进行,也可以对不合理的编码方式进行监控优化。
业务指标监控
数据大盘
诸如阿里云相关的云服务都提供了大盘的功能,可以监控机器的流量水位等。一些中小公司可以使用开源的工具搭建自身内部系统的监控。
具体可查看链接:https://blog.csdn.net/smooth00/article/details/85001823
大盘可以根据业务情况区分,比如订单创建大盘、用户登录大盘、账单支付成功大盘等,大盘可以帮助从全局角度观察同比环比趋势。通过趋势图可以对波峰、波谷、毛刺进行分析定位问题和优化系统。比如在突然的流量暴涨和暴跌,可以在数据大盘图快速定位。
成功率
又称之为“接口健康度”,及在指定时间内成功请求/总请求的比率,这个是接口稳定性里最重要的指标,可以通过这个指标直接判定系统的可用性。
健康度可以根据自己业务目标设置告警等级,比如某些非核心功能,可能设置低于70%成功率告警,对于某些核心功能,比如IM的会话送达率,则可能设置99.99%以上。
RT值
接口重要的几个指标,除了QPS外,就是RT了,RT表示一个接口的响应能力,RT越短说明接口提供服务的效率越高,相反,RT越大则代表提供服务能力越弱,一个系统内部出现多种情况的故障时,一般伴随的就对外提供能力变弱,响应的就是RT会明显加长。
因此通过监控RT可以很好的监控一个系统的提供服务能力的强弱,不仅在故障期间能够更为直观,在平常也可以给工程师提供一个性能优化的视图。
主日志
除了几个常规指标外,还有一个指标叫主日志,即把核心的错误日志都打印到同一个文件,通过关键的关键字进行错误分类,进而实现对错误分类和错误详情进行告警,帮助快速处理和解决线上问题,实现免登机器定位错误的能力。
DB监控
相对应用来说,DB往往是整个系统的性能瓶颈。优化一个准则,也是尽量把流量挡在DB外。也很容易理解,代码或硬件问题,可以通过集群和分布式来解决,但是所有写流量基本上都要集中在一个数据库实例中。因此数据库crash了往往会造成整体功能不可用。
当然在方案设计时候,可以显示的优化DB层面的设计,比如读写分离、数据缓存、分库分表等。这个对数据库的设计在其他内容中介绍,本文还是关注如何做好DB监控。
QPS
qps 每秒处理的查询数
QPS和TPS是判断整体数据库的核心指标,该指标也表示了当前的数据库运行能力,当然应用层不好判定具体暴涨业务的时候,可以通过数据库的SQL来对数据进行定位,辅助定位到异常的SQL语句,进而分析故障原因。
TPS
tps 每秒处理的事务数
慢SQL
数据查询变慢的一个原因,就是慢SQL,慢SQL顾名思义,就是一条执行很慢的SQL,主要是查询慢,一般来说SQL查询都是毫秒级别,到了秒级的话,就是基本慢SQL了。慢SQL严重性不仅是本身查询慢,而是慢SQL会大量消耗数据库本身的资源,比如数据库的线程、CPU、内存等,从而使得整体服务能力下降,最终拖垮整个数据库。
压测
相对运行期间监控来说,压测是运行前的一个提前发现问题的操作。压测也需要做到常规化、持续化执行。压测可以用自动化的手段来在真实环境下获得系统的稳定性问题,提前发现系统异常和薄弱环节。
像大型的双十一,就会用提前压测的方法模拟双十一甚至超过几倍的请求,来进行全链路探测系统问题,并及时进行修复解决,这样当然就不怕双十一期间的自然大流量完全压垮系统。也提前做到了心中有数。
压测一般用我们上述提及的指标作为衡量标准,比如load是否到1,成功率是否下跌,主日志是否出现错误等等。
演练
监控发现问题治理,压测探查系统薄弱瓶颈,而演练则是在生产上真实的创建故障,用来发现系统稳定性、鲁棒性和自动恢复性,还能检测应用负责人是否有快速响应系统异常的能力、止血和修复的能力。
演练类似消防演习,即人工的采取某些措施,比如断网、停DB、MOCK缓存失败等。
总结
稳定性治理三板斧:监控、压测和演练。应用容器三要素:load、线程、GC。业务数据监控四要素:大盘、成功率、RT值、主日志。DB监控三要素:QPS、TPS、慢SQL。
系统稳定性压倒一切,只有保障了好了稳定性,才能帮助业务蓬勃增长,因此稳定性治理始终是工程师基本能力之一。
------图片来自网络,侵删