Tempo - 分布式Loki鏈路追蹤利器

更多奇技淫巧歡迎訂閱博客:https://fuckcloudnative.io
前言
Tempo是Grafana Labs在ObservabilityCON 2020大會(huì)上新開源的一個(gè)用于做分布式式追蹤的后端服務(wù)。它和Cortex、Loki一樣,Tempo也是一個(gè)兼?zhèn)?code style="border-radius: 2px;font-size: 0.92rem;color: rgb(233, 105, 0);background-color: rgb(248, 248, 248);margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-family: 'Roboto Mono', 'Source Sans Pro', Monaco, courier, monospace !important;">高擴(kuò)展和低成本效應(yīng)的系統(tǒng)。
之前小白有提到Grafana Labs的云原生Observability宇宙只剩下trace部分,那么今天就拿Loki的分布式追蹤來體驗(yàn)下這Observability的最后一環(huán)吧。正式開始前,先看下小白精心準(zhǔn)備的Tempo體驗(yàn)視頻吧。
關(guān)于Tempo
Tempo本質(zhì)上來說還是一個(gè)存儲(chǔ)系統(tǒng),它兼容一些開源的trace協(xié)議(包含Jaeger、Zipkin和OpenCensus等),將他們存在廉價(jià)的S3存儲(chǔ)中,并利用TraceID與其他監(jiān)控系統(tǒng)(比如Loki、Prometheus)進(jìn)行協(xié)同工作。

可以看到Tempo的架構(gòu)仍然分為distributor、ingester、querier、tempo-query、compactor這幾個(gè)架構(gòu),熟悉Loki和Cortex的朋友可能光看名字就知道他們大概是做什么的。不熟悉的同學(xué)也沒關(guān)系,下面簡(jiǎn)單說下各模塊的作用:
distributor
監(jiān)聽多個(gè)端口,分別接受來自Jaeger、Zipkin和OpenCensus協(xié)議的數(shù)據(jù),按照TraceID進(jìn)行哈希并映射到哈希環(huán)上,并交由ingester進(jìn)行存儲(chǔ)處理。當(dāng)前distributor支持的trace協(xié)議如下:
| Protocol | Port |
|---|---|
| OpenTelemetry | 55680 |
| Jaeger - Thrift Compact | 6831 |
| Jaeger - Thrift Binary | 6832 |
| Jaeger - Thrift HTTP | 14268 |
| Jaeger - GRPC | 14250 |
| Zipkin | 9411 |
ingester
具體負(fù)責(zé)trace數(shù)據(jù)的塊存儲(chǔ)(memcache、GCS、S3)、緩存(Memcache)和索引的處理
querier
負(fù)責(zé)從ingester和后端存儲(chǔ)里面撈取trace數(shù)據(jù),并提供api給查詢者
compactor
負(fù)責(zé)后端存儲(chǔ)塊的壓縮,減少數(shù)據(jù)塊數(shù)量
tempo-query
tempo的一個(gè)可視化界面,用的jaeger query,可以在上面查詢tempo的trace數(shù)據(jù)。
Loki鏈路跟蹤
要體驗(yàn)的同學(xué),可以先下載小白在GitHub上的Docker-Compose,推薦配合本篇內(nèi)容一起實(shí)踐
https://github.com/CloudXiaobai/loki-cluster-deploy/tree/master/demo/docker-compose-with-tempo
Loki方面
在做之前我們先看下Loki的文檔是怎么描述的:
The tracing_config block configures tracing for Jaeger. Currently limited to disable auto-configuration per environment variables only.
可以看到當(dāng)前Loki對(duì)于Trace的支持集中在Jaeger,而且配置是默認(rèn)開啟的,并且只能在環(huán)境變量里面讀取jaeger的信息。docker-compose下的案例如下:
querier-frontend:
image: grafana/loki:1.6.1
runtime: runc
scale: 2
environment:
- JAEGER_AGENT_HOST=tempo \\tempo的地址
- JAEGER_ENDPOINT=http://tempo:14268/api/traces
- JAEGER_SAMPLER_TYPE=const \\采樣率類型
- JAEGER_SAMPLER_PARAM=100 \\采樣率100
API網(wǎng)關(guān)方面
API網(wǎng)關(guān)并不是Loki的原生組件,而是在Loki分布式部署的情況下,需要有一個(gè)統(tǒng)一的入口對(duì)Loki API進(jìn)行路由。之前小白用的Nginx,但是原生的Nginx并不支持OpenTracing。小白根據(jù)nginx1.14版本做了一個(gè)帶jaeger模塊的鏡像用于Loki入口的trace生成和日志采集。
gateway:
image: quay.io/cloudxiaobai/nginx-jaeger:1.14.0
runtime: runc
restart: always
ports:
- 3100:3100
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./jaeger-config.json:/etc/jaeger-config.json
- 'gateway_trace_log:/var/log/nginx/'
對(duì)于支持OpenTracing的Nginx,我們需要修改nginx.conf配置文件如下:
...
#加載opentracing庫(kù)
load_module modules/ngx_http_opentracing_module.so;
http {
#啟用opentracing
opentracing on;
#加載jaeger庫(kù)
opentracing_load_tracer /usr/local/lib/libjaegertracing_plugin.so /etc/jaeger-config.json;
#日志格式,打印traceid
log_format opentracing '"traceID":"$opentracing_context_uber_trace_id"';
server {
listen 3100 default_server;
location = / {
#向upstream轉(zhuǎn)發(fā)時(shí)帶上trace的頭信息
opentracing_operation_name $uri;
opentracing_trace_locations off;
opentracing_propagate_context;
proxy_pass http://querier:3100/ready;
}
}
}
以上小白只截取了Nginx部分配置,完整的要參考docker-compose里的nginx.conf
此外,nginx還需要一個(gè)jaeger-config.json,用于將trace數(shù)據(jù)轉(zhuǎn)給agent處理。
{
"service_name": "gateway", \\服務(wù)名
"diabled": false,
"reporter": {
"logSpans": true,
"localAgentHostPort": "jaeger-agent:6831" \\jaeger-agent地址
},
"sampler": {
"type": "const",
"param": "100" \\采樣率
}
}
為了方便演示,小白配置的采樣率均為100%
最后,我們?yōu)锳PI網(wǎng)關(guān)啟用一個(gè)Jaeger-agent用于收集trace信息并轉(zhuǎn)給Tempo,它的配置如下:
jaeger-agent:
image: jaegertracing/jaeger-agent:1.20
runtime: runc
restart: always
# 轉(zhuǎn)發(fā)給tempo
command: ["--reporter.grpc.host-port=tempo:14250"]
ports:
- "5775:5775/udp"
- "6831:6831/udp"
- "6832:6832/udp"
- "5778:5778"
為什么API網(wǎng)關(guān)不直接發(fā)給Tempo要經(jīng)過Jaeger-agent轉(zhuǎn)發(fā)一下,小白認(rèn)為用agent的方式更加靈活一些。
以上,我們就完成了Loki分布式追蹤的配置部分,接下來我們用docker-compose up -d將服務(wù)都運(yùn)行起來。
Grafana方面
當(dāng)docker的所有服務(wù)運(yùn)行正常后,我們?cè)L問grafana并添加兩個(gè)數(shù)據(jù)源
添加tempo數(shù)據(jù)源

添加Loki數(shù)據(jù)源,并解析API網(wǎng)關(guān)TraceID


Loki提取TraceID的正則部分是從API網(wǎng)關(guān)的日志中匹配
體驗(yàn)Tempo
數(shù)據(jù)源設(shè)置OK后,我們進(jìn)入Explore選擇loki查詢trace.log就可以得到API網(wǎng)關(guān)的日志了。
從Parsed Fields里面我們就可以看到,Grafana從API網(wǎng)關(guān)的日志里面提取了16位字符串作為TraceID了,而它關(guān)聯(lián)了Tempo的數(shù)據(jù)源,我們點(diǎn)擊Tempo按鈕就可以直接切到Trace的信息如下:

展開Trace信息,我們可以看到Loki的一次查詢的鏈路會(huì)經(jīng)過下面幾個(gè)部分
gateway -> query-frontend -> querier -> ingester
|-> SeriesStore.GetChunkRefs
并且得出結(jié)論,本次查詢的耗時(shí)主要落在Ingeter上,原因是查詢的日志還沒被flush到存儲(chǔ)當(dāng)中,querier需從ingester中取日志的數(shù)據(jù)。

我們?cè)賮砜匆粋€(gè)Loki接收日志的案例:

從trace的鏈路來看,當(dāng)日志采集端往Loki Post日志時(shí),請(qǐng)求的鏈路會(huì)經(jīng)過如下部分:
gateway -> distributor -> ingester
同時(shí),我們還看到了這次的提交的日志流經(jīng)過兩個(gè)ingester實(shí)例的處理,且處理時(shí)間沒有明顯差異。
總結(jié)
關(guān)于Logging和Tracing兩部分在Grafana上的展示還沒有達(dá)到ObservabilityCON 2020上的流暢度,不過根據(jù)會(huì)上的消息,更精細(xì)話的trace <--> log、metrics <--> trace和metrics <--> log這三部分互相協(xié)作部分應(yīng)該很快會(huì)發(fā)布。屆時(shí)Grafana將是云上可觀測(cè)性應(yīng)用系統(tǒng)里的王者級(jí)產(chǎn)品(雖然有額外的各種查詢語句學(xué)習(xí)成本)


你可能還喜歡
點(diǎn)擊下方圖片即可閱讀

云原生是一種信仰??

掃碼關(guān)注公眾號(hào)
后臺(tái)回復(fù)?k8s?獲取史上最方便快捷的 Kubernetes 高可用部署工具,只需一條命令,連 ssh 都不需要!


點(diǎn)擊?"閱讀原文"?獲取更好的閱讀體驗(yàn)!
??給個(gè)「在看」,是對(duì)我最大的支持??

