上篇回顾
地图永远不准、告警没人信、全链路不可控——四年,三堵墙,把一个银行运维工程师逼到了出走的边缘,也让他决定跟着系统一起上云。
在上家城商行的四年里,我有一件没做完的事——全链路。
做了10来条,就做不下去了。我知道那条链路有多重要,也知道没有它意味着什么:出了事,20多人拉群,每个系统的负责人说"我这边正常"。最后靠老大裁决,不靠证据。
离开后,我把五年里每一条死路重新摆出来看,看它们各自死在哪里。然后我明白了一件根本的事,老路是走不通了,在信创、云化、AI化的今天,运维必须趟出一条全新的路子。于是我换了工作,加入一家领先的可观测性公司做售后工程师,依然服务于我熟悉的客户,城商行。
接手第一个项目的时候,客户正处在架构切换最关键的节点上:新核心上云,信创改造同步推进。这意味着传统的监控手段在新架构面前,不是变难了,是直接失效了。物理引流点没了,服务路径随时在变,一笔交易穿过十几个系统,近百个微服务,出了事,没有人知道从哪里开始查。
他们在最不该“失明”的时刻,面临“失明”的风险。
出发前我在笔记本上写下三个问题:试过哪些路?在哪里卡住的?最怕的是什么?
不是"需要什么功能",是"卡在哪里",因为我做过那个人。
一、他试过所有的路
客户这边负责应用运维的叫老陈。见面第一句话,他就把底牌翻出来了。
老陈:"APM(应用性能监控)我们做过,探针跟ESB(企业服务总线)的老版本中间件冲突,直接崩了。BPM(业务性能监控)也做过,私有云东西向流量走虚拟网络,镜像不到。日志方案就更不用说了,格式不统一,链路不全,告警不准,关键时刻查起来经常白屏。"
他说这些的时候,语气不是抱怨,是陈述。像一个做过多次手术的人在跟新来的医生交代既往病史。
老陈:"你们这个,有什么不一样?"
我没有立刻回答。我问了他一个问题:
小李:"ESB那里,进出两端的交易ID能对上吗?"
他停了一下,看了我一眼。
老陈:"对不上。进去一个ID,出来完全变了。链路到那里就断了。每次都断在那里。"
这个问题我没有想太久就问出来了,因为那堵墙我也撞过。
在上一家银行,全链路做到10来条就做不下去了,ESB是主要原因之一,没有统一的ID,链路在那里永远是断的。
**老陈,**见我没接着讲产品,问:"你之前做过银行运维?"
小李:"做过,四年。"
他没说话,但眼神变了一点。
二、两周没查出的问题
我问老陈:最近有没有查了很久查不出来的问题?
他说了一件事。一个月前,手机银行转账偶发超时,查了两周,应用日志、数据库慢查询、网络设备问了一圈,所有人说自己这边正常。后来问题自己消失了,到现在不知道是什么原因。
这种最难受,不知道它什么时候还会来。
我把那个时间段记下来,当天晚上一个人在机房把POC环境中的可观测性平台装好。
第二天早上,老陈过来找我,我指了指屏幕。
屏幕上是一笔手机银行转账的完整链路。线上渠道服务平台在中间,像个调度中心一样反复出现——存款系统 → 关注名单管理系统 → 服务集成系统 → 电子渠道实时交易监测系统 → 存款系统 → 统一支付平台 → 线下渠道服务平台 → 服务集成系统 → 交易监控系统 → 存款系统 → 消息平台。
一笔转账,从线上渠道服务平台进出了10多次,串了9个系统。 每一跳旁边标着响应时间。
图1:手机银行转账全链路追踪
老陈的第一反应,是认出了这些名字。关注名单、统一支付、交易监测,这是他们行的系统,不是教科书上的示意图。
**老陈,**盯着看了一会儿,然后问_"等一下,这条链路中间过了服务集成系统,渠道平台每次出去再回来,TraceID肯定断了。我们自己试过,APM到第3跳就散了。你是怎么把10几段串成一条的?"_
小李:"内核层自动关联的。不管应用传不传TraceID,TCP层有序列号,两端的内核都能看到,自动匹配。渠道平台出去调存款系统,存款系统再回来,这一进一出在内核层就是同一对socket,不需要任何系统做任何改造。"
老陈没有立刻说话。
这句话的分量,他比我更清楚。一笔转账穿过9个系统、10几次调用,分属不同团队、不同技术栈、不同插桩标准。他试了多少种方案,链路永远断在中间某一段。不是某个系统不配合,是从架构上就串不起来。而在这里不是问题了。不是绕开了那些系统,是从更底下的一层把两端接上了。
我点开时间分布。大部分正常,但有一小撮响应时间飙到了400多毫秒,集中在渠道平台调存款系统的那几跳上。"这些毛刺,应用日志里看不到。应用只记了一笔转账的总响应时间,分不清是存款系统慢、还是渠道平台自己慢、还是中间网络慢。"
上个月手机银行转账偶发超时的根因:渠道平台到存款系统之间,有一波TCP重传,持续了约40分钟。中间一个网络设备的队列溢出。存款系统本身响应正常,渠道平台本身处理也正常,慢在中间那段网络上。所以每个系统自查都说自己没问题——他们说的是对的,问题不在任何一个系统里。
老陈:"这个数据从哪来的?"
小李:"操作系统内核。不经过应用。"
他把截图拍下来发给了网络组,把手机扣在桌上。
老陈:"你把系统全部打开,我们继续聊。"
他查了两周没查出来的东西,在这里有了答案。其实那个答案一直都在,只是以前从来没有人能同时站在应用层和网络层,把它们对齐到同一笔交易上看。症状在应用层,根因在网络层,而这两层之间的连线,以前是断的。
三、都说没问题
几天后,老陈主动来找我了。
信用卡核心系统准生产环境在做压测,性能上不去。应用团队说代码没问题,数据库说查询正常,容器平台说资源充足。但压测一加量,响应时间就飘,而且不是某个接口慢,是整体都在抖。
老陈:"查了三天,所有指标都正常,但就是压不上去。明天要出压测报告,你能帮我看看吗?"
我打开可观测平台,没有先看应用层,而是从网络指标开始扫。几秒钟之后我停住了。
**TCP 179端口——大量客户端重置。**不是偶发,是持续的、成片的。
179是BGP的端口。这个环境跑的是Rancher,底层网络用的Calico,节点之间靠BGP交换路由。应用团队不知道这个端口的存在,容器团队也未必清楚Calico底层每个节点都在跟其他所有节点建BGP连接。
小李:“这个集群有多少个节点?”
老陈:"准生产刚扩过容,现在大概120个。"
我在纸上算了一下:Full-Mesh BGP,每个节点跟其他所有节点建peer,连接数是 n×(n-1)/2。120个节点,就是7140条BGP连接。每条连接要占一个TCP Socket,要维护keepalive,要交换路由表。这不是应用的流量,是基础设施自己的流量,而且它跟业务跑在同一张网络上。
图2:Full-Mesh BGP vs Route Reflector
节点少的时候没人感觉到,20个节点才190条连接。但120个节点,7000多条BGP连接在后台持续握手、断开、重建,抢占的是Node上的TCP Socket资源和CPU中断。压测一加量,业务流量和BGP流量在同一个内核里争抢,响应时间就开始飘。
小李:"问题不在应用里,也不在数据库里,也不在容器资源里。是Calico的Full-Mesh BGP模式在120个节点的规模下,产生了7000多条基础设施连接,挤占了业务的网络资源。"
老陈:"BGP?我们应用团队从来没碰过这个东西。"
小李:"所以查应用查不到。这个流量在应用层以下,日志里不会出现,APM也采集不到。但内核层能看到——179端口的大量重置,就是节点在不停地断开和重建BGP连接,说明资源已经扛不住了。"
我建议他让容器团队把Calico从Full-Mesh切成Route Reflector模式,不是每个节点都跟所有节点建连接,而是指定几个节点做路由反射器,其他节点只跟反射器通信。连接数从n(n-1)/2降到n,从7000多条降到120条。
老陈把数据发给了容器团队。改完配置之后,压测重跑,响应时间稳了,压测报告按时交了。
查了3天,所有人都在应用层转圈。
不是我聪明。是我能看到的东西不一样。应用日志只能记录应用自己知道的事,而这件事,应用从头到尾都不知道。
四、在对的层上
经过了这几次问题的排查和不断增加的业务全链路拓扑,老陈也开始放下了评判的态度,有一天跟我说了这样一段话。
老陈:"我这几年走的全是应用层的路。日志、APM、BPM,每条路理论上都走得通,实际上每条路都有一个过不去的坎。要改代码人家说没排期,要引流没人敢动网络,靠日志的根本拼不全。
我一直以为全链路的问题是怎么把数据采全。其实不是。应用层每个系统各管各的,中间永远有几段是别人的地盘、别人的ID,你进不去。你们换了一层,从内核看,就绕开了所有这些。内核不分自研还是外购、开源还是闭源,它看到的是所有通信,天然就是全的。"
他停了一下。"所以最大的好处其实不是技术多先进,是不求人。"
我没有立刻接话。但我知道他说的"不求人",不只是字面上的意思。
求人,意味着你手里的数据永远来自别人。出了问题你拿着这份数据去找人,人家说"我这边没问题",你没有办法反驳,因为你的数据本来就是他给的。你只能转述,不能裁决。
我在城商行配了600多条告警规则,最后没有人信。不只是数据不准的技术问题,是一套可疑数据撑起来的判断,别人凭什么信?
老陈真正想要的,是一套没有任何人能说"那个不对"的数据,因为那不是任何系统报上来的,是电子眼直接看到的事实。有了这套数据,他说"问题在这里",才是别人可以信的判断。
我花了四年才隐约明白这件事,他用两周说清楚了——因为他也在那堵墙前站了很多年。
从那一刻起,我意识到自己真正在做的事情是什么。是给银行的所有IT系统架设电子眼。它不靠任何人主动汇报,只是把发生的每一件事如实记录下来。事实就在那里,不经任何人转述,不会因为"我这边正常"而消失。
五、两次不同的根因
项目进入到投产准备阶段,我和老陈把30条核心交易链路全部串通,手机银行转账、跨行支付、贷款审批、信用卡交易、代发工资、对公转账。每一条从App穿到人行接口,经过ESB,经过外购闭源系统,经过私有协议,一段不断。没改一行代码,没找任何一个开发团队配合。两个月不到,全通。
每个场景只看2个指标:响应时延和异常比例。30个业务场景,60条告警规则。
我在的上一家城商行是600多条告警规则,每天10多条有效告警,值班的人看到告警弹出来,第一反应是先确认一下是不是误报。那个确认的动作,在凌晨3点的故障窗口里,可能就是最关键的10分钟。
这里是60条规则,安静。
投产前,非功能压测必须全部通过。某个核心交易模块成了第一个卡点,时延抖动严重,最小0.5秒,最大3.4秒,一周没有定位到问题。
业务开发说代码没问题,老陈让我帮忙看看。
我调出压测时间段的链路数据,从路径分析一路点进去。压测机到网关正常,网关到应用正常,应用到数据库,响应时延1.2秒。问题直接定界到数据库。
老陈把截图发给数据库团队,一周的扯皮在一张图前结束了。
数据库调优之后,同一个模块再做一轮压测。时延又飘了,最大2.5秒。
老陈:"上次是数据库,这次该不会又是?"
小李:“不是。这次卡点不在数据库,而在应用服务本身。”
我点开链路数据,应用收到网关请求后,过了两秒多才开始向下游发起调用。 再点开这个进程在那个时间段的CPU分析,原因写得清清楚楚:工作线程几乎全部耗在异常处理和日志打印上,不是业务逻辑慢,是应用在疯狂抛异常、生成堆栈信息,把自己的线程堵死了。
老陈看了一会儿,说了一句:"这一轮同样的症状,所有人的第一反应一定还是去查数据库。"
图3:两次完全不同的根因
**同一个业务,同一种症状,两次完全不同的根因。**如果没有从链路到进程的下钻能力,第二轮压测会重演上一次的剧本,所有人再盯一周数据库。
六、五十二个小时
两轮压测通过后,进入投产窗口。
投产保障采用现场模式,二十四小时驻场。我用可观测平台对核心业务做定时巡检,不是看大屏等告警,是主动扫异常。按协议类型分别过滤,只看服务端返回异常状态的调用。
一个晚上扫出来10个问题:有插入数据时触发了字段约束导致写入失败的;有重复主键冲突说明并发逻辑有问题的;有Pod启动时去访问一张根本不存在的表的;有健康检查脚本里的查询字段跟数据库对不上随时可能误判触发容器重启的;还有消息队列的消费位点越界的。
其中,6个问题被业务团队确认为真实隐患。 另外4个经排查确认暂无业务影响,但数据异常确实存在。
老陈把每一条都标注了具体的服务名、接口名、异常原因和潜在业务影响,直接发给对应的负责人。没有拉群对“暗号”,没有"先确认一下是不是误报"。
如果没有提前发现,投产当天叠加业务高峰,这些隐患可能引发连锁反应。按以前的方式,应用没有主动报错、日志里没有明显异常,没有任何人会在投产前注意到它们。
投产日从下午开始,52个小时,3000余步投产操作。
大屏上,30条链路安静地排列着,绿色。数字在缓缓跳动。
3天后的下午,投产完成。100多套系统,一次性集中切换,零差错。
尾声
那次项目结束之后,我在回程的飞机上想了一件事。
压测时延抖动,第一轮是数据库慢,第二轮同样的症状,根因变成了应用自己的异常风暴——是老陈拿着链路数据和CPU分析截图,直接告诉开发团队该查什么。投产前一个晚上扫出10个隐患,6个确认为真——是老陈把服务名、接口名、异常原因标清楚,直接发给对应的负责人。
不是别人告诉老陈哪里有问题。是老陈告诉别人该查哪里。
过了小半年,老陈给我讲了一件更有意思的事。投产时系统里的告警规则是60条,30个场景,每个场景看时延和异常两个指标,我们一起定的。
但没过多久,变成了600条。再过一段时间,6000条。
不是老陈加的。是各部门自己跑来要接入,应用团队来了,数据库团队来了,网络组也来了。
后来我听说,老陈成了SRE负责人。
这条路,老陈走通了。
编辑后记
这篇文章写的是一个年轻运维工程师的5年。类似的故事正在很多人身上发生着。
如果你也选择了这条路,也碰到到了那堵高高的墙壁,可以和我们一起探索“破壁”之道。
在原文发送**「链路」**两个字,我们来安排一次交流。
原文链接:mp.weixin.qq.com/s/eHt7