详解软件系统稳定性的三大秘密

 更新时间:2021年5月20日 13:07  
随着软件复杂性越来越高,稳定性的保障越来越难,随着服务规模越来越大,稳定性的重要性越来越高。工程师在设计和开发软件的时候,要坚持底板思维。

何谓系统稳定性?

控制系统理论认为:系统受到某种干扰而偏离正常状态,当干扰消除,如果系统的扰动能逐渐收敛并最终恢复正常状态,则系统是稳定的;反之,系统偏离越来越大,则是不稳定的,所以,稳定性是系统抗干扰和返回平衡状态的能力。

对于经典的传递函数的软件系统,一般我们讲的稳定指的是BIBO稳定,即有界输入有界输出稳定。一个系统如果对任意有界输入得到有界输出,它就是BIBO稳定的。一句话,稳定的系统对于各种输入需要有符合预期的输出。

随着软件复杂性越来越高,稳定性的保障越来越难,随着服务规模越来越大,稳定性的重要性越来越高。阿里云CEO行癫把稳定性比喻成木桶的底板,如果稳定性出问题,则滴水不留,所以,工程师在设计和开发软件的时候,要坚持底板思维。

我们的软件需求和计划很少考虑非功能部分,然而软件的结构和实现却有非常大的比重服务于此,这也许是软件项目计划经常延期的重要原因。

如何保障稳定性?

虽然理论上没有绝对稳定的系统,但我们依然可以有所作为,使我们设计和开发的系统在生产环境接近稳定运行。

从大的方面讲,稳定性保障,可以分成3个部分:

制度纪律:

  • 编码规范、代码提交门禁
  • Code Review
  • 静态代码扫描,动态代码分析
  • Unit Test、压测
  • 灰度发布、Rollback、应急预案
  • 监控
  • 复盘、故障树分析

思想之道:

  • 保持简单、降低复杂度
  • 不(零)信任、面向失败设计

实践之术:

  • 冗余设计(数据、计算、带宽冗余)
  • 快速恢复设计(无状态设计)
  • 容错、灾备
  • 隔离
  • 过载保护(限流、熔断、有损服务)
  • 错误重试策略,避免流量风暴
  • 去关键路径、去中心化、避免单点故障
  • 负载均衡(load balance)
  • 看门狗设计
  • 安全编码

制度纪律

通过制度去规范操作和行为,通过纪律去约束大家在框架内活动,被证明是保障稳定减少出错行之有效的方式。

纪律是关键,只有持之以恒的遵守制度,才能避免方法和规定沦为空谈。

但制度和纪律只是划出质量底线,只能解决大多数稳定性问题,难以发现一些隐匿的问题,需要配合思想之道和实践之术,持续改进软件质量,才能全面保障稳定性。

思想之道

道是大的层面,它具有全局性的指导意义,我从众多的指导思想里,挑选最重要的两点:保持简单和不信任/面向失败设计,展开来讲。

1. 保持简单

复杂是稳定性的天敌,保持简单即保持稳定。单一职责,功能清晰即是践行保持简单。

把简单的东西搞复杂很容易,而化繁为简则堪称化腐朽为神奇。所以保持简单并不是低要求,它需要你透过表象洞悉事物本质,用最直接最土味的方式解决问题,做技术的同学有一个奇怪的癖好,喜欢把自己最近琢磨的东西用到项目中,不然总有锦衣夜行的感觉。

我的建议是“学深用浅”。引入复杂性,一方面要权衡收益,另一方面要警惕损伤,要理解项目开发很多时候是团队合作,任何复杂性的引入都会对合作者提出更高要求,严以律人是危险的,低门槛才是符合人性的。

2. 不信任设计、面向失败设计

不信任设计又叫零信任设计,和面向失败的设计有相似之处,其本质都是防御性编程思想。

不信任设计思想假设系统依赖的上下游都不靠谱,假设周围都是坏人,假设攻击无处不在。

网络服务需要对客户端请求参数做严格验证,不仅检查合法性,也要验证NaN。游戏开发有一句名言:假设客户端的数据都是假的。

进程内的函数调用大多时候很安全,会有可预期的结果,但如果跨进程调用(RPC)的可靠性则会低很多,有可能超时,有可能丢包,有可能失败,调用者必须意识并处理好各种异常情况,是重试?如果重试的话重试多少次?重试之间的间隔应该怎么确定?请求的上下文怎么保存和恢复?

我们要正确理解不信任设计的内涵,避免用力过猛,警惕借面向失败设计之名行无效编程之实,比如已经对客户端请求数据做了严格校验,在服务器处理过程中,重复检验,比如已经对接口入参判空,在内部调用过程中重复判断。这会降低代码浓度,混入大量无效代码,损伤可读性和执行效率,本质上是违背“保持简单”原则的。

实践之术

术是局部层面,它是实践经验,牵扯方方面面,难以尽数枚举。

如果以文章写作类比软件开发,谋篇布局相当于设计层面,设计层面要致广远,遣词造句相当于实现层面,实现层面要尽精微。

所谓千里之堤溃于蚁穴,防微杜渐功德无量。

1. 冗余设计

冗余设计指留出安全余量,冗余包括数据冗余、计算冗余、带宽冗余。

数据冗余指一份数据多个副本,一主多备。

计算冗余,比如服务实例的QPS极限是10K,但实际上我们会按5K跑,这样,即使出现流量超速增长,我们依然有反应时间。

2. 快速恢复设计(无状态设计)

互联网服务很多都是无状态设计,服务实例只是逻辑的盒子,后面跟着分布式一致性数据库,这样能极大简化设计,即使实例挂了,客户可以很容易迁移到其他服务实例执行,而有状态设计则要复杂难搞得多。

3. 容错、灾备

容错指我们的系统要有一定的错误容忍能力,这意味错误发生,我们要能查错、检错、避错、甚至改错,只要可能,我们就要吞咽错误。

灾备这个大家耳熟能详,主从设计,异地备灾,目标都是为了应对各种极限情况。

4. 隔离

隔离本质上就是说如果故障发生了,如果故障发生,而又不能吞咽,那也应该隔离避免错误传播扩散,千方百计缩小影响范围,相当于感染新冠要被隔离起来。容器化等技术为隔离提供良好能力支撑。

5. 过载保护熔断

熔断:

机制不止软件设计独有,股市也有,我甚至怀疑软件的熔断机制是从股市学来的。

限流:

系统设计要做好资源耗尽、资源不够用的情况,如果服务请求超过服务能力,那就应该限流,这应该作为一种配置,或者自动执行的策略。

这个跟地铁限流差不多,处理不了,那就排队。

有损服务:

有损服务我印象中最先是腾讯跟海量服务的概念一起提出来的,指如果出现服务能力不够,不能为所有客户所有业务提供服务的异常情况,那系统有所取舍,尽可能保持业务运行,减少损失,比如在微信服务器在处理能力有限的情况下,可以优先保消息发送,而关闭朋友圈服务能力,比如直播业务在带宽有限的情况下,应该降低码率减少清晰度,而不应该拒绝服务。

有损的意义就是有损失,有损伤的意思,它是一种思想,是退而求其次,是不得已而为之。

6. 错误重试策略,避免流量风暴

如果设计一个ToC服务,在客户大规模断连的情况下,客户会重连,重连失败再连,如果重连尝试的频率不控制好,正常客户端重连有可能演变成对服务器的大规模攻击,打爆一台服务器,又去灭另一台,这太吓人了。

可以参考kernel TCP的重连策略,有最大尝试次数,而且重试间隔是逐渐拉大的。

7.去关键路径、去中心化、避免单点故障

企业不要关键先生,关键先生会成为瓶颈,软件也不能把宝压到一个地方,去中心化去集中式,没什么难理解的。

8.负载均衡

load balance其实就是分担压力,LB要避免倾斜,有多种LB算法,比如RR,比如一致性hash,各有利弊,有兴趣可以研究下。

LB不仅限于服务,进程内的多线程可能也会需要考虑这个问题。

9.看门狗和心跳机制

可以参考kernel的watch dog,其实就是看护机制,检测错误并努力掰过来。

10.安全编码

安全编码是一个职业程序员的基本要求,安全编码规则很多,很细节的一些规矩。这个可能跟语言相关,如果是C++相关的可以参考:C++的门门道道

  • C相关的规则要少一些,我顺手列举一些。
  • 比如要注意初始化。
  • 比如全局变量不要有构造顺序的依赖。
  • 比如慎用强转,强转等于接管了编译帮你做的类型检查。
  • 比如理解线程安全函数,理解可重入的概念,理解信号机制。
  • 比如要避免死锁,理解ABBA锁理解自死锁。
  • 比如要谨防资源泄漏。
  • 比如处理好内存分配失败的情况,理解野/悬垂指针。
  • 比如要处理好边界,防止越界,溢出。
  • 比如内存拷贝要避免内存重叠,理解memmove的用途。
  • 比如理解递归的低效和栈的大小限制,避免爆栈。
  • 比如建议使用STD安全版本函数(_s+n)版本。
  • 比如了解unsigned < 0导致死循环的情况。
  • 比如了解浮点数跟0比较的问题。
  • 比如理解整型数据溢出和反转。
  • 比如不要返回临时变量的引用或者指针,理解栈帧动态伸缩的原理。
  • 比如理解做好把关检查的必要性,包括系统把关和模块把关。

小结

最后来读段经典:《系统化思维导论》一书中引用冯诺依曼的话写道:如果你观察一些自动装置,不论它们是人类设计的还是自然界本来就存在的,你通常会发现,它们的结构很大程度上受控于它们可能失效的方式,以及针对失效所采取的防御性措施(多少有些效果),说它们能预防失效有点夸张,它们不是能预防失效的,只是被设计成试图达到这种状态,这样至少大部分失效都不会是毁灭性的。所以,根本谈不上消除失效,或完全消除失效带来的影响。我们能尝试的只是设计一种自动装置,在大部分失效发生时仍能继续工作,这种装置减轻了失效的后果,而不是治愈失效,大部分人造的和自然界存在的自动装置,其内部原理都是如此。

以上就是详解软件系统稳定性的三大秘密的详细内容,更多关于软件系统稳定性的三大秘密的资料请关注猪先飞其它相关文章!

相关文章

  • 比较简单的虚拟主机管理软件MyIIS 1.0.0

    MyIIS 做了部分,程序只写了些函数(带数据库),具体调用各位写逻辑程序实现...2016-01-27
  • 戴尔确认出售软件业务 4年净赔16亿美元

    北京时间6月21日消息,据科技博客TechCrunch报道,当地时间周一上午,私募股权公司FranciscoPartners、对冲基金ElliottManagement旗下私募股权公司和戴尔公司举行联合新闻发布会,两家私募公司将收购戴尔软件部门。...2016-07-04
  • php 怎么打开?教你用什么软件打开php文件

    php文件相信很多电脑老手也不知道吧?本文教你用什么软件打开php文件,不知道的同学赶快来看看吧! php文件相信很多电脑老手也不知道吧?今天有一聚教程网网友问了编辑这...2017-07-06
  • 手机自带软件如何卸载?手机自带软件卸载教程

    很多手机都有一些我们不常用或者根本用不到的自带软件,而且这些软件占用着我们的内存很是碍事,那么如何卸载这些手机的自带软件?有需要的朋友可以来看看。 随着智...2016-12-21
  • Python爬虫+Tkinter制作一个翻译软件的示例

    这篇文章主要介绍了Python爬虫+Tkinter制作一个翻译软件的示例,帮助大家更好的理解和学习使用python,感兴趣的朋友可以了解下...2021-02-21
  • C#软件注册码的实现代码

    开发软件时,当用到商业用途时,注册码与激活码就显得很重要了。现在的软件破解技术实在在强了,各种国内外大型软件都有注册机制,但同时也不断地被破解。下面发的只是一个常用版本,发出源码被破就更容易了,但我们学习的是技术。当然也为以后自己的软件不会被轻易破解。...2020-06-25
  • vivo x9总提示内存不足安装软件失败怎么办?

    vivo x9老是提示内存不足应该怎么处理?下面小编整理了解决办法,一起来看一看吧。 问:vivo x9总提示内存不足安装软件失败怎么办?答:内存不足一般有两种,一个是运行内存...2017-01-22
  • IBM:今年敲诈软件比去年激增60倍 多数受害人支付了赎金

    IBM 安全研究部门最新研究发现,今年附带敲诈软件的垃圾电子邮件数量比去年猛增了 60 倍,几乎占到垃圾电子邮件总数的 40%。...2016-12-21
  • 详解软件系统稳定性的三大秘密

    随着软件复杂性越来越高,稳定性的保障越来越难,随着服务规模越来越大,稳定性的重要性越来越高。工程师在设计和开发软件的时候,要坚持底板思维。...2021-05-20
  • 开源软件那么多,我们该如何选择

    文TWInsights  当我们说起开源软件的时候,想必大家都有丰富的使用经历,小到 Node.js 的一个组件库,大到一套办公软件如 LibreOffice,再如 Linux 操作系统,可以说无奇不有,浩如烟海。就拿我们常用的 Github 来说,官方的数据显示已经有超过三千八百万个项目托管在上面。...2016-12-15
  • 预装软件需可卸载 靠隐私赚钱再也行不通了

    尽管姗姗来迟,也好过遥遥无期。自明年 7 月 1 日起,中国手机用户可自行卸载手机中用不着、看着烦又卸不掉的应用软件了。...2016-12-31
  • PS软件如何设置快捷键?

    每一个设置师对于自己喜好的快捷键是不一样了,如果我们换了电脑要如何定义自己习惯的快捷键呢,下面小编一为各位介绍一篇关于PS软件如何设置快捷键的教程。 一、打...2016-09-14
  • 汉字转拼音软件制件示例(汉字转字母)

    这篇文章主要介绍了c#汉字转拼音的方法,但不能判断多音字,大家可以参考修改使用...2020-06-25
  • 如何用VBS脚本收集远程计算机或本地计算机安装的软件

    这篇文章主要介绍了如何用VBS脚本收集远程计算机或本地计算机安装的软件,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-02-23
  • C#判断某个软件是否已安装实现代码分享

    这篇文章主要介绍了C#判断某个软件是否已安装实现代码分享,本文直接给出实现代码,需要的朋友可以参考下...2020-06-25
  • ftp软件的bug: 上传和下载的php文件换行丢失

    最近发现一个奇怪的事件,刚编辑好的php文件上传到Linux服务器上,然后下载后就发现代码在一行,换行符丢失了,找了好久才找到解决办法,分享如下。 在使用ftp软件上传下载...2016-11-25
  • C#定时每天00点00分00秒自动重启软件

    这篇文章主要为大家详细介绍了C#定时每天00点00分00秒自动重启软件,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-11-03
  • Python使用tkinter制作在线翻译软件

    这篇文章主要为大家详细介绍了Python使用tkinter制作在线翻译软件,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-02-22
  • Python结合百度语音识别实现实时翻译软件的实现

    这篇文章主要介绍了Python结合百度语音识别实现实时翻译软件的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-01-18
  • 学习C++编程的必备软件

    本文给大家分享的是作者在学习使用C++进行编程的时候所用到的一些常用的软件,这里推荐给大家...2020-04-25