我们介绍了服务的注册发现,本篇文章我们再来聊聊另一个问题——全链路日志。
为了便于理解,我们依然从业务场景入手。
当时公司的微服务刚刚迁移到Springcloud,服务注册发现基于SpringCloudZookeeper实现,不过组件方面只使用了SpringCloud的服务间调用(Feign)。
迁移到微服务之后,就得考虑日志跟踪的事情了。
之前我们只是简单把日志打印到本地文件上,然后使用ELK进行日志收集、分析、,因此日志记录比较随意且没有形成一个统一的规范。
与技术人员商量后,我们决定把日志进一步规范化,于是提出了如下3点需求:
1、记录什么时候调用了缓存/MQ/ES等中间件,在哪个类的哪个方法耗时多久?
2、记录什么时候调用了数据库,执行了什么SQL,耗时多久?
3、记录什么时候调用了另一个服务,服务名是什么?方法名是什么?耗时多久?
一般来说,一个请求会跨多个服务节点,针对这种情况我们又梳理了2条重要需求。
1、把同一个请求在全部服务的以上所有记录进行串联,最终实现一个树状的记录。
2、设计一个基于这些基础数据的查询统计功能。
通过以上需求梳理并将日志规范后,我们就可以在一个页面上看到每个请求的树状结构日志了,如下图所示,仅供参考:
通过这样的操作,如果后期线上环境出现问题需要进一步调查,我们就有了更多的依据。
需求提完后,我们就需要选择一款真正适合的开源技术进行方案实现,这就涉及技术选型过程。
二、技术选型
在技术选型时,可以看看下方的框架对比表,如图所示:
在上表中我们发现,可供选择的系统太多了,我们该如何选择呢?通过与其他技术同事的讨论,最终商量出了如下标准。
1、日志数据结构支持OpenTracing
平时日志行都是单独记录的,我们只能通过线程id把它们关联起来,因此我们需要一个数据结构把每个请求在全部服务的相关日志关联起来。
而且市面上已经有1个比较通用的全链路数据格式-OpenTracing,它的标准和API是由一个开源的组织(CloudNativeConmmputingFoundation云原生计算基金会孵化)进行维护,这个开源组织也包含了一些全链路日志系统的维护者。
OpenTracing通过提供一个与平台/厂商无关的API,使得开发人员能够更方便地添加(或更换)追踪系统。这样就算我们之前引入的全链路日志不好用,以后想再换掉也是超级方便。
接下来我们解释下OpenTracing标准,它主要包含两个概念:一个是Trace,一个是Span。
我们先来看看下面的例子,如下图所示。
在上图中,我们看到一个客户端调用OrderAPI的请求时经历的整个流程(1到10),即1个Trace,之后它又调用了ProductService的整个过程(2到5),这就是1个Span,每个Span代表Trace中被命名且被计时的连续性执行片段。
通过上图我们还发现,Span中又包含了一个子Span,比如调用ProductService的过程中,ProductService会访问一次数据库(3到4),这也是一个Span。因此,我们可以得出一个Span可以包含多个子Span,而Span与Span之间的关系就叫Reference。
在技术选型时,大家都认可:必须保证系统的可替代性,尽量别在一项开源技术上绑死。因为以前我们吃过一次大亏,强依赖了一个框架,结果那个框架不维护了,后面维护相关代码的人就非常痛苦。但是如果全部迁移掉,代价又太大且工作量也很大,付出与回报产出比不足以说服领导进行决策。要是不迁移,我们就只能一直用着上个年代的技术,所以这次选型我们坚决使用基于OpenTracing的日志系统。
2、支持Elasticsearch作为存储系统
诚然,因为流量大的原因,导致我们记录的日志数据量也很大,这就要求存储这些日志的系统必须支持海量数据且保证查询高效。
最终,因为公司运维同事对Elasticsearch比较熟悉,所以我们提出可以使用Elasticsearch对日志进行存储。
3、保证日志的收集对性能无影响
当服务正在记录日志,我们需要确保日志的记录与收集对服务器的性能不会产生影响。
比如之前我们调研过Pinpoint,当服务正在记录日志,Pinpoint的并发数达到了一定数量且整体吞吐量少了一半,对服务器的性能影响很大,这肯定不行。
4、查询统计功能的丰富程度
一般来说,查询统计的功能越丰富越好,但必须首先满足一个基础功能:支持每个请求树状结构的全链路日志(如下图所示),比如SkyWalking的功能就非常适用。
查询系统除了满足基本功能以外,我们也想实现监控报警、指标统计等功能,以此帮助我们减轻一堆二次开发的工作量。
5.如何以最小的业务代码侵入性引入系统
我们希望日志数据的收集过程对写业务代码的人保持透明,因此,最理想的解决方案是使用Java的探针,通过字节码加强的方式进行埋点。不过,这种方式对系统性能也会产生一定影响。
而且在实际业务中,公司都会把对数据库、Redis、MQ访问的代码进行封装,我们无法通过字节码加强的方式实现埋点,只能尝试在封装的代码中实现埋点了,这样对开发业务代码的人来说同样透明。
6.客户案例
技术选型时,我们往往还需要了解哪些知名公司使用了这个技术,因为大公司的业务场景相对复杂些,提前踩的坑较多,一个技术如果被很多公司都使用过了,那我们使用起来也就会平稳很多。
以上就是技术选型时需考虑的几个问题,大家有更好的想法可以留言我再补充上来。
7.最终选择
根据以上问题的剖析及性能测试结果的分析,我们发现SkyWalking比较符合我们的需求。
不过,做性能测试时,我们发现线程压力以下的服务是否使用SkyWalking对服务的吞吐量影响不大,差别一般不超过10%。
在SkyWalking官方测试报告中也提道:假如有个并发用户,每个用户的每次请求间隔是10ms,TPS基本没什么变化,如下图所示。
技术选型时我们经常提到,不仅仅需要