微服务之调用链路跟踪-1

9 阅读7分钟

能够快速诊断问题是微服务不可或缺的特性, Troubleshooting 是每个开发运维人员的日常工作, 经常会耗费大量时间和精力。服务器端尤其如此,有些偶发性的问题, 本地难以重现, 只有产线上的日志可供分析,这时候, 每个开发人员都变成了福尔摩斯,在蛛丝马迹之中寻找有价值的线索, 演绎推理,大胆假设, 小心求证。

以前一个单体服务,服务器数量有限,在有限的服务器上检查日志,分析问题就行了,虽然单件服务的逻辑复杂,毕竟波及的范围有限, 搞得多了,也就熟能生巧。但是微服务就不同了,消息在多台服务器之间流转,定位错误更加困难, 开发人员往往也只是负责一两个微服务, 在众多不熟悉的服务之间查找错误,定位发生故障的服务和节点,并分析原因,制定解决方案,不能再靠以前的三板斧: 查日志,翻代码,做验证。

假设我们有微服务A, B, C, D, E 服务于用户的一个业务请求:

服务越多, 相互调用关系越复杂, 仿佛一团乱麻, 想要理清楚, 可不是一件容易的事。

我们要对消息在微服务之间的跳转必须有个宏观的把握, 我总结为三个关键,五个要点,三种标记, 基于这个基本信息, 我们就可以构建起一直调用链关系图, 并借助于 ElasticSearch 和 Hadoop 等数据分析工具高效地进行问题分析,诊断和排错。

三个关键

其实我们只要掌握了三个最关键的信息, 我们也就大体搞定了微服务的诊断

关键路径 Key path

  • 业务流程中并会经过哪些节点,哪些服务参与了这个流程
  • 节点之间的网络拓扑,跳数,节点的地址,微服务的端点,ip, port

关键度量 Key metrics

  • API 的调用次数,花费时间, 响应码, 重点关注 400,404,401, 403, 404, 500,502, 503, 504 以及超时错误 每秒查询数QPS(Query Per Second) 每秒调用数CPS(Call Per Second), Voip/Telephony 应用中也作每秒呼叫次数

  • 网络传输中的关键指标延迟,丢包,抖动,带宽等指标

  • 多媒体应用中的编码,码率,帧率,分辨率,加密与否

  • 数据库应用中的查询/更新次数,查询/更新时间,TPS(Transaction Per Second)

关键事件 Key event

一个业务流程中调用哪些服务API,发送或接收了哪些消息, 最为关键的可以衡量成功失败与否的事件是什么

  • eventName:事件名称 presence, createRoom, joinRoom, closeRoom, etc.
  • eventTime: 事件发生的时间

在整个流程中,哪些事件是不可或缺的,缺失或者发生错误不可接受,我们要在流程分析中设置关键检查点

比如远程在线上课,进入课堂,退出课堂,发起或关闭通话,开启或关闭视频,媒体通道搭建成功与否,这些都是关键事件,在故障分析时可以设置相应的检查点

五个要点

著名的保安三大问题: 你是谁, 你从哪里来, 你到哪里去.

微服务在分布式系统中的消息往来,事件传输,我们需要关心5个要点

    1. 时间 timestamp
    1. 从哪里来 from
    1. 到哪里去 to
    1. 消息内容 messageContent: type, name, etc.
    1. 消息标识 messageID: 下面所说的 TrackingID, SpanID 以及业务实体的ID

三种标记

1)TrackingID

我们需要一个应用流程上的若干条消息串起来, 这里通常需要一个跟踪标识, 可以顺藤摸瓜, 找到来龙去脉, 通常我们叫它 TrackingId,它可以是UUID, 或者其它全局唯一的字串

2) SpanID

再有就是SpanID,或翻译成跨度ID, 它可以用来表示层级和顺序关系的标识

MessageSpanID
A-->B-1.2
B-->C2.3
B-->D2.4
D-->E4.1

3) Business Entity ID 业务实体标识

在具体业务领域,还会加上业务实体特定的标识,通过它来关联 TrackingID, 比如:

  1. 业务流水号,比如订单号,会议号等
  2. 服务的标识信息:比如数据中心名,地区或集群名称,服务器地址,进程号等
  3. 用户的标识信息:比如组织或租户号, 用户号,学号等等

在写日志中需要注意不要记录用户的隐私信息,比如姓名,密码,电子邮件,手机号码,身份证号等, 用一个可以标识用户身份的 ID 就好了,这个ID与具体用户关联,需要查询用户个人隐私信息时需要用户授权和安全审查

综上所述,有了调用链和事件流,关键路径,关键度量,关键事件了如指掌.

下面我们就介绍一下业界常用的几种具体做法

Dapper

Google 有一篇论文详细阐述了它的做法,它提到了链路跟踪要满足如下需要 1)性能损耗低 2)对应用透明 3)具有可伸缩性 4)跟踪数据可视化并迅速反馈 5)持续监控

其中有如下术语

  • Span
  • Trace
  • Annotation
    • cs: client sent
    • cr: client received
    • ss: server sent
    • sr: server received

现在的 Sleuth , Zipkin, Pinpoint 大多借鉴了它的思路

ELKK

  1. 应用程序记录下关键的事件信息写到日志文件中

  2. LogStash forwarder 将日志中的事件信息发到 Kafaka 上

  3. Kafaka中的消息由 LogStash shipper 送到 ElasticSearch 中

  4. 基于 ElasticSearch 和 Kibana 建立各种查询和图表进行分析

通过调用 Elastic Search 的 API 我们可以很容易的根据关键的 ID 标识找出相关的日志信息

Sleuth and Zipkim

Spring Cloud 全家桶中提供了 Spring Cloud Sleuth , 它从Dapper,Zipkin和HTrace大量借鉴了Spring Cloud的分布式跟踪解决方案。 对于大多数用户而言,Sleuth应该是不可见的,并且您与外部系统的所有交互都应自动进行检测。 您可以简单地在日志中捕获数据,也可以将其发送到远程收集器服务。

Span跨度是工作的基本单位。例如,发送RPC是一个新的Span,就像发送响应到RPC一样。Span 由一个唯一Span 的64位ID和Span所属的Trace 的另一个64位ID标识。Span还具有其他数据,例如 描述,键值 annotation,发起它们的 Span 的ID和进程ID(通常为IP地址)。Span 开始和停止时总会记录其时间信息。创建 Span 后,必须在将来的某个时间点将其停止。一组 Span 形成称为 Trace 的树状结构。

Spring Cloud Sleuth功能:

  • 将跟踪和跨度ID添加到Slf4J MDC,以便您可以在日志聚合器中从给定的跟踪或跨度提取所有日志。

  • 提供对常见的分布式跟踪数据模型的抽象:跟踪,跨度(形成DAG),注释,键值注释。宽松地基于HTrace,但与Zipkin(Dapper)兼容。

  • 从Spring应用程序(Servlet过滤器,Rest模板,调度的动作,消息通道,Zuul过滤器,伪客户端)中检测常见的入口和出口点。

  • 如果spring-cloud-sleuth-zipkin可用,则该应用将通过HTTP生成并收集与Zipkin兼容的跟踪。默认情况下,它将它们发送到本地主机(端口9411)上的Zipkin收集器服务。使用spring.zipkin.baseUrl配置服务的位置。

zipkin 启动很简单

curl -sSL https://zipkin.io/quickstart.sh | bash -s
java -jar zipkin.jar

参考资料