背景
项目向微服务转变过程中(还未上K8S,为主机版本),有一天早上我愉快的研究这K8S,突然线上产生了严重的告警,mongodb的CPU,内存激增,并且微服务部署机器内存已经爆满;从而导致平台崩掉。紧急情况下,部门开始对线上的机器进行逐一排查,最终发现是某个服务某个接口性能存在问题,耗时2小时;
从结果来看,我们急需一些手段进行线上问题的跟踪排查;对于微服务来说存在以下几个问题:
- 未对微服务的内存,CPU的使用进行限制;
- 用户是通过前端网关进行接口访问,没有手段快速得知是后端哪个服务,哪个接口产生的问题;
对于第一个问题,简单的处理方式也是演进方向就是直接上K8S进行限制;第二个问题,我们思考下,如果我通过各种手段已经知道了是哪个微服务,哪个接口=>如果想看日志的话,我该去这个服务的哪个实例上看日志=>如果我们也有日志中心汇总了=>那么我们因为怎么找到这一次调用对应的日志(日志都是时间顺序);
思路
云原生中有一个概念叫做服务可观测性,可观测性分为:metric,trace,log;
对于以上问题,可以通过tracing结合log进行快速定位;
- 在前端API调用时生成一条tracing,向下调用时,关键路径都传入该链路信息,将traceID写入到http响应头中,这样一次调用报错,可以通过前端http响应头中的TraceID到链路追踪系统中查询到该链路;快速定位服务以及接口。
- 在微服务关键日志打印可采取以下两种策略:
-
- 关键信息少许重要日志可直接打印到链路追踪中;
- 程序日志打印时都携带tracingId作为索引,最终吐到ELK的日志系统中;
日志方面比较简单,接下来重点介绍下什么是trace;
什么是Trace
Trace的规范叫:OpenTracing;
早在 2005 年,Google 就在内部部署了一套分布式追踪系统 Dapper,并发表了一篇论文《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》,阐述了该分布式追踪系统的设计和实现,可以视为分布式追踪领域的鼻祖。
当这个论文发布后,开启了各派的华山论剑,比较有名的比如Twitter的zipkin,Uber的jaeger,大众点评的CAT,以及吴晟大佬的Skywalking;
在选型过程中,需要对自身项目的技术栈,后续的演进方向,性能等综合方面考虑进行。而我想法就比较简单的,跟踪CNCF大哥走,选择了jaeger。当然jaeger的性能也不差,毕竟CNCF毕业推荐组件。
话说回来,OpenTracing作为一个规范,有必要了解它是啥?这里只介绍关键最应该理解的部分:
Trace:一条跟踪调用链,每一个跨度叫做Span, Span的调用数据结构一样,有祖宗,有爷爷,有父亲,有儿子等等,每个阶段(Span)包含如下状态:
- Operation Names: 操作名称,在创建时需要传参;
- 起始时间(组件自动生成,跟当前程序时区相关)
- 结束时间(同上)
- Tags/Attribute: 一组 KV 值,作为阶段的标签(Span Tags)
- Log: 阶段日志
- SpanContext: 阶段上下文,其中包含 Trace ID 和 Span ID
- 引用关系(References)
查询如下:
每一条span点开,可以看到状态信息:
如果有阶段服务发生问题,那么前端会打红色感叹号。
总结
在云原生中,有丰富的组件能够帮助观测服务性能指标,当然在各派华山论剑过程中,CNCF站了出来,发布了未来可观测性重磅炸弹--->openTelemetry,小唐的项目中就采用opentelemetry+jaeger进行分布式链路追踪部署。