简介:软件工程领域存在一个共识:维护代码所花费的时间要远多于写代码。而整个代码维护过程中,最惊心动魄与扣人心弦的部分,莫过于问题排查(Trouble-shooting)了。特别是那些需要 7x24 小时不间断维护在线业务的一线服务端程序员们,大大小小的问题排查线上救火早已成为家常便饭,一不小心可能就吃成了自助餐 —— 竖着进躺着出,吃不了也兜不住。本文分享作者在服务端问题排查方面的一些经验,包括常见问题、排查流程、排查工具,结合实际项目中发生过的惨痛案例进行现身说法。
Know Your Enemy:知己知彼,百战不殆。
日常遇到的大部分问题,大致可以归到如下几类:
上述分类可能不太完备和严谨,想传达的点是:你也可以积累一个这样的 checklist,当遇到问题百思不得其解时,耐心过一遍,也许很快就能对号入座。
医生:小王你看,这个伤口的形状,像不像一朵漂浮的白云?
病人:...再不给我包扎止血,就要变成火烧云了。
快速止血
问题排查的第一步,一定是先把血止住,及时止损。如何快速止血?常见方式包括:
保留现场
血止住了?那么恭喜你,至少故障影响不会再扩大了。卸下锅,先喘口气再说。下一步,就是要根据线索找出问题元凶了。作为一名排查老手,你需要有尽量保留现场的意识,例如:
定位原因
OK,排查线索也有了,接下来该怎么定位具体原因?这个环节会综合考验你的技术深度、业务熟悉度和实操经验,因为原因往往都千奇百怪,需要 case by case 的追踪与分析。这里给出几个排查方向上的建议:
解决问题
最后,问题根因已经找到,如何完美解决收尾?几个基本原则:
3 排查工具
手里只有锤子,那看什么都像钉子。作为工程师,你需要的是一整套工具箱。
问题排查其实就是一次持续观测应用行为的过程。为了确保不遗漏关键细节,你需要让自己的应用变得更“可观测(Observable)。
提升应用可观测性有三大利器:日志(Logging)、监控(Metrics)、追踪(Tracing)。在我之前所做的项目中,这三块能力分别是由 SLS、Alimonitor / AliMetrics / Tsar、EagleEye 提供的,这里就不再展开描述了。
另外也很推荐 Arthas 这个工具,非常实用和顺手,相信很多同学都已经用过。
只学会了问题排查还远远不够(当然技能必须点满,shit always happen),再熟练也只是治标不治本。如果想从根源上规避问题,必须从系统本身出发:按照性能、稳定性和可维护性三个方向,持续优化你的系统实现,扼杀问题于摇篮之中,让自己每天都能睡个安稳觉。
老板:既要快,又要稳,还要好。哦,工资的事你别担心,下个月一定能发出来。
系统优化的三个基本方向:性能(Performance)、稳定性(Stability)、可维护性(Maintainability)。三者之间并不是完全独立的,而是存在着复杂的相互作用关系,有时甚至会此消彼长。
最优秀的软件系统,并非要把这三个方向都做到极致,而是会根据自己实际的业务需求和场景合理取舍,在这三者之间达到一个综合最优的动态平衡状态,让各方面都能做到足够好即可。
所以,优化不只是一门科学,也是一门艺术。
问:要跑出最快的圈速,是车手重要,还是赛车重要?
答:全都重要。
没有哪个男人会不喜欢高性能跑车,也没有哪个女人会希望在看李佳琦直播时突然卡顿。
性能,是各行各业工程师们共同追求的终极浪漫。
性能指标
指标(Indicators)是衡量一件事物好坏的科学量化手段。对于性能而言,一般会使用如下指标评估:
此外,同一个系统的吞吐率与响应时间,一般还会存在如下关联关系:吞吐率小于某个临界值时,响应时间几乎不变;一旦超出这个临界值,系统将进入超载状态(overloaded),响应时间开始线性增长。对于一个有稳定性要求的系统,需要在做性能压测和容量规划时充分考虑这个临界值的大小。
注:其实按更严谨的说法,性能就是单指一个系统有多“快”;上述部分指标并不纯粹只代表系统快慢,但也都与快慢息息相关。
性能分析
古人有句老话,If you can't measure it, you can't improve It.
要优化一个系统的性能(例如Web请求响应时间),你必须首先准确地测量和分析出,当前系统的性能究竟差在哪:是请求解析不够快,还是查询 DB 太慢?如果是后者,那又是扫描数据条目阶段太慢,还是返回结果集太慢?或者会不会只是应用与 DB 之间的网络延迟太大?
任何复杂请求的处理过程,最终都可以拆解出一系列并行/串行的原子操作。如果只是逮住哪个就去优化哪个,显然效率不会太高(除非你运气爆棚)。更合理的做法,应该是坚持 2/8 原则:优先分析和优化系统瓶颈,即当前对系统性能影响最大的原子操作;他们很可能就是 ROI 最高的优化点。
具体该如何去量化分析性能?这里列出了一些工具参考:
其中很多工具也是问题排查时常用的诊断工具;毕竟,无论是性能分析还是诊断分析,目的都是去理解一个系统和他所处的环境,所需要做的事情都是相似的。
优化原则
你应该做的:上面已经提了很多,这里再补充一点:性能优化与做功能需求一样,都是为业务服务的,因此优化时千万不要忙着自嗨,一定要结合目标需求和应用场景 —— 也许这块你想做的优化,压根线上就碰不到;也许那块很难做的优化,可以根据流量特征做非通用的定制优化。
你不应该做的:即老生常谈的提前优化(Premature-optimization)与过度优化(Over-optimization) —— 通常而言(并不绝对),性能优化都不是免费的午餐,优化做的越多,往往可维护性也会越差。
优化手段
常用的性能优化手段有哪些?我这里总结了 8 个套路(最后 1 个是小霸王多合一汇总套路)。
1)简化
有些事,你可以选择不做。
2)并行
有些事,你可以找人一起做。
方式:单机并行(多线程)、多机并行(分布式)。
优点:充分利用机器资源(多核、集群)。
缺点:同步开销、线程开销、数据倾斜。
3)异步
有些事,你可以放手,不用死等。
方式:消息队列 + 任务线程 + 通知机制。
优点:提升吞吐率、组件解耦、削峰填谷。
缺点:排队延迟(队列积压)。
4)批量
有些事,你可以合起来一起做。
方式:多次单一操作 → 合并为单次批量操作。
案例:TCP Nagel 算法;DB 的批量读写接口。
优点:避免单次操作的固有开销,均摊后总开销更低。
缺点:等待延迟 + 聚合延迟。
5)时间空间互换
游戏的本质:要么有闲,要么有钱。
案例:缓存、CDN、索引、只读副本(replication)。
案例:数据压缩(HTTP/2 头部压缩、Bitmap)。
6)数据结构与算法优化
程序 = 数据结构 + 算法
7)池化 & 局部化
共享经济 & 小区超市
池化(Pooling):减少资源创建和销毁开销。
局部化(Localization):避免共享资源竞争开销。
8)更多优化手段
稳住,我们能赢。—— by [0 杀 10 死] 正在等待复活的鲁班七号
维持稳定性是我们程序员每天都要思考和讨论的大事。
什么样的系统才算稳定?我自己写了个小工具,本地跑跑从来没出过问题,算稳定吗?淘宝网站几千人维护,但双十一零点还是经常下单失败,所以它不稳定喽?
稳定是相对的,业务规模越大、场景越复杂,系统越容易出现不稳定,且带来的影响也越严重。
衡量指标
不同业务所提供的服务类型千差万别,如何用一致的指标去衡量系统稳定性?标准做法是定义服务的可用性(Availability):只要对用户而言服务“可用”,那就认为系统当前是稳定的;否则就是不稳定。用这样的方式,采集和汇总后就能得到服务总的可用/不可用比例(服务时长 or 服务次数),以此来监测和量化一个系统的稳定性。
可是,通过什么来定义某个服务当前是否可用呢?这一点确实跟业务相关,但大部分同类业务都可以用类似的方式去定义。例如,对于一般的 Web 网站,我们可以按如下方式去定义服务是否可用:API 请求都返回成功,且页面总加载时间 < 3 秒。
对于阿里云对外提供的云产品而言,服务可用性是一个更加需要格外重视并持续提升的指标:阿里云上的很多用户会同时使用多款云产品,其中任何一款产品出现可用性问题,都会直接被用户的用户感知和放大。所以,越是底层的基础设施,可用性要求就越高。关于可用性的更多细节指标和概念(SLI / SLO / SLA),可进一步参考云智能 SLA 了解。
可用性测量
有了上述可用性指标定义后,接下来该如何去准确测量系统的可用性表现?一般有如下两种方式。
1)探针模拟
从客户端侧,模拟用户的调用行为。
2)服务端采集
从服务端侧,直接分析日志和数据。
对可用性数据要求较高的系统,也可以同时运用上述两种方式,建议结合你的业务场景综合评估选择。
优化原则
你应该做的:关注 RT 的数据分布(如:p50/p99/p999 分位点),而不是平均值(mean) —— 平均值并没有太大意义,更应该去关注你那 1%、0.1% 用户的准确感受。
你不应该做的:不要尝试承诺和优化可用性到 100% —— 一方面是无法实现,存在太多客观不可控因素;另一方面也没有意义,客户几乎关注不到 0.001% 的可用性差别。
优化手段
常用的稳定性优化手段有哪些?这里也总结了 8 个套路:
1)避免单点
父母:一个人在外漂了这么多年,也该找个人稳定下来了。
如何避免?
只堆量不够,还需要具备故障转移能力(Failover)。
2)流控/限流
计划生育、上学调剂、车牌限号、景区限行... 人生处处被流控。
3)熔断
上午买的股票熔断,晚上家里保险丝熔断... 淡定,及时止损而已。
4)降级
没时间做饭了,今天就吃外卖吧... 对于健康问题,还是得少一点降级。
触发原因:流控、熔断、负载过高。
常见降级方式:
5)超时/重试
钉钉不回怎么办?每 10 分钟 ping 一次,超过 1 小时打电话。
超时:避免调用端陷入永久阻塞。
重试:确保可重试操作的幂等性。
6)资源设限
双 11 如何避免女友败家?提前把自己信用卡额度调低。
7)资源隔离
双 12 女友还是要败家?得嘞刷你自个的卡吧,别动我的。
8 )安全生产
女友哭着说再让我最后剁一次手吧?安全第一,宁愿心疼也不要肉疼。
程序动态性:开关、配置、热升级。
审核机制:代码 Review、发布审批。
灰度发布;分批部署;回滚预案。
前人栽树,后人乘凉。
前人挖坑,后人凉凉。
维护的英文是 maintain,也能翻译成:维持、供给。所以软件维护能有多重要?它就是软件系统的呼吸机和食物管道,维持软件生命的必要供给。
系统开发完成上线,不过只是把它“生”下来而已。软件真正能发挥多大价值,看的是交付后持续的价值兑现过程 —— 是不断茁壮成长,为用户发光发热?还是慢慢堕落,逐渐被用户所遗忘?这并不是取决于它当下瞬时是否足够优秀(性能)和靠谱(稳定),而是取决于未来 —— 能否在不断变化的市场环境、客户需求和人为因素中,始终保持足够优秀和靠谱,并且能越来越好。
相比性能和稳定性而言,可维护性所体现的价值往往是最长远、但也最难在短期内可兑现的,因此很多软件项目都选择了在前期牺牲可维护性。这样决策带来的后果,就跟架构设计一样,是几乎无法(或者需要非常高的成本)去弥补和挽回的。太多的软件项目,就是因为越来越不可维护(代码改不动、bug 修不完、feature 加不上),最后只能慢慢沦落为一个谁都不想碰的遗留项目。
衡量指标
相比性能和稳定性而言,可维护性确实不太好量化(艺术成分 > 科学成分)。这里我选取了几个偏定性分析的指标:
1)复杂度(Complexity):是否复杂度可控?
2)可扩展性(Extensibility):是否易于变更?
3)可运维性(Operability):是否方便运维?
重要性
这里给了几个观点,进一步强调可维护性的重要性。
优化原则
你应该做的:遵循 KISS 原则、DRY 原则、各种代码可读性和架构设计原则等。
你不应该做的:引入过多临时性、Hack 代码;功能 Work 就 OK,欠一堆技术债(出来混总是要还的)。
优化手段
常用的可维护性优化手段有哪些?这里我总结了 4 个套路:
1)编码规范
无规矩,不成方圆。
2)代码重构
别灰心,代码还有救。
3)数据驱动
相信数据的力量。
4)技术演进
技术是第一生产力。
Truth lies underneath the skin - 真理永远暗藏在表象底下。
对,就在这句话底下。
欢迎各位技术同路人加入阿里云云原生应用研发平台 EMAS 团队,我们专注于广泛的云原生技术(Backend as a Service、Serverless、DevOps、低代码平台等),致力于为企业、开发者提供一站式的应用研发管理服务,内推直达:pengqun.pq # alibaba-inc.com,有信必回。
原文链接:https://developer.aliyun.com/article/767550?
版权声明:本文中所有内容均属于阿里云开发者社区所有,任何媒体、网站或个人未经阿里云开发者社区协议授权不得转载、链接、转贴或以其他方式复制发布/发表。申请授权请邮件[email protected],已获得阿里云开发者社区协议授权的媒体、网站,在转载使用时必须注明"稿件来源:阿里云开发者社区,原文作者姓名",违者本社区将依法追究责任。 如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至:[email protected] 进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。