目录:
(1).准备工作
(2).jaeger体验
1.初步跑起
2.面板与功能解析
2.1.概述
2.2.Search
2.2.1.支持的查询条件
2.2.2.Trace耗时分布点位图
2.2.3.compare操作
2.2.4.查看trace详情
2.3.Compare
2.4.Dependencies
2.4.1. Force Directed Graph
2.4.2.DAG Graph
(3).加长链路调用
1.不做代码修改增加调用链flaskapp-server -> httpbin
2.代码修改flaskapp后增加调用链flaskapp-server -> httpbin
(4).ingress开放jaeger服务
(5).面向 DevOps 的诊断与分析系统
(6).思考
1.基础架构思考
2.新技术引入与做事思考
(7).参考资料与引述
(8).笔者相关文章
(9).招聘
a.阅读/实践本文请先行阅读/实践笔者公众号相关文章:
istio-1:部署与体验istio-1.4.2 istio-2:istio1.4.2-demo部署与体验,聊聊一些个人看法
b.本文主要以《深入浅出Istio:Service Mesh快速入门与实践》中的python-flask-demo为例论述。
c.架构实战交流钉钉群号:23394754
(1).准备工作
1.确保istio和istio-demo-app容器化
需要按照之前文章完成istio和istio-demo-app的容器化:
istio-1:部署与体验istio-1.4.2
istio-2:istio1.4.2-demo部署与体验,聊聊一些个人看法
确保istio基础组件正常:
代码语言:javascript复制kubectl get pod -n istio-system
NAME READY STATUS RESTARTS AGE
grafana-f5585fb49-dcvhr 1/1 Running 1 16d
istio-citadel-744f9798bb-lq4hc 1/1 Running 1 16d
istio-egressgateway-5c7cc9fb4-qwpwc 1/1 Running 1 16d
istio-galley-d4b8f88c8-ft2pv 1/1 Running 1 16d
istio-ingressgateway-b44fbfbf8-5jwm8 1/1 Running 1 16d
istio-pilot-65699c97df-gcnrv 1/1 Running 0 32h
istio-policy-999dfdb69-d6gcb 1/1 Running 11 16d
istio-sidecar-injector-684fcc7cfb-p87tk 1/1 Running 1 16d
istio-telemetry-7cdf8bf67c-59snl 1/1 Running 0 34h
istio-tracing-bc44d8d85-2bgl2 1/1 Running 0 46h
kiali-767f877b4-zzgvq 1/1 Running 1 16d
prometheus-5d56488ff6-7nrqv 1/1 Running 1 16d
确保istio-demo组件正常:
代码语言:javascript复制kubectl get pod -n istio-app
NAME READY STATUS RESTARTS AGE
flaskapp-v1-68498d7745-x7665 2/2 Running 0 7d
flaskapp-v2-5b64f9874-z9k2z 2/2 Running 0 7d
simple-flask-app-client-584588ccbd-rtkv9 2/2 Running 7 7d
2.jaeger-web服务暴露
需要将jaeger-web服务暴露到容器外部,然后可以通过浏览器访问。
需要两次端口转发:
kubectl port-forward -n istio-system$(kubectl get pod -n istio-system -l app=jaeger -ojsonpath='{.items[0].metadata.name}') 16686:16686
ssh -N -f -L 0.0.0.0:16687:127.0.0.1:16686 root@0.0.0.0
然后通过浏览器访问:
http://ip:16687/
(2).jaeger体验
1.初步跑起
进入istio-demo-client:
kubectl exec -it -n istio-appsimple-flask-app-client-584588ccbd-rtkv9 -- /bin/bash
执行命令向istio-demo-flask-server发起请求:
for i in `seq 10000`; do http --body http://flaskapp:7777/env/version;done
稍等几秒让他跑数据,然后访问jaeger-web:
sleep.istio-app:是本例中的isito-demo-client
flaskapp.istio-app:是本例中的istio-demo-server
jaeger-query:jaeger-web
2.面板与功能解析
2.1.概述
jaeger面板共包含三大模块:Search,Compare,Dependencies。
Search | 主要是提供多维度多视角的链路(trace)查询,查询方式支持传统下拉框和jsonfile两种形式。 |
---|---|
Compare | 比较两个trace。 |
Dependencies | 查看服务依赖图/拓扑图。 |
2.2.Search
2.2.1.支持的查询条件
多维度/多视角查询trace。
Service
2.2.2.Trace耗时分布点位图
可以看到查询结果所有trace在这个时间段内的耗时分布。
2.2.3.compare操作
在查询结果中选择你要对比的trace:
然后点击Compare Trace后跳入Compare模块,然后进行对比分析:
总感觉目前功能有点少。
2.2.4.查看trace详情
在查询结果中左键点击任意一个trace:
会出现一个trace概览:
再点击链路上的具体节点,可以看到这个Trace各节点详情:
Trace查询条件里的tag可以在这里找。
不得不提一点,老外的UI风格非常对我胃口,简约而不简单,这也算是我的做事原则之一吧。
2.3.Compare
这里不赘述了,在Search里顺带提了。
2.4.Dependencies
查看服务依赖图/拓扑图,提供两种图形:DAG,Force Directed Graph。
2.4.1. Force Directed Graph
导引图。
本例形式:
生产完整形式应该是这个程度:
2.4.2.DAG Graph
一条 Trace(调用链)可以被认为是一个由多个 Span 组成的有向无环图(DAG图)。
本例形式:
其中的数字10949是发生的指调用次数。
生产的大概形式:
(3).加长链路调用
目前链路是:istio-demo-client -> istio-demo-flaskapp
1.不做代码修改增加调用链flaskapp-server -> httpbin
我们现在让istio-demo-flaskapp调用另一个服务,然后我们看看是结果。
我们让istio-demo-flaskapp调用httpbin服务,位于:
https://github.com/istio-learning/istio-demo/tree/master/istio-1.4.2/istio-offical-samples/httpbin
将httpbin进行istio化:
istioctl kube-inject -f httpbin.yaml >httpbin-istio.yaml
将httpbin纳入istio管理:
kubectl apply -f httpbin-istio.yaml
我们接下来在simple-flask-app-client的pod中发起请求,要求flaskapp调用httpbin服务的“get”路径,并返回httpbin给出的响应,同时要显示出simple-flask-app-client发出的请求Header的内容:
进入发起Pod:
kubectl exec -it -n istio-appsimple-flask-app-client-584588ccbd-z9mnq -- /bin/bash
执行命令:
http --debug http://flaskapp:7777/fetch?url=http://httpbin:8000/get
fetch代码如下,打印接受到的client发送的request_header以及发送给httpbin服务的request_header,注意观察两者的不同:
代码语言:javascript复制@app.route('/fetch')
def fetch_env():
url = request.args.get('url', '')
request_headers = dict(request.headers)
with urlopen(url) as response:
res = response.read()
return "{}n{}".format(json.dumps(request_headers), res)
http命令其完整结果为:
代码语言:javascript复制HTTPie 0.9.9
Requests 2.19.1
Pygments 2.2.0
Python 3.6.6 (default, Aug 24 2018,05:04:18)
[GCC 6.4.0]
/usr/bin/python3
Linux 3.10.0-957.27.2.el7.x86_64
<Environment {
"colors": 8,
"config": {
"__meta__": {
"about": "HTTPie configuration file",
"help": "https://httpie.org/docs#config",
"httpie": "0.9.9"
},
"default_options": "[]"
},
"config_dir": "/root/.httpie",
"is_windows": false,
"stderr": "<_io.TextIOWrapper name='<stderr>'mode='w' encoding='UTF-8'>",
"stderr_isatty": true,
"stdin": "<_io.TextIOWrapper name='<stdin>'mode='r' encoding='UTF-8'>",
"stdin_encoding": "UTF-8",
"stdin_isatty": true,
"stdout": "<_io.TextIOWrapper name='<stdout>'mode='w' encoding='UTF-8'>",
"stdout_encoding": "UTF-8",
"stdout_isatty": true
}>
>>> requests.request(**{
"allow_redirects": false,
"auth": "None",
"cert": "None",
"data": {},
"files": {},
"headers": {
"User-Agent": "HTTPie/0.9.9"
},
"method": "get",
"params": {},
"proxies": {},
"stream": true,
"timeout": 30,
"url":"http://flaskapp:7777/fetch?url=http://httpbin:8000/get",
"verify": true
})
HTTP/1.1 200 OK
content-length: 785
content-type: text/html; charset=utf-8
date: Sun, 12 Jan 2020 02:09:06 GMT
server: envoy
x-envoy-upstream-service-time: 9
{"Host":"flaskapp:7777", "User-Agent": "HTTPie/0.9.9","Accept-Encoding": "gzip, deflate", "Accept":"*/*", "X-Forwarded-Proto": "http","X-Request-Id": "d8e64f39-554f-9ce8-b57a-50100a244248","Content-Length": "0", "X-B3-Traceid":"70581e6826c6b85d142280f15bd5e0eb", "X-B3-Spanid":"d1c1b20bbbfc2c68", "X-B3-Parentspanid": "142280f15bd5e0eb","X-B3-Sampled": "1"}
b'{n "args": {}, n "headers": {n "Accept-Encoding": "identity", n "Content-Length": "0",n "Host":"httpbin:8000", n "User-Agent": "Python-urllib/3.6", n "X-B3-Parentspanid":"d5ed195b2fb6fb97", n "X-B3-Sampled": "1", n "X-B3-Spanid":"2d3c5ab545b4fa95", n "X-B3-Traceid": "1a3a407555647b51d5ed195b2fb6fb97"n }, n "origin": "127.0.0.1", n "url": "http://httpbin:8000/get"n}n'
此时会发现,在simple-flaskapp-client(sleep)的pod中的httpie客户端发出的请求Header的原始内容为:
代码语言:javascript复制"allow_redirects": false,
"auth": "None",
"cert": "None",
"data": {},
"files": {},
"headers": {
"User-Agent": "HTTPie/0.9.9"
},
"method": "get",
"params": {},
"proxies": {},
"stream": true,
"timeout": 30,
"url":"http://flaskapp:7777/fetch?url=http://httpbin:8000/get",
"verify": true
而flaskapp-server收到的请求Header的内容却复杂得多,注意X-Request-Id:
代码语言:javascript复制{
"Host":"flaskapp:7777",
"User-Agent":"HTTPie/0.9.9",
"Accept-Encoding":"gzip, deflate",
"Accept":"*/*",
"X-Forwarded-Proto":"http",
"X-Request-Id":"d8e64f39-554f-9ce8-b57a-50100a244248",
"Content-Length":"0",
"X-B3-Traceid":"70581e6826c6b85d142280f15bd5e0eb",
"X-B3-Spanid":"d1c1b20bbbfc2c68",
"X-B3-Parentspanid":"142280f15bd5e0eb",
"X-B3-Sampled":"1"
}
我们再看flaskapp-server发向httpbin的请求header,可以发现没有将flaskapp-server接收到的X-Request-Id向后传递给httpbin,那么我们可以进行一个合理推测,即我们看不到simple-flask-client -> simple-flask-server -> httpbin链路,看到的应该是两条割裂链路,即,simple-flask-client-> simple-flask-server 与 simple-flask-server-> httpbin,事实也确实如此,注意看两个链路的X-B3-Traceid是不同的,说明是两个Trace。
代码语言:javascript复制"Accept-Encoding":"identity",
"Content-Length":"0",
"Host":"httpbin:8000",
"User-Agent":"Python-urllib/3.6",
"X-B3-Parentspanid":"d5ed195b2fb6fb97",
"X-B3-Sampled":"1",
"X-B3-Spanid":"2d3c5ab545b4fa95",
"X-B3-Traceid":"1a3a407555647b51d5ed195b2fb6fb97"
我们查看Trace,很明显是两个割裂的,并不是我们预期的完整调用链:client -> server -> httpbin:
原因就在于没有将X-Request-Id等与链路相关的Header向后传递,所以造成无法将不同的调用识别为同一个Trace的结果。
2.代码修改flaskapp后增加调用链flaskapp-server -> httpbin
我们增加fetch_with_header方法,以区别fetch方法,将接收到的reqeust中Trace相关的header向后传递给httpbin:
代码语言:javascript复制TRACE_HEADERS = [
'x-request-id',
'x-b3-parentspanid',
'x-b3-sampled',
'x-b3-spanid',
'x-b3-traceid',
'x-b3-flags',
'x-ot-span-context'
]
@app.route('/fetch_with_header')
def fetch_with_headers():
url = request.args.get('url', '')
request_headers = dict(request.headers)
new_header = {}
for key in request_headers.keys():
if key.lower() in TRACE_HEADERS:
new_header[key] = request_headers[key]
req = Request(url, headers = new_header)
res =urlopen(req).read()
#打印原request_header,request_header,Httpbin返回的response
return "{}n{}n{}".format(json.dumps(request_headers),json.dumps(new_header), res)
然后发起请求:
http --debug http://flaskapp:7777/fetch_with_header?url=http://httpbin:8000/get
完整结果如下:
代码语言:javascript复制HTTPie 0.9.9
Requests 2.19.1
Pygments 2.2.0
Python 3.6.6 (default, Aug 24 2018,05:04:18)
[GCC 6.4.0]
/usr/bin/python3
Linux 3.10.0-957.27.2.el7.x86_64
<Environment {
"colors": 8,
"config": {
"__meta__": {
"about": "HTTPie configuration file",
"help": "https://httpie.org/docs#config",
"httpie": "0.9.9"
},
"default_options": "[]"
},
"config_dir": "/root/.httpie",
"is_windows": false,
"stderr": "<_io.TextIOWrapper name='<stderr>'mode='w' encoding='UTF-8'>",
"stderr_isatty": true,
"stdin": "<_io.TextIOWrapper name='<stdin>'mode='r' encoding='UTF-8'>",
"stdin_encoding": "UTF-8",
"stdin_isatty": true,
"stdout": "<_io.TextIOWrapper name='<stdout>'mode='w' encoding='UTF-8'>",
"stdout_encoding": "UTF-8",
"stdout_isatty": true
}>
>>> requests.request(**{
"allow_redirects": false,
"auth": "None",
"cert": "None",
"data": {},
"files": {},
"headers": {
"User-Agent": "HTTPie/0.9.9"
},
"method": "get",
"params": {},
"proxies": {},
"stream": true,
"timeout": 30,
"url":"http://flaskapp:7777/fetch_with_header?url=http://httpbin:8000/get",
"verify": true
})
HTTP/1.1 200 OK
content-length: 991
content-type: text/html; charset=utf-8
date: Sun, 12 Jan 2020 07:06:59 GMT
server: envoy
x-envoy-upstream-service-time: 11
{"Host":"flaskapp:7777", "User-Agent": "HTTPie/0.9.9","Accept-Encoding": "gzip, deflate", "Accept":"*/*", "X-Forwarded-Proto": "http","X-Request-Id": "6d442409-6a77-9eed-89d6-e55d4a6bbca8","Content-Length": "0", "X-B3-Traceid":"8a211f31f620a1bff0eff6b65f626b90", "X-B3-Spanid":"d242b2985286bb23", "X-B3-Parentspanid":"f0eff6b65f626b90", "X-B3-Sampled": "1"}
{"X-Request-Id":"6d442409-6a77-9eed-89d6-e55d4a6bbca8", "X-B3-Traceid":"8a211f31f620a1bff0eff6b65f626b90", "X-B3-Spanid":"d242b2985286bb23", "X-B3-Parentspanid":"f0eff6b65f626b90", "X-B3-Sampled": "1"}
b'{n "args": {}, n "headers": {n "Accept-Encoding": "identity", n "Content-Length": "0",n "Host":"httpbin:8000", n "User-Agent": "Python-urllib/3.6", n "X-B3-Parentspanid":"eb582674eccb9c14", n "X-B3-Sampled": "1", n "X-B3-Spanid":"421ffd362db50cc2", n "X-B3-Traceid":"8a211f31f620a1bff0eff6b65f626b90"n }, n "origin":"127.0.0.1", n "url": "http://httpbin:8000/get"n}n'
我们对比下“flaskapp-server收到的请求Header”与“flaskapp-server发送给httpbin的Header”:
flaskapp-server收到的请求Header的内容:
代码语言:javascript复制 "Host":"flaskapp:7777",
"User-Agent":"HTTPie/0.9.9",
"Accept-Encoding":"gzip, deflate",
"Accept":"*/*",
"X-Forwarded-Proto":"http",
"X-Request-Id":"6d442409-6a77-9eed-89d6-e55d4a6bbca8",
"Content-Length":"0",
"X-B3-Traceid":"8a211f31f620a1bff0eff6b65f626b90",
"X-B3-Spanid":"d242b2985286bb23",
"X-B3-Parentspanid":"f0eff6b65f626b90",
"X-B3-Sampled":"1"
flask-server发送到httpbin的reqeustHeader内容:
代码语言:javascript复制 "X-Request-Id":"6d442409-6a77-9eed-89d6-e55d4a6bbca8",
"X-B3-Traceid":"8a211f31f620a1bff0eff6b65f626b90",
"X-B3-Spanid":"d242b2985286bb23",
"X-B3-Parentspanid":"f0eff6b65f626b90",
"X-B3-Sampled":"1"
httpbin返回的response内容为,注意观察X-B3-Traceid,和前边的链是一致的,说明通过X-Request-Id将两个请求链结到了一起:
代码语言:javascript复制 "Accept-Encoding":"identity",
"Content-Length":"0",
"Host":"httpbin:8000",
"User-Agent":"Python-urllib/3.6",
"X-B3-Parentspanid":"eb582674eccb9c14",
"X-B3-Sampled":"1",
"X-B3-Spanid":"421ffd362db50cc2",
"X-B3-Traceid":"8a211f31f620a1bff0eff6b65f626b90"
将修改后代码的Trace和修改代码前的Trace做比较,你会发现确实生效了:
观察具体的生效Trace,是完整的链路:flask-client -> flask-server -> httpbin
点开每个Span,你会发现都有一个X-Request-Id,并且值都一样,验证了整个Trace是通过X-Request-Id串联到一起的:
(4).ingress开放jaeger服务
本文提供ingress配置文件,下载然后执行:
https://github.com/hepyu/k8s-app-config/blob/master/yaml/min-cluster-allinone/istio/istio-1.4.2/istio-demo-jaeger-ingress.yaml
本地配置host后访问域名即可:jaeger-istio-demo.inc-inc.com
(5).面向 DevOps 的诊断与分析系统
本节论述节选自(笔者完全认同):
作者:猫耳呀 链接:https://www.jianshu.com/p/0859dac9320c 来源:简书
面向 DevOps 的诊断与分析系统,包括集中式日志系统(Logging),集中式度量系统(Metrics)和分布式追踪系统(Tracing)。
Logging,Metrics 和 Tracing 有各自专注的部分。
Logging - 用于记录离散的事件。例如,应用程序的调试信息或错误信息。它是我们诊断问题的依据。
Metrics - 用于记录可聚合的数据。例如,队列的当前深度可被定义为一个度量值,在元素入队或出队时被更新;HTTP 请求个数可被定义为一个计数器,新请求到来时进行累加。
Tracing - 用于记录请求范围内的信息。例如,一次远程方法调用的执行过程和耗时。它是我们排查系统性能问题的利器。
通过上述信息,我们可以对已有系统进行分类。
Trace领域:
zipkin,skywakling等。
Metric领域:
Prometheus 开始专注于 metrics,随着时间推移可能会集成更多的 tracing 功能,但不太可能深入 logging 领域。
笔者观点:
不认为prometheus可以替代Trace,比如从性能和实现角度来说Prometheus是时序数据库,而trace体量很大,prometheus作者设计的初衷就不是干这个的。
在metric领域,prometheus是无可争议的事实标准。
logging领域:
ELK,阿里云日志服务这样的系统,但同时也不断地集成其他领域的特性到系统中来,正向上图中的圆心靠近。
(6).思考
1.基础架构思考
我们都知道go由于语言本身特性是做不到java中skywalking那样非侵入性的trace支持,但是我们通过细节体验可以得出一个结论:可以将jaeger的支持放到基础框架中,这样可以是go的业务服务默认具备trace能力,实际上也可以达到“非侵入”目的。
jaeger相对skywalking优势:
jaeger更加轻量级;jaeger可以统一所有语言的Trace标准,这点非常好;目前看jaeger将会成为容器化背景下的事实标准,会有大量优秀公司和开发者“帮我们干活”。
这样综合看来,skywalking相对于jaeger的非侵入优势远不足以cover掉jaeger作为“统一标准能力”带来的收益。
2.新技术引入与做事思考
在互联网存量时代,细节更加重要,尤其对于新技术的引入,对于细节的了解程度以及基于此拓展的认知与方法论直接决定了你提出方案/论据的完备性与闭合性,这样才能大幅提高和通过公司级质疑与论证的概率。
同时才能不断的去论证/评估你对新技术终结程度;互联网存量时代下,对事务尤其是对重要事务的终结能力直接决定了公司/Team/个人的竞争力,以及赤裸裸的生存率。
(7).参考资料与引述
开放分布式追踪(OpenTracing)入门与 Jaeger 实现
https://www.jianshu.com/p/0859dac9320c
jaeger实战
https://www.dazhuanlan.com/2019/10/16/5da60eedcea1c/
Metrics, tracing, and logging
http://peter.bourgon.org/blog/2017/02/21/metrics-tracing-and-logging.html
《深入浅出Istio:Service Mesh快速入门与实践》