搭建调用链路监控系统
现在微服务非常盛行的年代,在公司内,有各种各样的微服务相关的实践。今天我们不展开微服务具体是什么,只需要了解在一个互联网服务系统内部可能是由N多个子服务组成,每个子服务独立开发、部署、维护,通过API/RPC与其他服务通信,而不是直接共同操作相同的数据库、表来实现数据交互。在这样的架构之下,服务间的调用链路关系可能是这样的:a -> b -> d -> e
a -> c -> d -> b -> f
以这个单向的调用为例,实际场景可能是更加复杂的网状形式。比如 a 是对用户提供服务,其内部的2个功能分别会有2个不同的调用链路。这时如果 a 检测到一个错误发生,那么怎么确定是 a 自身异常导致的,还是由于上游服务 b/d/e 异常导致的。如果不能很好的、快速的定位最根本的异常产生在哪里,那么势必会影响故障恢复时间,进而影响到服务的可用性。
那么,有这样的问题,如何解决呢?那就是调用链路监控系统该上台了。目前,有2个比较流行的开源系统 zipkin/ pinpoint . 看到“左耳朵耗子”推荐 zipkin,所以我们就直接使用zipkin,所以下面我们以zipkin实践为主题展开介绍。
zipkin 主要包括两部分功能,第一,提供调用日志收集接口,第二,提供展示界面。
zipkin 官网:https://zipkin.io/
zipkin GitHub: https://github.com/openzipkin/zipkin/
我们的web服务是PHP语言,我们希望记录、上报应用间的调用信息,并且是无侵入、异步高性能的。无侵入是指不修改现有应用程序代码,异步高性能是指不能因为记录、上报调用日志信息而影响主业务响应速度。zipkin.io 中提到了好多语言的实现,多数都是无侵入式的,这一点很好。我们使用php语言,因此就选择了Molten (https://github.com/chuan-yun/Molten) ,这个是一个PHP扩展,安装过程也比较简单,对应配置项在github中有说明,说明不是特别详细,酌情理解。它提供4中方式来记录、上报调用日志信息,第一,记录本地文件,第二,输出到标准输出,第三,输出到Syslog,第四,直接通过zipkin的接口上报。
第四种方式,当zipkin接口服务挂掉后,会直接影响正常业务访问,这种方式与zipkin形成了一种强依赖性,所以我们没采用。前三种方式其实都是记录日志,并不上报给 zipkin,需要我们自己想办法完成上报。为了更加简单、依赖更少,我们选择记录本地文件,也就是第一种方式。在实战过好多项目后,发现写本地文件还是最可靠的。
这里我们放下我们的 molten 相关的配置:
[molten] extension=molten.so molten.enable=1 molten.output_type=1 molten.sampling_type=1 molten.sampling_rate=64 molten.sampling_request=1000 molten.sink_type=1 molten.sink_log_path=/letv/logs/phpzipkin/ molten.span_format=zipkin molten.report_interval=60 molten.report_limit=1000sink_log_path 如果要指定目录,最后需要加上 / ,同时要确保这个目录权限可写。如果指定为文件前缀,最终生产的文件是这样的 {prefix}tracing-20180502.log ,所以要保证上级目录有写权限。
在同一台服务器上可能部署多个服务,因此服务名称需要再各个项目中指定
// 调用链监控分析,服务名称 ini_set('molten.service_name', 'odp');当然,如果单台机器部署单个项目,可以把service_name 定义在php.ini中
接着就是要把这些日志上报给zipkin,基于我们已有的 filebeat+kafka+ELK架构(可以参看“搭建ELK日志监控平台那些事”),我们就直接集成到现有的架构上,形成这样的:
molten + filebeat + kafka + zipkin-collector + zipkin + elasticsearch
看上去这样是完美的解决方案,好像我们啥也不用做,并且也实现了我们最开始提到的2点要求。但是最终还是遇到了一些问题,好在都一一攻破了。
1. filebeat 要收集多种日志,该如何配置?
在同一台web服务器上我们需要收集的日志各种各样,在ELK架构下,这些日志最终会经过 logstash 分析处理,最终保存到 elasticsearch 中。那么调用链路日志信息是不需要经过logstash的,因为molten生成的格式就是zipkin所需要的,同时为了有更好的隔离,我们需要把这些不同的日志收集到Kafka的不同 Topic中。
我们通过2个input_log 段,添加一些自定义字段实现,fields.topic 这个定义了不同的 Topic 名称,之后通过在 output.kafka中配置这个变量即可。
filebeat.prospectors: - input_type: log paths: - /letv/logs/odp.my.le.com.access.log - /letv/logs/benefit.my.le.com.access.log - /letv/logs/phpmessages fields: topic: odp_log - input_type: log paths: - /letv/logs/phpzipkin/* fields: topic: lefan_tracing_log tags: ["service-lefan", "web-tier"] output.kafka: enabled: true hosts: ["10.183.97.52:9092", "10.183.97.62:9092", "10.183.97.63:9092"] topic: "%{[fields][topic]}" logging.level: error
2. zipkin-collector 无法正确解析 filebeat 收集的调用日志信息
filebeat 收集的所有日志信息,全部都会在外层加一个结构,然后把日志信息,放入 message 字段中。但是这样一来,经过包装的这个结构,最终给到 zipkin-collector 时就会出错。
这当中有想过通过 logstash 把这个日志信息从kafka取出,除去这层外衣后,再录入kafka 中,然后让 zipkin-collector 接收。但是这样一来,在流程中加入了 logstash,会让这个流程更加复杂,也需要在logstash中加入一些过滤规则。另外一个解决办法是,logstash 处理完之后,不会kafka,直接通过logstash的另外插件,上报给zipkin。
但是这两种方法,我们都没有采用。原因很简单:第一种方案,太绕,架构流程更加复杂了;第二种方案,需要安装一个新的 logstash 插件,其稳定性,可用性并没有得到验证,所以还是不能用。
最后,我们决定对zipkin-collector 这个收集数据的工具,进行小小的调整,能够解析filebeat增加的这层 json外衣,然后取其中的message字段即可。后来,在github提交了 pull request ,但是 zipkin 项目维护者感觉这不属于 zipkin 的职责,是数据输入前需要考虑的问题,因此就暂时还没有合并到 master。
github:https://github.com/WiFeng/zipkin
jar包:kafka10.zip 解压后,取出其中的kafka10.jar
有了这些之后,我们需要启动zipkin,并且需要加一些启动参数:
zipkin.sh
#!/bin/bash zipkin=`ps aux|grep zipkin.jar|grep -v grep` if [ -z "$zipkin" ]; then #java -jar zipkin.jar --logging.level.zipkin=DEBUG 2>&1 >/dev/null & export STORAGE_TYPE=elasticsearch export ES_HOSTS=http://10.183.97.33:9200,http://10.183.97.34:9200,http://10.183.97.51:9200 export ES_INDEX=zipkin java \ -Dloader.path='kafka10.jar,kafka10.jar!/lib' \ -Dspring.profiles.active=kafka \ -Dzipkin.collector.kafka.bootstrap-servers=10.183.97.52:9092,10.183.97.62:9092,10.183.97.63:9092 \ -Dzipkin.collector.kafka.topic=lefan_tracing_log \ -cp zipkin.jar \ org.springframework.boot.loader.PropertiesLauncher \ --logging.level.zipkin=ERROR 2>&1 >>/letv/logs/zipkin/zipkin.log & sleep 10 fi
在 zipkin.sh 的同目录下会一个 kafka10.jar 这个包,才可以启动从kafka获取日志信息。在这里使用上面修改过的包 kafka10.jar ,然后重新启动即可。
zipkin 的调用链路数据,我们最终保存在了 elasticsearch 中,以方便查看最近一段时间的数据。上面也提供了对应的配置项。把对应IP/PORT 修改即可。
启动就直接执行这个 zipkin.sh 就行。
[liuweifeng@dfs-zb20-node1 zipkin]$ cd /usr/local/zipkin/ [liuweifeng@dfs-zb20-node1 zipkin]$ ./zipkin.sh
如果启动成功,我们可以访问其web界面,默认监听 9411 端口,例如:http://10.112.43.1:9411/zipkin/
最终我们的监控系统,输入侧都是 filebeat , web图形化系统分别为 zipkin / kibana ,中间组件都共用,非常清晰。
您好 您这个 有现成的dockerimage吗 重新 封装过的zipkin
我最近也在做这个事。google filebeta->zipkin的时候看到了你提的PR.
希望对你有用
哥们加个联系方式呗,咱们聊聊关于全链路监控这里的东西
邮箱:silkcutbeta@gmail.com
哥们加个联系方式呗,咱们聊聊关于全链路监控这里的东西
邮箱:silkcutbeta@gmail.com
用了你的kafka10
报错无法启动大神
Cannot load configuration class: zipkin.autoconfigure.collector.kafka10.ZipkinKafka10CollectorAutoConfiguration
@golang
有没有更加详细的错误信息?
弟兄报错啊咋整
Cannot load configuration class: zipkin.autoconfigure.collector.kafka10.ZipkinKafka10CollectorAutoConfiguration