一个完整的业务流程通常由多个微服务来协同完成,追踪和定位问题相对比较麻烦,通过在关键点设置链路埋 点,记录下重要的步骤,方便排查和定位问题。
jaeger
Jaeger是一款广受欢迎的开源分布式链路跟踪系统,兼容OpenTracing API,且已加入CNCF开源组织。其主要功能是聚合来自各个异构系统的实时监控数据。
官网:jaeger
官方包支持语言:
OpenTracing Tutorial (Java, Go, Python, Node.js, C#) (tutorials)
jaeger架构
按照数据流向,整体可以分为四个部分:
- jaeger-client:Jaeger 的客户端,实现了 OpenTracing 的 API,支持主流编程语言。客户端直接集成在目标 Application 中,其作用是记录和发送 Span 到 Jaeger Agent。在 Application 中调用 Jaeger Client Library 记录 Span 的过程通常被称为埋点。
- jaeger-agent:暂存 Jaeger Client 发来的 Span,并批量向 Jaeger Collector 发送 Span,一般每台机器上都会部署一个 Jaeger Agent。官方的介绍中还强调了 Jaeger Agent 可以将服务发现的功能从 Client 中抽离出来,不过从架构角度讲,如果是部署在 Kubernetes 或者是 Nomad 中,Jaeger Agent 存在的意义并不大。
- jaeger-collector:接受 Jaeger Agent 发来的数据,并将其写入存储后端,目前支持采用 Cassandra 和 Elasticsearch 作为存储后端。个人还是比较推荐用 Elasticsearch,既可以和日志服务共用同一个 ES,又可以使用 Kibana 对 Trace 数据进行额外的分析。架构图中的存储后端是 Cassandra,旁边还有一个 Spark,讲的就是可以用 Spark 等其他工具对存储后端中的 Span 进行直接分析。
- jaeger-query & jaeger-ui:读取存储后端中的数据,以直观的形式呈现。
Jaeger 的架构非常清晰,部署起来也很轻松,Docker Hub 中有官方打好的 Image,可以拿来直接用,https://hub.docker.com/u/jaegertracing/。如果是本地测试,可以直接用 Jaeger 的 all-in-one Image,
具体使用
首先假设某微服务已经有了中心化的日志收集和处理系统,如果还没有的话,强烈建议部署一套 ELK。再假设对于每一个请求,都会有一个贯穿整个请求流程的 Request ID,如果还没有的话,强烈建议加一个。以上准备完毕后,可以选取一个分布式追踪系统,集成到服务当中,建议采用 Jaeger。重点在最后,在 Trace 的起始处,将 Trace ID 设置为 Request ID,这么一来就打通了日志系统和分布式追踪系统,可以使用同一个 ID 查询请求的事件流和日志流,从此开启了上帝视角。
jaeger组件
jaeger由agent,collector, query, ingester几个部分组成
- Agent
- Collector
- Query
- Ingester
Agent
- 通过UDP接收追踪数据
- 批量发送到Collector
- 部署在主机或者容器中
jaeger-agent 是客户端代理,需要部署在每台主机上。
Collector
- 接收Agent发送的数据并进行处理
- 验证、索引、转换、存储
- 支持Cassandra、ElasticSearch和Kafka作为存储
收集器,可以部署多个。收集 agent 发来的数据并写入 db 或 kafka。
Query
从存储后端查询数据并展示
Ingester
从 kafka中读取数据并写入存储后端
jaeger组件可以统一布署,也可以分开布署。
统一布署指的是把所有组件打包成单一进程支行,
使用的是all-in-one镜像,
分开布署是指单个组件分开各自独立的镜像,适合于数据量大的情况。
数据流
客户端埋点上报数据给Agent
agent将数据发送给colletor
colletor写入es
query从存储后端查询数据展示
具体实例
暂时只部署collector、agent、query和es, kibana这几个组件。
安装es和kibana
注意 es 和 kibana 版本保持一致
docker pull elasticsearch:7.7.0
docker pull kibana:7.7.0
启用 elasticsearch 容器
创建相应文件夹
mkdir elasticsearch
cd elasticsearch
mkdir config
mkdir data
mkdir logs
mkdir plugins
# 给 config 写入配置文件
echo "http.host: 0.0.0.0" >> config/elasticsearch.yml
给这几个目录,赋于777的权限
启动 es 容器
docker run --name es -p 9200:9200 -p 9300:9300 \
-e "discovery.type"="single-node" \
-e ES_JAVA_OPTS="-Xms64m -Xmx128m" \
-v /data/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
-v /data/elasticsearch/data:/usr/share/elasticsearch/data \
-v /data/elasticsearch/plugins:/usr/share/elasticsearch/plugins \
-v /data/elasticsearch/logs:/usr/share/elasticsearch/logs \
-d elasticsearch:7.7.0
启动成功
查看容器信息
docker inspect 44b40a6e81c5
找出你需要的 IP 地址,比如我的是: http://172.17.0.2,下面的 kibana 会需要用到。
启动 kibana 容器
启动容器
把 IP 改成 es 的 IP 地址
docker run --name kibana -e ELASTICSEARCH_HOSTS=http://172.17.0.2:9200 -p 5601:5601 -d kibana:7.7.0
启动成功:
修改配置文件
进入容器
docker exec -it 容器id /bin/sh
修改配置文件
vim /usr/share/kibana/config/kibana.yml
修改 es 的 IP 为当前的 IP
#
# ** THIS IS AN AUTO-GENERATED FILE **
#
# Default Kibana configuration for docker target
server.name: kibana
server.host: "0"
elasticsearch.hosts: [ "http://elasticsearch:9200" ] # 将这里的 IP 换成 Es 的 IP,172.17.0.2
monitoring.ui.container.elasticsearch.enabled: true
查看 kibana 容器日志
docker logs -f 容器 ID
外网访问
输入外网 IP:5601,访问 kibana,第一次访问,成功就会显示一个欢迎语
jaeger 技术栈
jaeger-collector
镜像名称:jaegertracing/jaeger-collector:1.28
版本:1.28
jaeger-collector 参数
数据存储容器采用了elastic,相关参数请根据自己的实际情况填写;
- SPAN_STORAGE_TYPE.存储类型、
- ES_SERVER_URLS.保存请求地址、
- ES_USERNAME.用户名,没有可不填
- ES_USERNAME.密码,没有可不填
- es.index-prefix 存储索引前缀(可选),默认值 jaeger-span-2021-09-27,增加前缀后mini-jaeger-span-2021-09-27
对外开放端口: - 14250 grpc服务端口、
- 14269 服务信息查询端口、
服务心跳检测路由: http://127.0.0.1:14269/
14268 http服务端口
如果采用http推送的span信息,请求路由为: http://127.0.0.1:14268/api/traces
启动容器
es 的 IP 改成自己的 IP,没有配置127.0.0.1就换内网 IP
docker run -d --name=jaeger-collector -p 9411:9411 -p 14250:14250 -p 14268:14268 -p 14269:14269 -e SPAN_STORAGE_TYPE=elasticsearch -e ES_SERVER_URLS=http://127.0.0.1:9200 jaegertracing/jaeger-collector:1.28
jaeger-agent
镜像名称:jaegertracing/jaeger-agent:1.28
版本:1.28
启动容器
docker run -d --name=jaeger-agent -p 6831:6831/udp -p 6832:6832/udp -p 5778:5778/tcp -p 5775:5775/udp -e REPORTER_GRPC_HOST_PORT=127.0.0.1:14250 -e LOG_LEVEL=debug jaegertracing/jaeger-agent:1.28
jaeger-query
镜像名称:jaegertracing/jaeger-query:1.28
版本:1.28
启动容器
es 的 IP 改成自己的 IP,没有配置127.0.0.1就换内网 IP
docker run -d --name=jaeger-query -p 16686:16686 -p 16687:16687 -e SPAN_STORAGE_TYPE=elasticsearch -e ES_SERVER_URLS=http://127.0.0.1:9200 jaegertracing/jaeger-query:1.28
输入外网 IP 加16686端口
访问成功显示
至于,整个架构搭建完成。
数据流
- 客户端埋点上报数据给Agent
- agent将数据发送给colletor
- colletor写入es
- query从存储后端查询数据展示
业务代码埋点收集数据
不同语言实现方式不太一样,具体以自己的业务中使用的语言和框架为准。