要实现分布式追踪 , 如何传递SpanContext是关键 。OpenTracing定义了两个方法Inject和Extract用于SpanContext的注入和提取 。
文章插图
Inject 伪代码
span_context = ...outbound_request = ...?# We'll use the (builtin) HTTP_HEADERS carrier format. We# start by using an empty map as the carrier prior to the# call to `tracer.inject`.carrier = {}tracer.inject(span_context, opentracing.Format.HTTP_HEADERS, carrier)?# `carrier` now contains (opaque) key:value pairs which we pass# along over whatever wire protocol we already use.for key, value in carrier: outbound_request.headers[key] = escape(value)这里的注入的过程就是把context的所有信息写入到一个叫Carrier的字典中 , 然后把字典中的所有名值对写入 HTTP Header 。
Extract 伪代码
inbound_request = ...?# We'll again use the (builtin) HTTP_HEADERS carrier format. Per the# HTTP_HEADERS documentation, we can use a map that has extraneous data# in it and let the OpenTracing implementation look for the subset# of key:value pairs it needs.## As such, we directly use the key:value `inbound_request.headers`# map as the carrier.carrier = inbound_request.headersspan_context = tracer.extract(opentracing.Format.HTTP_HEADERS, carrier)# Continue the trace given span_context. E.g.,span = tracer.start_span("...", child_of=span_context)?# (If `carrier` held trace data, `span` will now be ready to use.)抽取过程是注入的逆过程 , 从carrier , 也就是HTTP Headers , 构建SpanContext 。
整个过程类似客户端和服务器传递数据的序列化和反序列化的过程 。这里的Carrier字典支持Key为string类型 , value为string或者Binary格式(Bytes) 。
3.怎么用能?【一文读懂微服务监控之分布式追踪】好了讲了一大堆的概念 , 作为程序猿的你早已经不耐烦了 , 不要讲那些有的没的 , 快上代码 。不急我们这就看看具体如何使用Tracing 。
我们用一个程序猿喜闻乐见的打印‘hello world’的Python应用来说明OpenTracing是如何工作的 。
客户端代码
import requestsimport sysimport timefrom lib.tracing import init_tracerfrom opentracing.ext import tagsfrom opentracing.propagation import Format??def say_hello(hello_to): with tracer.start_active_span('say-hello') as scope: scope.span.set_tag('hello-to', hello_to) hello_str = format_string(hello_to) print_hello(hello_str)?def format_string(hello_to): with tracer.start_active_span('format') as scope: hello_str = http_get(8081, 'format', 'helloTo', hello_to) scope.span.log_kv({'event': 'string-format', 'value': hello_str}) return hello_str?def print_hello(hello_str): with tracer.start_active_span('println') as scope: http_get(8082, 'publish', 'helloStr', hello_str) scope.span.log_kv({'event': 'println'})?def http_get(port, path, param, value): url = 'http://localhost:%s/%s' % (port, path)? span = tracer.active_span span.set_tag(tags.HTTP_METHOD, 'GET') span.set_tag(tags.HTTP_URL, url) span.set_tag(tags.SPAN_KIND, tags.SPAN_KIND_RPC_CLIENT) headers = {} tracer.inject(span, Format.HTTP_HEADERS, headers)? r = requests.get(url, params={param: value}, headers=headers) assert r.status_code == 200 return r.text??# mainassert len(sys.argv) == 2?tracer = init_tracer('hello-world')?hello_to = sys.argv[1]say_hello(hello_to)?# yield to IOLoop to flush the spanstime.sleep(2)tracer.close()客户端完成了以下的工作:
- 初始化Tracer , trace的名字是‘hello-world’
- 创建以个客户端操作say_hello , 该操作关联一个Span , 取名‘say-hello’ , 并调用span.set_tag加入标签
- 在操作say_hello中调用第一个HTTP 服务A , format_string , 该操作关联另一个Span取名‘format’ , 并调用span.log_kv加入日志
- 之后调用另一个HTTP 服务B , print_hello , 该操作关联另一个Span取名‘println’ , 并调用span.log_kv加入日志
- 对于每一个HTTP请求 , 在Span中都加入标签 , 标志http method , http url和span kind 。并调用tracer.inject把SpanContext注入到http header 中 。
from flask import Flaskfrom flask import requestfrom lib.tracing import init_tracerfrom opentracing.ext import tagsfrom opentracing.propagation import Format?app = Flask(__name__)tracer = init_tracer('formatter')@app.route("/format")def format(): span_ctx = tracer.extract(Format.HTTP_HEADERS, request.headers) span_tags = {tags.SPAN_KIND: tags.SPAN_KIND_RPC_SERVER} with tracer.start_active_span('format', child_of=span_ctx, tags=span_tags): hello_to = request.args.get('helloTo') return 'Hello, %s!' % hello_to?if __name__ == "__main__": app.run(port=8081)
推荐阅读
- 企业微信怎么赚钱?只需要做好这几点
- 微软Edge浏览器恢复DoH选项:用户可选择DNS服务提供商
- 适合小微企业申请的https证书是哪种
- 微波炉柠檬酸清洗,微波炉使用技巧
- 微信加好友封号会自动解除吗?
- 微软|坐等升级!Windows 11大更新将公测 微软添加多个给力新功能
- 微信头像国旗怎么弄上去的?
- 修复更新所致打印机蓝屏故障
- 微服务版 前后端分离开源快速开发平台
- 一文让你享用 Google 全套服务