可以非常清晰的看到整个调用的访问链路。
我们还可以点击具体的节点来查看具体的调用信息。
例如我们点击网关微服务查看网关的具体链路,如下所示。
点开后的效果如下所示。
接下来,查看下订单微服务的调用链路具体信息,如下所示。
点开后的效果如下所示。
可以看到,通过ZipKin能够查看服务的调用链路,并且能够查看具体微服务的调用情况。我们可以基于ZipKin来分析系统的调用链路情况,找出系统的瓶颈点,进而进行针对性的优化。
另外,ZipKin中也支持下载系统调用链路的Json数据,如下所示。
点击JSON按钮后,效果如下所示。
其中,显示的Json数据如下所示。
[ [ { "traceId": "9d244edbc1668d92", "parentId": "3f01ba499fac4ce9", "id": "5f0932b5d06fe757", "kind": "SERVER", "name": "get /get/{pid}", "timestamp": 1652413758790051, "duration": 10941, "localEndpoint": { "serviceName": "server-product", "ipv4": "192.168.0.111" }, "remoteEndpoint": { "ipv4": "192.168.0.111", "port": 54140 }, "tags": { "http.method": "GET", "http.path": "/product/get/1001", "mvc.controller.class": "ProductController", "mvc.controller.method": "getProduct" }, "shared": true }, { "traceId": "9d244edbc1668d92", "parentId": "3f01ba499fac4ce9", "id": "c020c7f6e0fa1604", "kind": "SERVER", "name": "get /update_count/{pid}/{count}", "timestamp": 1652413758808052, "duration": 5614, "localEndpoint": { "serviceName": "server-product", "ipv4": "192.168.0.111" }, "remoteEndpoint": { "ipv4": "192.168.0.111", "port": 54140 }, "tags": { "http.method": "GET", "http.path": "/product/update_count/1001/1", "mvc.controller.class": "ProductController", "mvc.controller.method": "updateCount" }, "shared": true }, { "traceId": "9d244edbc1668d92", "parentId": "9d244edbc1668d92", "id": "3f01ba499fac4ce9", "kind": "CLIENT", "name": "get", "timestamp": 1652413758763816, "duration": 54556, "localEndpoint": { "serviceName": "server-gateway", "ipv4": "192.168.0.111" }, "remoteEndpoint": { "ipv4": "192.168.0.111", "port": 8080 }, "tags": { "http.method": "GET", "http.path": "/order/submit_order" } }, { "traceId": "9d244edbc1668d92", "parentId": "9d244edbc1668d92", "id": "475ff483fb0973b1", "kind": "CLIENT", "name": "get", "timestamp": 1652413758759023, "duration": 59621, "localEndpoint": { "serviceName": "server-gateway", "ipv4": "192.168.0.111" }, "tags": { "http.method": "GET", "http.path": "/order/submit_order" } }, { "traceId": "9d244edbc1668d92", "id": "9d244edbc1668d92", "kind": "SERVER", "name": "get", "timestamp": 1652413758757034, "duration": 63190, "localEndpoint": { "serviceName": "server-gateway", "ipv4": "192.168.0.111" }, "remoteEndpoint": { "ipv4": "127.0.0.1", "port": 54137 }, "tags": { "http.method": "GET", "http.path": "/server-order/order/submit_order" } }, { "traceId": "9d244edbc1668d92", "parentId": "3f01ba499fac4ce9", "id": "a048eda8d5fd3dc9", "kind": "CLIENT", "name": "get", "timestamp": 1652413758774201, "duration": 12054, "localEndpoint": { "serviceName": "server-order", "ipv4": "192.168.0.111" }, "tags": { "http.method": "GET", "http.path": "/user/get/1001" } }, { "traceId": "9d244edbc1668d92", "parentId": "3f01ba499fac4ce9", "id": "5f0932b5d06fe757", "kind": "CLIENT", "name": "get", "timestamp": 1652413758787924, "duration": 12557, "localEndpoint": { "serviceName": "server-order", "ipv4": "192.168.0.111" }, "tags": { "http.method": "GET", "http.path": "/product/get/1001" } }, { "traceId": "9d244edbc1668d92", "parentId": "3f01ba499fac4ce9", "id": "c020c7f6e0fa1604", "kind": "CLIENT", "name": "get", "timestamp": 1652413758805787, "duration": 7031, "localEndpoint": { "serviceName": "server-order", "ipv4": "192.168.0.111" }, "tags": { "http.method": "GET", "http.path": "/product/update_count/1001/1" } }, { "traceId": "9d244edbc1668d92", "parentId": "9d244edbc1668d92", "id": "3f01ba499fac4ce9", "kind": "SERVER", "name": "get /submit_order", "timestamp": 1652413758765048, "duration": 53101, "localEndpoint": { "serviceName": "server-order", "ipv4": "192.168.0.111" }, "remoteEndpoint": { "ipv4": "127.0.0.1" }, "tags": { "http.method": "GET", "http.path": "/order/submit_order", "mvc.controller.class": "OrderController", "mvc.controller.method": "submitOrder" }, "shared": true }, { "traceId": "9d244edbc1668d92", "parentId": "3f01ba499fac4ce9", "id": "a048eda8d5fd3dc9", "kind": "SERVER", "name": "get /get/{uid}", "timestamp": 1652413758777073, "duration": 14640, "localEndpoint": { "serviceName": "server-user", "ipv4": "192.168.0.111" }, "remoteEndpoint": { "ipv4": "192.168.0.111", "port": 54139 }, "tags": { "http.method": "GET", "http.path": "/user/get/1001", "mvc.controller.class": "UserController", "mvc.controller.method": "getUser" }, "shared": true } ] ]
小伙伴们也可以根据Json数据分析下系统的调用链路。
ZipKin数据持久化
我们实现了在项目中集成ZipKin,但是此时我们集成ZipKin后,ZipKin中的数据是保存在系统内存中的,如果我们重启了ZipKin,则保存在系统内存中的数据就会丢失,那我如何避免数据丢失呢?ZipKin支持将数据进行持久化来防止数据丢失,可以将数据保存到ElasticSearch、Cassandra或者MySQL中。这里,我们重点介绍下如何将数据保存到MySQL和ElasticSearch中。
ZipKin数据持久化到MySQL
(1)将Zipkin数据持久化到MySQL,我们需要知道MySQL的数据表结构,好在ZipKin提供了MySQL脚本,小伙伴们可以在链接:https://github.com/openzipkin/zipkin/tree/master/zipkin-storage里面下载。
当然,我将下载后的MySQL脚本放到了网关服务shop-gateway的resources目录下的scripts目录下。
(2)在MySQL数据库中新建zipkin数据库,如下所示。
create database if not exists zipkin;
(3)在新建的数据库zipkin中运行mysql.sql脚本,运行脚本后的效果如下所示。
可以看到,在zipkin数据库中新建了zipkin_annotations、zipkin_dependencies和zipkin_spans三张数据表。
(4)启动ZipKin时指定MySQL数据源,如下所示。
java -jar zipkin-server-2.12.9-exec.jar --STORAGE_TYPE=mysql --MYSQL_HOST=127.0.0.1 --MYSQL_TCP_PORT=3306 --MYSQL_DB=zipkin --MYSQL_USER=root --MYSQL_PASS=root
(5)启动ZipKin后,在浏览器中访问链接http://localhost:10001/server-order/order/submit_order?userId=1001&productId=1001&count=1
,如下所示。
(6)查看zipkin数据库中的数据,发现zipkin_annotations数据表与zipkin_spans数据表已经存在系统的调用链路数据。
- zipkin_annotations数据表部分数据如下所示。
- zipkin_spans数据表部分数据如下所示。
可以看到,ZipKin已经将数据持久化到MySQL中,重启ZipKin后就会从MySQL中读取数据,数据也不会丢失了。
ZipKin数据持久化到ElasticSearch
(1)到ElasticSearch官网下载ElasticSearch,链接为:
https://www.elastic.co/cn/downloads/elasticsearch。
这里下载的安装包是:elasticsearch-8.2.0-windows-x86_64.zip。
(2)解压elasticsearch-8.2.0-windows-x86_64.zip,在解压后的bin目录下找到elasticsearch.bat脚本,双击运行ElasticSearch。
(3)启动ZipKin服务端时,指定ElasticSearch,如下所示。
java -jar zipkin-server-2.12.9-exec.jar --STORAGE_TYPE=elasticsearch --ESHOST=localhost:9200
(4)启动ZipKin服务端后,在浏览器中访问链接http://localhost:10001/server-order/order/submit_order?userId=1001&productId=1001&count=1
,如下所示。
ZipKin就会将请求的链路信息保存到ElasticSearch中进行持久化。
好了,今天我们就到儿吧,限于篇幅,文中并未给出完整的案例源代码,想要完整源代码的小伙伴可加入【冰河技术】知识星球获取源码。也可以加我微信:hacker_binghe,一起交流技术。