Skip to main content

第9章 全链路日志

第8章介绍了服务的注册发现,这里就来谈谈所有微服务都会遇到的一个问题——全链路日志

全链路日志概念

9.1 业务场景:这个请求到底经历了什么

公司某业务线刚迁移到 Spring Cloud。之前只是简单地把日志打印到本地文件,然后使用 ELK(ElasticSearch、Logstash、Kibana)进行日志收集和分析,日志记录比较随意,没有统一规范。

问题案例

有一次碰到某用户总是登录失败的问题,服务调用链路是:

UserAPI → AuthService → UserService

在 UserAPI 中还能根据用户名和线程 ID 找到相关日志。但是要去 AuthService 查找下一个服务的日志时就复杂了:

  • 同一时间点有多个服务器节点
  • 每个节点有多个线程 ID 在活动
  • 无法判断哪个服务器的哪个线程 ID 是处理这次请求的

最终调查到的问题根源是:UserAPI 调用 AuthService 时,有个参数因为含有特殊字符被 Tomcat 自动摒弃了。

需求梳理

项目组商量后,总结了以下需求:

基础记录需求

  1. 记录什么时候调用了缓存、MQ、ES 等中间件,在哪个类的哪个方法中耗时多久
  2. 记录什么时候调用了数据库,执行了什么 SQL 语句,耗时多久
  3. 记录什么时候调用了另一个服务,服务名是什么,方法名是什么,耗时多久

跨服务串联需求

  1. 把同一个请求在全部服务中的所有记录进行串联,实现树状的记录
  2. 设计基于这些基础数据的查询统计功能

9.2 技术选型

OpenTracing协议

9.2.1 日志数据结构支持 OpenTracing

目前已经有一种比较通用的全链路数据格式——OpenTracing,由 Cloud Native Computing Foundation(云原生计算基金会)维护。

OpenTracing 核心概念

概念说明
Trace一个客户端请求经历的整个流程
SpanTrace 中被命名且被计时的连续性执行片段
ReferenceSpan 与 Span 之间的关系

一个 Span 可以包含多个子 Span,例如:

  • Order API 调用 Product Service 的整个过程是一个 Span
  • Product Service 访问数据库也是一个 Span(子 Span)
为什么选择 OpenTracing

必须保证系统的可替代性,尽量不要束缚于一项开源技术上。如果之前引入的全链路日志不好用,以后想换掉也非常方便。

9.2.2 支持 Elasticsearch 作为存储系统

因为流量大导致日志数据量也很大,存储系统必须支持海量数据且保证查询高效。公司运维人员对 Elasticsearch 比较熟悉。

9.2.3 保证日志收集对性能无影响

SkyWalking架构

当服务在记录日志时,需要确保对服务器性能不会产生影响。

例如调研过 Pinpoint,并发数达到一定数量时整体吞吐量少了一半,这是不能接受的。

9.2.4 查询统计功能的丰富程度

基础功能:支持每个请求树状结构的全链路日志

扩展功能:监控报警、指标统计等,减轻二次开发工作量

9.2.5 最小业务代码侵入性

希望日志数据的收集过程对写业务代码的人保持透明:

  • 使用 Java 的探针,通过字节码加强的方式进行埋点
  • 在封装的公共代码中实现埋点

9.2.6 最终选择:SkyWalking

日志树状结构

根据问题剖析及性能测试结果,SkyWalking 比较符合需求:

  • 500 线程压力以下的服务,是否使用 SkyWalking 对吞吐量影响不大(相差不超过 10%)
  • 官方测试报告:500 并发用户,每次请求间隔 10 毫秒,TPS 基本没什么变化
  • 国产开源框架,更贴近实际需求

9.3 注意事项

9.3.1 SkyWalking 的数据收集机制

日志收集过程必须是异步的,与业务流程解耦:

  • 如果同步收集,业务系统和日志系统就是耦合的
  • 不可能让高可用的系统依赖中可用的系统

SkyWalking 的实现

  1. 服务中有一个本地缓存,先存放所有日志数据
  2. 后台线程通过异步的方式将缓存中的日志发送给 SkyWalking 服务端
  3. 日志埋点处无须等待服务端接收数据,不影响系统性能

9.3.2 如果 SkyWalking 服务端宕机了

服务端宕机后,日志缓存中的数据会出现没人消费的情况。

SkyWalking 的处理:设置缓存的大小,如果数据超出缓存大小,Trace 不会保存,不会超出内存。

9.3.3 流量较大时如何控制日志数据量

流量大时,不可能收集每个请求的日志。SkyWalking 通过采样比例控制:

agent.config:
agent.sample_n_per_3_secs: 100 # 每3秒采样100个
注意事项
  1. 启用 forceSampleErrorSegment 后,出错时会收集所有数据
  2. 所有相关联服务的 sampleRate 最好保持一致,否则会出现一个 Trace 串不起来的情况

9.3.4 日志的保存时间

一般保存 3 个月的数据,使用 SkyWalking 直接配置即可:

core:
default:
recordDataTTL: 90 # 保存90天

9.3.5 集群配置:如何确保高可用

SkyWalking 的收集服务(Receiver)和聚合服务(Aggregator)支持集群模式,支持的协调服务包括:

  • Kubernetes
  • ZooKeeper
  • Consul
  • etcd
  • Nacos

9.4 小结

全链路日志总结

使用效果

在方案中使用 SkyWalking 后,对于问题排查帮助非常大:

  • 根据关键字查到 TraceID 后,基于 TraceID 调出所有的请求日志
  • 到底发生了什么一目了然

带来的收益

全链路日志系统上线后,团队优化了很多慢请求:

  • 每个调用环节和耗时都列出来了
  • 很容易找到瓶颈点并加以解决
  • 基于这个系统,完成了多个可以汇报的亮点工作

技术选型总结

选型要点具体内容
数据格式支持 OpenTracing
存储系统支持 Elasticsearch
性能影响收集对性能无影响
查询功能树状结构日志、监控报警
侵入性最小业务代码侵入

这次架构经历不涉及太多的架构设计,主要是技术选型和注意事项。

接下来将讨论微服务架构中的另一个重要问题——熔断