一,概述
zipkin的作用
在微服務架構下,一個http請求從發出到響應,中間可能經過了N多服務的調用,或者N多邏輯操作,
如何監控某個服務,或者某個邏輯操作的執行情況,對分析耗時操作,性能瓶頸具有很大價值,
zipkin幫助我們實現了這一監控功能。
二、安裝zipkin
環境說明
操作系統:centos 7.6
配置:2核4g
python版本:3.5.2
啟動zipkin
啟動方式有2種,一個是docker,一個jar包。任選其一即可。
本文采用jar包方式啟動
docker
docker run --name zipkin -d -p 9411:9411 openzipkin/zipkin
jar包
wget https://dl.bintray.com/openzipkin/maven/io/zipkin/java/zipkin-server/2.12.9/zipkin-server-2.12.9-exec.jar java -jar zipkin-server-2.12.9-exec.jar
訪問zipkin
http://192.168.31.232:9411
效果如下:
三、python實現zipkin
使用py_zipkin模塊來實現,這里以flask項目來測試。
安裝模塊
pip3 install py_zipkin pymysql flask
創建項目
新建demo.py
mkdir -p /data/flask_demo/ cd /data/flask_demo/ vim demo.py
內容如下:

import requests from flask import Flask from py_zipkin.zipkin import zipkin_span,create_http_headers_for_new_span import time app = Flask(__name__) app.config.update({ "ZIPKIN_HOST":"127.0.0.1", "ZIPKIN_PORT":"9411", "APP_PORT":5000, # any other app config-y things }) def do_stuff(): time.sleep(2) headers = create_http_headers_for_new_span() requests.get('http://localhost:6000/service1/', headers=headers) return 'OK' def http_transport(encoded_span): # encoding prefix explained in https://github.com/Yelp/py_zipkin#transport #body = b"\x0c\x00\x00\x00\x01"+encoded_span body=encoded_span zipkin_url="http://127.0.0.1:9411/api/v1/spans" #zipkin_url = "http://{host}:{port}/api/v1/spans".format( # host=app.config["ZIPKIN_HOST"], port=app.config["ZIPKIN_PORT"]) headers = {"Content-Type": "application/x-thrift"} # You'd probably want to wrap this in a try/except in case POSTing fails r=requests.post(zipkin_url, data=body, headers=headers) print(type(encoded_span)) print(encoded_span) print(body) print(r) print(r.content) @app.route('/') def index(): with zipkin_span( service_name='webapp', span_name='index', transport_handler=http_transport, port=5000, sample_rate=100, #0.05, # Value between 0.0 and 100.0 ): with zipkin_span(service_name='webapp', span_name='do_stuff'): do_stuff() time.sleep(1) return 'OK', 200 if __name__=='__main__': app.run(host="0.0.0.0",port=5000,debug=True)
新建server1.py

from flask import request import requests from flask import Flask from py_zipkin.zipkin import zipkin_span,ZipkinAttrs import time import pymysql app = Flask(__name__) app.config.update({ "ZIPKIN_HOST":"127.0.0.1", "ZIPKIN_PORT":"9411", "APP_PORT":5000, # any other app config-y things }) def do_stuff(): time.sleep(2) with zipkin_span(service_name='service1', span_name='service1_db_search'): db_search() return 'OK' def db_search(): # 打開數據庫連接 db = pymysql.connect("127.0.0.1", "root", "123456", "mysql", charset='utf8') # 使用cursor()方法獲取操作游標 cursor = db.cursor() # 使用execute方法執行SQL語句 cursor.execute("SELECT VERSION()") # 使用 fetchone() 方法獲取一條數據 data = cursor.fetchone() print("Database version : %s " % data) # 關閉數據庫連接 db.close() def http_transport(encoded_span): # encoding prefix explained in https://github.com/Yelp/py_zipkin#transport #body = b"\x0c\x00\x00\x00\x01" + encoded_span body=encoded_span zipkin_url="http://127.0.0.1:9411/api/v1/spans" #zipkin_url = "http://{host}:{port}/api/v1/spans".format( # host=app.config["ZIPKIN_HOST"], port=app.config["ZIPKIN_PORT"]) headers = {"Content-Type": "application/x-thrift"} # You'd probably want to wrap this in a try/except in case POSTing fails requests.post(zipkin_url, data=body, headers=headers) @app.route('/service1/') def index(): with zipkin_span( service_name='service1', zipkin_attrs=ZipkinAttrs( trace_id=request.headers['X-B3-TraceID'], span_id=request.headers['X-B3-SpanID'], parent_span_id=request.headers['X-B3-ParentSpanID'], flags=request.headers['X-B3-Flags'], is_sampled=request.headers['X-B3-Sampled'], ), span_name='index_service1', transport_handler=http_transport, port=6000, sample_rate=100, #0.05, # Value between 0.0 and 100.0 ): with zipkin_span(service_name='service1', span_name='service1_do_stuff'): do_stuff() return 'OK', 200 if __name__=='__main__': app.run(host="0.0.0.0",port=6000,debug=True)
運行demo.py
python3 demo.py
運行server1.py
python3 server1.py
訪問5000端口
四、查看調用鏈
點擊查證,點擊下面的結果
效果如下:
可以看到,有webapp和services兩個service,5個span標簽,可以清楚看到service和service,service和span,span和span之間的關系,和各span耗時情況。
點擊依賴,效果如下:
點擊webapp,效果如下:
五、api調用
官網api文檔:https://zipkin.io/zipkin-api/#/default/get_traces
這里演示一下,調用2個api
services
返回與span終結點關聯的所有服務名稱的列表。
http://192.168.31.232:9411/api/v2/services
效果如下:
traces
調用此請求將檢索與以下篩選器匹配的跟蹤。
http://192.168.31.232:9411/api/v2/traces
效果如下:
這里的tags,可以顯示錯誤信息。
有錯誤時,就是紅色的,點擊紅色區塊
就可以看到具體信息
這個錯誤信息表示,無法連接到mysql。因為這台機器,還沒有mysql服務。
為了消除這個錯誤,可以再啟動一個mysql數據庫。
mkdir -p /data/mysql docker pull mysql:5.7 docker run -itd -p 3306:3306 --name wiki-mysql -e MYSQL_ROOT_PASSWORD=123456 --restart=always --restart=on-failure:1 --oom-score-adj -1000 --privileged=true --log-opt max-size=10m --log-opt max-file=1 -v /data/mysql:/var/lib/mysql mysql:5.7
重新啟動server1.py
再次訪問5000端口
再次查詢一次,就沒有紅色了
如果需要做報警,可以通過調用api,獲取到error信息,進行統一的郵件通知。
六、mysql的方式存儲
注意:zipkin的數據,默認是存在內存中的,如果重啟服務,會造成數據丟失。
在現有數據庫基礎上,新建實例,實例名為zipkin。
CREATE DATABASE zipkin DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
然后執行官網建庫腳本
https://github.com/openzipkin/zipkin/blob/master/zipkin-storage/mysql-v1/src/main/resources/mysql.sql
執行sql之后,會建立3張表
這樣我們的數據庫就建好了。
執行
STORAGE_TYPE=mysql MYSQL_USER=root MYSQL_PASS=123456 MYSQL_HOST=127.0.0.1 MYSQL_TCP_PORT=3306 java -jar zipkin-server-2.12.9-exec.jar
這樣啟動zipkin,就自動連上mysql,並存儲數據了。
如圖,大功告成
注意,一般我們都在后台運行zipkin,所以用nohup的方式啟動,命令如下
STORAGE_TYPE=mysql MYSQL_USER=root MYSQL_PASS=123456 MYSQL_HOST=127.0.0.1 MYSQL_TCP_PORT=3306 nohup java -jar zipkin-server-2.12.9-exec.jar &
本文參考鏈接: