1. 首页
  2. 数据分析

那些年我在大厂学到的工程思维(一):灰度思维

故不积跬步,无以至千里;不积小流,无以成江海。

骐骥一跃,不能十步;驽马十驾,功在不舍。

《劝学》

一个真实的故事

作为一个支付系统研发工程师,我在生产环境做过很多次线上变更。

这些线上变更,绝大多数都是平淡无奇的,以至于到现在都已经淡忘了。

值得自豪的是,我干了七八年的业务研发,线上变更都已经做到手麻了,从来没有因为自己的变更搞出过非常严重的生产故障。

唯独有一次,我和我们的dba(数据库管理员)在生产环境做主数据库切换。这本是一件稀松平常的事情,之前也搞过很多次,可以说有手就行。

但就是这次变更,却差点搞出一个生产故障,整个过程非常精彩刺激,以至于现在都让我记忆犹新。

而这,全拜我们dba的俄式切换所赐。

在继续分享这个故事前,为了让能让你更好地理解我们的工作,这里先让我做一点必要的铺垫。

首先,所谓的生产环境就是线上真实环境。

在生产环境里,我们部属了一套服务器集群,集群上运行着我们编写的支付系统代码,这些代码处理着用户的支付请求流量。如果你在某个电商网站做了一次支付,那么这个支付请求就会顺着光纤发送到我们机房的生产环境集群中处理。

6bf98db6312cb05b52fcf4208e968a31

一般来说,我们布署在生产环境的服务器集群每秒钟大概会处理上千次的用户请求,而这个过程都是在眨眼之间发生的。(在双十一的时候,这个的流量就更离谱了。)

所以,很多同事把我们的服务器集群比作在高空飞行的飞机。这是一个非常贴切的比喻。某种意义上看,我们的服务器集群的确就是一台台高速运转的机器。

一台机器想要长期运转,当然少不了维护。在软件工程里,维护就是给支付系统添加一些新的代码,此时我们一般会在生产环境做各种各样的变更。比如,新功能的发布,历史问题的修复,模块功能的打开和关闭,流量的切换等等——这也不难理解,高速运转的机器也需要定期保养和更换零件。

只是,难点在于,用户的支付请求并不会因为你的变更而停止——换言之,我们所有的变更,都是在这架高速飞行的“飞机”上完成的——整个变更过程中飞机一直都在飞行——这有点像红牛特技飞行表演队在飞机上完成的各种辗转腾挪,队员们的操作稍有不慎便会机毁人亡。

4a7742fe25f0a08ce87858a00d9e92b4

是不是感觉很疯狂?

疯狂就对了!

要知道动中取静的艺高人胆大可是某些技术人员的极致追求,他们总是喜欢为自己参与过“空中换引擎”的项目而自豪。

而与艺高人胆大为伴的自然是线上故障。我们常说“没有变更就没有伤害(故障)”,因为故障往往都由于变更导致的。在我的职业生涯里,我就经历过我们的整个支付服务不可用的故障,而且不止一次。

故障发生的时候,现场的每个人都很紧张。在那一刻,所有之前的应急策略和应急演练都被证明是无效的。眼看着支付成功率的曲线犹如坠机般一路下跌,故障群里各路老板的各种消息频繁弹出,工位上方的空气早已经凝固。

众人一言不发,一直到故障解决。

然而,故障解决并不是事情的结束。之后还有抽丝剥茧的故障复盘(复盘思维,工程师思维之一,后续会单独)和扯皮不断的故障定责,这些事情光是想想就让人头大。

至于最后背了故障的同事和团队——用大家经常挂在嘴边的话来说,就是“这一年白干了”。

没人愿意白干一年或者一年白干,所以大家对生产环境的操作非常谨慎,以至于有些人都患上了线上变更pdst,一到变更的时候就噤若寒蝉,口干舌燥、坐立不安,求神拜佛之事更是不在话下。

当然,在和风险对抗的过程中,我们也总结出了很多惯例操作来保护自己。我们像消防队员一样疯狂地训练自己,试图把这种惯例变成一种近乎本能的条件反射,我们把自己变成机器,试图用机器打败机器。这个我会在后续的文章中说到。

现在,让我们回到一开始的那个故事里:

当时和我一起做变更的dba是一个例外,我确认他没有任何线上变更pdst。

当时的情况是这样的。因为是主数据库做物理切换,按照我们事先确定的操作步骤(为了便于你的理解,这里我做了简化),我只要把应用的流量切到临时容灾库(fo库),再由dba完成主数据库的物理切换,最后再由我把流量切回新的主数据库就可以了。

904616d747da47721772abac123d10a0

这个过程看上去并不不复杂,都是一些常规操作,但事实上我们的数据库有100个物理分片:主数据库有100个分片,相应的临时容灾库也有100个分片(这是为了应对生产环境的超大支付流量而设计的,学名叫分库分表)。

ebb851dab307fe134bf27142a467ce4c

为了把切换对用户的影响降到最低,我和dba约定,在我把流量切换到fo库之后,等十分钟,等新流量完全走到fo库之后,再对主库禁读写,而且必须按照分片一片一片的禁读写。

然而,当我把流量切到fo库后没多久,我们的监控系统就跳出现大量且持续的报错,就连我的手机也开始因收到持续不断的报警短信而疯狂震动——这些报错,我看都是数据库链接池失败相关的,用脚想想就知道和我们切库有关系。

而且,当时整个生产环境就我们两在做变更。

大量的生产报错惊动了我的老板,他在团队的应急群里问我是什么情况,平时沉寂的应急群也热闹了起来,很多大佬都出来询问情况,其中的吃瓜群众自然也不在少数,主持大局的应急值班长条件反射般地要求我们回滚刚才的操作,避免对用户造成更大的影响。

回滚?现在问题都没搞清楚,从哪里开始回滚?

我只得问坐在我身边的dba,问他刚才做了什么神仙操作。

一开始dba支支吾吾,语焉不详。

但是留给我们的时间不多了。

反复追问之下,他终于才坦白,他说他并没有按照我们的约定操作:在我把流量切换到fo库之后,他没有等待十分钟,而是一次性就把主数据库的100个分片禁止掉了。

这就意味着,在他操作的瞬间,主数据库上的流量就被禁止了,而新流量还没有到fo库——反映在业务上,就是用户们在那时的支付请求在瞬间全部失败了。

换言之,这个毛糙的dba做了一个暴力的俄式切换,让我们的本该平滑着陆的飞机来了个颠簸巨大的硬着陆。

回到应急群这边,当时我很清楚这种切换操作是不可回滚的,就算回滚也没有意义了,毕竟影响已经造成了——瞬间支付成功率跌零。

好的一面是,后续新的用户流量已经被切到了fo库,所以dba在主库的俄式操作带来的影响会随着时间的推移而逐渐消失。

我在应急群中说明了情况,说这是基本操作,造成的影响是预期中的,让大家不要惊慌。

随后没多久,生产环境的报错果然消失了,在引起更多的不必要的关注之前,一场风波就这样结束了。

事后我很生气,转头问不按套路出牌的dba:

“线上这么大的流量,你不知道操作要灰度的吗?找死!?”

dba和我同年入职,也是年轻气盛,他反问道:

“你给我解释一下,什么是他妈的灰度?”

(他不是不知道灰度,他的意思是爷在生产环境操作从来不带灰度的。)

到这里,这个故事就结束了。

对于这个故事,我承认有一部分是我戏说的,但是戏说不是胡说,戏说更不是空穴来风。

这件事的确是我的亲身经历。

事后我反思了一下,如果当时dba按照灰度的方式去操作,一片一片的禁写分片,也不至于搞出很大的动静。

遗憾的是,我们的dba似乎并不具备灰度意识,后来我们又合作了很多次,我发现他在俄式切换上倒是颇有造诣——这未尝不是一种迷人的变更风格。

但是,作为一名工程师,在变得艺高人胆大、横扫秋名山之前,我强烈建议你先培养好自己的灰度意识,否则机毁人亡、一年白干只是一个时间问题。

下面进入正题,让我们了解一下工程师思维第一种思维工具——灰度思维吧。

什么是灰度思维

这个世界之所以能够正常运行,很大的一部分原因就在于我们的物理定律和社会规范都是确定性的。

在确定性的世界里,太阳从东方升起西方落下,绿灯表示通行红灯表示静止,大家的行动和行动造成的结果都是可预期的。

另一方面,这个世界之所以有趣,除了确定性的部分之外,不确定的那一部分同样扮演了重要的角色。

比如,彩票在开奖之前,从概率上看我永远都有机会一夜暴富;又比如盲盒再打开之前,我永远都不知道里面装的是什么东西。再比如,我无法决定我的性别以及所在的国家——这是出生的不确定性。

带来不确定性的事件有很多种类。比如,彩票这种随机事件,人这种天生具有不确定性的动物产生的不确定的行为,或者,此前从来没有经历过的未知情况带来的不可预期的结果。

行动和结果不可预期,有时候带给我们的是惊喜,在生活中我们的确需要这样的惊喜不是吗?但在另外一些时候,不可预期的结果就不那么让人愉快了——它除了不会带来惊喜之外,轻则会带来惊吓,重则可能会让我们的财产甚至生命安全遭到损失。

如此,在面对不可预期的结果的时候,我们在行动时就得格外谨慎,尤其是当我们要做出非此即彼的关键选择时更是如此。比如,人生在紧要处的几次关键选择,就应该如此。而宏观来看,整个人类的历史更是一部和风险对抗的斗争史。

我把这种结果不可预期的问题称为“从已知出发走向未知”的问题,处理这类问题时,“灰度思维”就可以发挥作用。

6a159a4c8232cbcb98329277fe9ee31b

简单来说,灰度思维要求我们遇事不要过早下结论,应该先以最小的成本去试探一下,在获得足够多的反馈和信息、建立足够的自信之后,再决定是否迈出更大的步子或者调转方向。

可以看到,灰度不是0到1的非黑即白——不是前面dba的一刀切,而是是0.1到1.0的逐渐递增——灰度,是一个渐进式的过程。

回到故事中的dba切换的例子里,对于一次性把100个分片禁读写这件事情,虽然我们在操作前也分析了这样“一刀切”会带来怎样的影响,但是我们不能打包票说实际切换时,这一刀切下去之后剧情一定会按照我们的分析展开,因为这个世界是复杂的,我们可能会有分析上的疏漏,我们掌握的知识可能是老旧的,我们用我们知道的部分去分析我们并不了解的事情,往往就会带来不确定性——我们主观以为的和客观世界实际发生的情况出现了不一致。在这种不确定的情况下,如果贸然一刀切,说不定可能会引起更大的故障。

所以,对于dba来说,面对这种不确定性,最好的策略就是灰度操作——先切换一个分片观察一下情况。如果切换后的结果符合预期,再继续下一步的操作;如果不符合预期,此时影响和成本都是可接受的。我们只需要回滚刚才的操作,更新我们之前抱持的错误认知,用新的认知重新进行分析,重新制定计划,重新实施计划。

可以看到,这是一个循环往复的迭代过程(迭代思维后续会有单独的文章)。

这样的思考方式,就是“灰度思维”,而用“灰度思维”思考之后去行事,就是“灰度操作”。

作为工程实践当中的一种重要思维工具,在背后支持灰度思维的底层逻辑,是科学实践中的怀疑精神。

怀疑精神要求我们对我们现有的经验都保持持怀疑态度,对我们利用这些经验在脑海里的推演持怀疑态度,因为这些推演并不代表实际情况,只有实际操作过,看到了客观世界的实际结果,我们才能做最后的判断。

那么,具体到实操层面,我们应该如何使用“灰度思维”呢?

首先,我们要判断问题的性质。

如果这个问题对于我们来说是已经解决的问题,那你多半已经轻车熟路了。除非有新的因素引入(比如,后来切库我们换了一个新的dba同学,那么我可能就会对他进行一个灰度测试,先让他做一个简单的变更),否则一般不需要使用“灰度思维”。

如果这个问题对于我们来说之前完全没有做过,属于从已知走向未知的问题,而失败的成本对我们来说又无法接受,那么这样的问题就非常适合使用“灰度思维”。

其次,确认当前问题是否可以拆解为规模更小的等价问题。

只有把问题拆解成更小的问题,我们才能有效降低验证成本。同时,只有确保这些小问题是原始问题的等价问题,我们才可能从对小问题的验证中获得对原始问题一样有价值的信息。

1c01c61159819b1abdc749e6a5a078ac

还是dba切库这个例子,一刀切100个分片和切1个分片,其实就是一个等价问题,因为二者带来的结果从质上看是一样的,只是在量级上有差异。而切1片就算真的出了问题,其所造成的影响只占切100片造成的影响的1%,基本可以忽略不计。

发现了问题,还没造成巨大的影响,这就是灰度操作的价值。

当然,并不是所有的问题都可以从规模上进行拆解,此时就需要对原始问题做建模了。比如,飞行器设计的过程,一般都是从数学模型到缩比模型再到全尺寸模型一路走过来的,其实这也是一种灰度。

还有一些复杂性问题,由于他本身只有在规模效应下才会出现,所以这种问题本身就是无法拆解的,也就无法使用灰度思维了。当然这种问题已经超出本文所讨论的范畴和作者的能力,这里就不再展开了。

最后,在前面的功课都做完之后,灰度思维要求我们付诸实践。

在这一步,我们要设计好试验步骤并对试验结果做好假设。

比如,在dba切换的例子里,试验步骤就是我们当时拟定好的操作计划。

当灰度试验开始,一定要按照计划步骤操作。如果试验通过,那么继续增大试验规模。如果试验失败,则要有退出机制,换言之,要在一开始就为我们的灰度试验想好退路。

比如,在dba切库的例子里,我们的退路就是把上一步的操作回滚掉,让系统回到之前的状态。

当然,回滚之后事情并没有结束,我们还要对操作结果进行复盘(复盘思维,会有单独的章节介绍)研究,形成(关于现实世界的)新的知识,重新调整方案,依照新方案开始新的灰度,直到达到我们的既定目标。

总之,只要是从已知世界走向未知世界的情况,我们都可以用灰度思维来试探和尝试。

为了更好的理解“灰度思维”,不妨让我们看几个例子。

工作上的例子

新功能模块的灰度切流

灰度切流是每个研发同学在职业生涯中都会遇到的情况,这样的例子不胜枚举,我甚至可以不重样地说上一整天。

比如,我们要发布一个支付安全性检测的模块,这个模块会拦截看上去有安全风险的用户支付请求。

在研发测试阶段,虽然我们已经对这个模块做了反复的测试,但在模块上线之后,本着控制风险的原则,我们是不会让流量直接进入这个模块的。(还记得前文中的怀疑精神吗?)

正确的方法是,我们会通过白名单逐步给这个模块导入流量,确保这个模块的功能符合预期,确人这个模块的性能禁得住大流量的冲击。

之后,我们才会全量开放这个新模块。

蓝绿发布

在代码发布的时候,并不是所有的改动都可以像前文描述的功能模块一样,有独立的开关控制流量进行灰度。

但是,这并不能阻挡工程师们想要灰度的决心——他们甚至把灰度做到了机房级别,在发布时对机房的流量进行灰度控制,也就是业界所说的蓝绿发布。

c67d5d3cc52626d0f4b8955f6b4e09b2

具体来说,蓝绿发布要求至少得有两个发布分组(或者两个机房),其中一个是蓝机房,另外一个是绿机房。

发布新代码之前,我们把所有的用户流量都切到蓝机房,把绿机房的流量清空,然后在绿机房发布新代码。

之后,我们再以灰度切流的方式把流量从蓝机房逐渐切到绿机房,相当于对新代码进行了灰度验证。

如果一切顺利,我们会用同样的方式发布蓝机房。而如果在灰度中发现问题,我们可以立即回切流量,非常安全便捷。

精益创业

如果你了解精益创业,那么你一定也知道精益创业的思想背后其实也有灰度思维的影子。

精益创业的核心思想是用最小的成本验证你的点子是否可行,这里的可行与否,有两个维度:

一,有没有价值

二,可不可持续

为了尽早完成对以上两点的验证,精益创业的建议是快速搭建mvp(最小可用产品,如下图),然后推向市场,然后再根据市场反馈快速改进,这其实就是一个灰度的过程。

e3c21dbfbd7b084fdbf805b0a2e83b7b

对精益创业有兴趣的朋友可以阅读《精益创业》一书,本文就不再赘述了。

下面,我们再几个在生活中使用灰度思维的例子。

生活中的例子

首笔转账

给别人转账时,为了避免账号输错,一般可以用一个很小的金额做一次测试转账,确定账号正确之后,再发起全额转账。

培养自己的爱好

学习一门兴趣,没必要一开始就重金投入购入大量的装备,而是从入门所需的最基本原料开始。

比如,如果要学习摄影,经过前期的调研后,你会发现器材在前期并不是关键因素,不用一开始就够买价格昂贵的专业相机,此时可以先用手机练习起来(灰度)。直到你对光影、构图和审美有了一定的感觉,觉得自己的能力受到了器材的限制时,再考虑购入相机。这样,即便你玩儿了半天发现自己其实对摄影并不是真的上头,此时放弃的成本也不会太高。

培养孩子的爱好

家长也可以用灰度思维去帮助小孩培养兴趣。此时可以把前期报的各种兴趣班看作是看作一种灰度,家长可以想办法压低灰度的成本(比如通过体验课,甚至在家里自己教)。在确定了最感兴趣的几项兴趣之后,再投入大量成本去深入学习。

发展人际关系

人际交往的过程本来就是一个相互试探的过程,试探就是灰度。

比如,臭名昭著的服从性测试就以灰度的方式展开。实际操作时,实施测试的一方会先给对方提一个不足挂齿的要求,如果对方接受了,那么就给对方提一个更大的要求,如果对方又接受了,再提一个更大的要求,直到逼近对方的底线,甚至在潜移默化中将对方洗脑。

这里一不小心举了一个反面的例子,诸位一定要注意甄别,不要被这种计量给pua了。

生活处处皆可灰度

最后,重要的事情值得反复提起——只要是从已知世界走向未知世界的问题,都可以使用灰度思维来处理——在做一件事情时,不妨让我们问问自己,这个事情之前是不是没做过?对结果是不是拿不太准?如果是是的话,这个时候就可以灰度起来了——总之,生活处处皆可灰度,我们的人生更是亦然。

1813ded95109d1c8b8e1544da29d14ea

事实上,需要坦白的是,之所以把本文作为本系列的第一篇文章,其实也是我对灰度思维一次应用:

其一,从读者的角度出发,帮助你快速了解这个系列的尿性,以决定是否继续追更。

其二,从作者的角度来说,我想通过这篇文章对市场进行灰度测试,以决定是否有必要把这个系列写完。

当然,既然你已经读到了这里,我衷心希望你在读过本文后,能够对“灰度思维”这个思维工具有所了解,最好能有所掌握和应用。

这样,当下次再遇到问题的时候,你就能够像一个工程师那样,大胆假设,小心求证,最终完成从已知世界到未知世界的飞跃。

以上,就是我所知道的“灰度思维”的全部内容,希望对你有用。

(本章完,版权归作者王晓辰所有,若要转载,请标明出处)

作者简介

王晓辰,软件研发工程师,8年+金融科技从业者,文字价值和文字理想的信仰者和践行者,公众号“架构师的白日梦”的作者。

他坚信用心写就的文字具有无穷的能量,可以穿越时空的阻隔,向读者传达最纯粹的经历、最质朴体悟以及最深邃的思索,最终完成思想的启迪和灵魂的交流。

架构创造未来,文字打败时间!

发表评论

邮箱地址不会被公开。