从救火到防火:我在金融企业构建可观测性体系的实战之路

下午15:17的那场故障

下午15:17,正值交易高峰期,支付核心链路P99延迟从80ms飙升至2.3s。

用户投诉如潮水涌入,监控大盘却一片"正常"------因为CPU小于70%,内存小于80%,HTTP 5xx错误率小于0.1%。

这就是没有可观测性的代价:系统在崩溃,而你一无所知。

在金融行业,我们无法承受这种"盲跑"。可观测性,不是可选项,而是生存底线。为什么需要可观测性?本质上就是人类想要掌控系统的健康状况。工程师总是担心系统不可用,为了掌控系统,所以可观测性应运而生。就好比中医的望闻问切,来判定一个人的健康状态一样。只能看到各项指标正常,才能比较放心,晚上才能睡个安稳觉。

可观测性的三大基石

那问题来了,怎么判断系统可观测呢?业界公认的三大基石:日志、调用链、指标。咱们一个一个聊。

日志:最原始但也最真实

日志本来是散落在各个系统之间的,最原始的方式是什么?tail、cat、grep、awk这些老古董。你得一台服务器一台服务器登录进去,手工翻日志。

但这太分散了,根本不利于操作。你想想,线上几十台甚至上百台服务器,出了问题你怎么找?来回切屏幕切到眼花,还容易漏掉关键信息。

所以需要把它们收集到一起。这时候Filebeat、Logstash就派上用场了,它们负责收集、转换、格式化日志,最后写到Elasticsearch的索引里。再开发一个界面来管理这些索引,维护它们的归档、查询等工作------这个界面就是Kibana。

说实话,刚开始用ELK的时候,我也觉得麻烦。又要装Filebeat,又要配Logstash,索引还得规划。但用习惯了之后,你会发现真香。出问题时,在Kibana里输入个关键字,几秒钟就能把相关日志全捞出来,比以前效率高太多了。

金融级挑战:从关键词到规则的跨越

但在金融场景,普通的日志查询很快就遇到瓶颈了。支付失败可能表现为"余额不足""风控拦截""渠道超时""账户冻结""限额超限"等数十种语义,你不可能把所有关键词都记住。

我们的解决方案是:通过结构化日志加业务状态码标准化,将"支付异常"抽象为统一字段。比如所有支付相关的错误,都必须包含errorCode、errorType、bizType这些标准字段,这样规则就可以复用了。

同时,金融系统对日志合规性要求极高。所有涉及资金流转的操作,日志必须保留至少5年,而且要能随时审计。这就要求我们在日志采集的最开始,就做好分类、脱敏、归档的规划,不能事后补救。

调用链:给请求装个GPS

微服务时代,一个请求的生命周期变得特别复杂。从用户点击按钮开始,请求可能经过Nginx、业务网关、微服务前台、微服务中台、各种中间件,最后才返回结果。这一条逻辑线是否正常、性能如何,得有办法追踪啊。

因此从流量入口(东西流量)进入系统大门开始,就需要给它打个标记。这个标记叫TraceId,而且要尽可能早地生成。同时要采集你能想到的各种信息:PC还是手机端、uid、ip、设备号、时间、请求报文等等。

这个TraceId会穿透整个微服务系统。为了更精细化,还需要在每个微服务模块中增加SpanId(南北流量)。每一次请求,我们巴不得从Nginx、业务网关、微服务前台、微服务中台、中间件,到最后的返回信息(成功、失败、http状态码、业务状态码、业务报文),都装上透视眼。

这里也产生了很多工具,比如早期大众点评的Cat,现在字节码增强的Agent工具,最典型的就是SkyWalking了。

有了调用链之后,你在SkyWalking里看报表,跟踪慢接口,一目了然。哪个环节慢了?是数据库查询的问题,还是第三方接口超时?一查便知。

金融级挑战:TraceId的全链路保障

但在金融场景,调用链有个致命问题:TraceId透传在异步线程、消息队列消费、定时任务中极易断裂。

你想想,一笔支付请求进来,可能触发异步风控校验、发送MQ通知、定时对账任务。如果TraceId在某个环节断了,整条链路就追踪不下去了。出了问题,你连完整的调用路径都看不到,怎么排查?

我们的解决方案是改造SkyWalking Agent,强制在MDC(Mapped Diagnostic Context)中注入bizId加traceId。不管是主线程还是异步线程,不管是HTTP调用还是MQ消费,都必须携带这两个标识。这样一来,哪怕是跨了三天的异步对账任务,我们也能追溯回当初的那笔交易。

金融系统还有个特点:资金流必须百分百可追溯。监管部门随时可能要求你提供某笔交易的完整调用链,从用户发起请求,到最终扣款成功,中间经过了哪些系统、哪些节点,每个节点的耗时多少,都要清清楚楚。这不是"最好有",而是"必须有"。

指标:从微观到宏观的跨越

有了日志和调用链,够了吗?

没有!

你可以在Kibana查日志,在SkyWalking看调用链,但这还是太微观了。它们回答不了一些更感性的问题:

系统健康吗?调用慢不慢?有没有异常?哪个系统有异常?什么原因?多长时间能恢复?怎么恢复?

解决了一次又一次线上故障后,你还会进一步提问:下次能提前知道吗?有没有自动巡检功能?能不能先于用户发现,降低影响面?能不能一经发现,很快就能恢复?

为了解决这些问题,就需要规则。怎么制定规则?对了,指标就要上场了。

指标本质上是时间维度的一个原子化的度量。比如说,某台服务器的某一刻,CPU利用率多少、内存占用大不大、网络IO多不多、磁盘空间如何?这就是Google提出的USE方法论------四大度量。

这是最基本的一些指标,每一台服务器都需要安装。当每一台服务器都安装了这些指标采集器后,这些数据会汇总到Prometheus中。Prometheus是一个时间序列的指标存储、查询工具。

拉模式还是推模式?这不是技术问题

Prometheus采用的是拉模式,固定时间比如15秒采集一次。

为什么是拉,而不是推?很多文章没有讲清楚,我告诉你,本质上不是技术的原因,是业务的原因。

第一,推的话你是一个指标一个指标地推,零零散散。

第二,业务上需要一个不间断的时间区间,才能画出图形或者制定规则。

所以拉模式一次性取出若干指标,而且时间间隔能够得到保证。想象一下,你要画一条CPU使用率的曲线,如果数据点时断时续,这图还怎么看?

为了监控,每台服务器都需要安装Exporter(导出器),然后Prometheus统一进行拉取并装进它的TSDB时间序列存储里。

Grafana:让数据会说话

进入Prometheus后,又是个黑盒?怎么办?别急,有Grafana!

很多优秀的工程师都提供了Node-Exporter的Grafana模板,界面很科技、很炫,看上去很牛逼。但在我看来,炫不炫不是重点,功能也并没有增加多少,也仅仅是能够看清某一时刻服务器的状态而已。

Grafana的真正价值在于:它是故障出现后的分析平台,是故障发生时的报警依据。你可以在上面设置各种Dashboard,监控不同维度的指标,一旦数据异常,立马就能发现。

金融级挑战:秒级交易下的监控盲区

但Prometheus默认15秒采集一次,在金融场景下有个大问题:盲区太大。

金融系统是秒级交易,高峰期一秒钟可能有几千笔订单。15秒的采集间隔意味着什么?意味着中间可能有几万笔交易,你完全看不到。如果在这个盲区内出现了短暂的流量尖刺或者性能抖动,等到下一次采集时,问题可能已经过去了,但用户已经受影响了。

我们把核心服务的指标采集频率提升到2秒一次。别小看这个改动,对存储和计算的压力是成倍增加的。但没办法,金融系统容不得盲区。

还有一个更隐蔽的问题:固定阈值告警在金融场景下经常误报。比如你设置"交易量每分钟超过10000就报警",听起来合理吧?但双十一零点、发工资日、节假日,交易量本来就会暴涨,这时候报警就是误报。

我们引入了动态基线告警:系统会自动学习历史数据的波动规律,计算出每个时间段的正常基线。只有当实际值显著偏离基线时,才触发报警。这样一来,市场正常波动不会误报,真正的异常却能及时发现。

重头戏来了:报警!

好了,经过这么多铺垫,终于可以讲到重头戏了------报警!

报警怎么报?想一想,系统由多台服务器组成,由多个中间件组成,有数据库、缓存、文件系统、网关、容器化、分布式调度、服务治理等等。某一个系统出现亚健康或者不可用,就需要报警。

报警分级:红黄蓝三色体系

我们在实践中总结出了一套分级体系:

红色报警:中间件或者虚拟机宕机类,要立即处理。比如数据库挂了、Redis不可用了、核心服务宕机了。这种情况不能等,必须马上响应。这对应的是资金损失风险,影响交易能不能完成。

黄色报警:性能跟不上了,IO流量过大、CPU利用率高、内存上升快,要尽快处理。这种还没到生死存亡的地步,但也不能拖太久。对应的是用户体验受损,交易变慢、响应变慢。

蓝色报警:磁盘涨幅过大,预计3天后就满了,要清理或者加磁盘,要安排后处。这种属于预警,给你时间从容处理。对应的是运维成本上升,提前规划资源。

以上是运维需要关注的硬件、中间件指标。

业务报警:更贴近实际场景

还有业务系统要注意的:接口过慢、数据库慢查询、微服务宕机了,怎么发现这些问题?

往往都散落在日志、调用链、指标里,但需要工程师根据日常工作去抽象。比如:

  • 日志中包含"支付异常"
  • HTTP接口产生500错误
  • HTTP请求超过3秒
  • 数据库慢SQL

抽象出这些规则后,对它们进行统一的报警。

自研报警引擎:为什么要自己造轮子?

在日志、调用链、指标这三类基础设施之外,还需要开发一套报警引擎。

AlertManager也可以用,但不够定制化。比如我们需要:

  • 避免重复处理:同一个问题别反复报
  • 处理报警毛刺:偶尔抖动一下不算故障
  • 报警收敛:同一类问题合并通知
  • 分级通知:红色报警打电话,黄色报警发短信,蓝色报警发邮件
  • 值班轮转:自动分配责任人
  • 升级机制:超时未处理自动升级

报警的开发,绝对不是可有可无的。没有它,你就没办法回答系统是否健康、是否能正常运转,没办法巡检。夸张点说,你睡觉都不踏实。

我们的实践成果:金融级可观测性的效果验证

我服务的公司是一家金融企业,对各项要求都比较高。我们自研了一套报警系统,经过两年多的迭代优化,取得了比较明显的效果。

先看几个关键数据:

指标 优化前 优化后 提升幅度
故障发现时间 15分钟 3分钟 降低80%
报警误报率 35% 低于5% 降低85%
核心链路覆盖率 60% 100% 提升40%
自动恢复率 20% 60% 提升3倍

这些数字背后,是无数个深夜的故障复盘,和对"规则"的极致打磨。

具体来说:

覆盖范围

  • 各类中间件10多项(MySQL、Redis、Kafka、RabbitMQ、Elasticsearch等)
  • 监控虚拟机300多台
  • 每天处理上万条报警规则

核心能力

  • 报警收敛:同一类问题合并通知,避免报警风暴
  • 毛刺过滤:短暂抖动不触发报警,减少误报
  • 分级通知:红色报警打电话,黄色报警发短信,蓝色报警发邮件
  • 值班轮转:自动分配责任人,清晰责任边界
  • 升级机制:超时未处理自动升级到上级

这套系统是我们团队一点一点摸索出来的。踩过很多坑,比如一开始报警太频繁,运维同学的手机一天到晚响个不停,后来加了收敛机制才好转。也试过报警规则设置得太宽松,结果真出问题时没及时发现,导致故障扩大。

写在最后:从经验到能力的跨越

我发现现在讲可观测性这块内容的人不多,要么讲得很零散,要么不够落地。所以我想把我的工作实践,结合金融企业的实际场景,把怎么想的、怎么做的、达到了什么效果,毫无保留地脱敏后分享出来。

可观测性不是买几个工具就能解决的,它需要你对业务的深刻理解,对系统的全面把控,和一次又一次故障中积累的经验。

但更重要的是:把经验沉淀为规则,把规则固化为系统,把系统转化为能力。

这,才是金融级可观测性的真正护城河。

希望这篇文章能帮助大家理清可观测性的大局观,知道在实际工作中方方面面该怎么处理。如果你也在做可观测性相关的工作,欢迎一起交流探讨。

相关推荐
韩立学长2 小时前
基于Springboot建筑物保护可视化系统rk6tni53(程序、源码、数据库、调试部署方案及开发环境)系统界面展示及获取方式置于文档末尾,可供参考。
数据库·spring boot·后端
superman超哥2 小时前
Rust Link-Time Optimization (LTO):跨边界的全局优化艺术
开发语言·后端·rust·lto·link-time·跨边界·优化艺术
superman超哥2 小时前
Rust 编译优化选项配置:释放性能潜力的精细调控
开发语言·后端·rust·rust编译优化·精细调控·编译优化选项
UrbanJazzerati2 小时前
深度解析Salesforce Apex的Governance Limit:SOQL 50,000条记录的事务级限制
后端·面试
To Be Clean Coder3 小时前
【Spring源码】getBean源码实战(一)
java·后端·spring
巴塞罗那的风3 小时前
golang协程泄漏排查实战
开发语言·后端·golang
quant_19863 小时前
BTC 行情预警系统实战教程
开发语言·后端·python·websocket·程序人生·金融
小小王app小程序开发3 小时前
招工招聘小程序开发全解析:全栈架构、核心模块实现与性能优化
性能优化·架构
superman超哥3 小时前
Rust 日志级别与结构化日志:生产级可观测性实践
开发语言·后端·rust·可观测性·rust日志级别·rust结构化日志