Vert.x,应用监控 - 全链路跟踪,基于Zipkin

关于Zipkin

Zipkin是一款开源的分布式实时数据追踪系统(Distributed Tracking System),能够收集服务间调用的时序数据,提供调用链路的追踪。Zipkin每一个调用链路通过一个trace id来串联起来,通过trace id,就能够直接定位到这次调用链路,并且可以根据服务名、标签、响应时间等进行查询,找出哪些耗时比较长的链路节点。

当用户发起一次调用时,Zipkin的客户端(Brave)会在入口处为整条调用链路生成一个全局唯一的trace id, 一个trace id代表一个完整的调用链。一个trace内部包含多个span。

Zipkin为一条链路中的每一次分布式调用生成一个span id。一个trace由一组span组成,一个trace中的所有span是一个树形结构,树的根节点叫做root span。除root span外,其他span都会包含一个parent Id,表示父级span的span Id。

每个span中包含多个Annotation,用来记录关键事件的时间点。

ZipKin 可以分为两部分:

  • ZipKin Server :用来作为数据的采集存储、数据分析与展示;
  • ZipKin Client :基于不同的语言及框架封装的一些列客户端工具,这些工具完成了追踪数据的生成与上报功能。

ZipKin Server

Zipkin支持的存储类型有inMemory(默认)、MySQL、Cassandra、以及ElasticsSearch几种方式,正式环境推荐使用Cassandra和ElasticSearch。

要使用ZipKin Server非常简单,通过https://repo1.maven.org/maven2/io/zipkin/zipkin-server/下载zipkin-server-x.xx-exec.jar文件,然后执行即可:

# java -jar zipkin-server-3.4.2-exec.jar
...
2024-11-08T11:15:47.484+08:00  INFO [/] 2450 --- [oss-http-*:9411] c.l.a.s.Server                           : Serving HTTP at /[0:0:0:0:0:0:0:0]:9411 - http://127.0.0.1:9411/

说明: 如果不指定参数,zipkin server不存储跟踪数据(inMemory) , 可以通过--STORAGE_TYPE参数指定支持的持久化存储。

ZipKin Client

Brave是ZipKin客户端的库文件,在我们编写的代码中使用,用于将我们的埋点信息上报到Zipkin服务器端,通常框架会整合Brave。

vertx-zipkin

Vert.x通过Zipkin Brave整合了Zipkin,提供了一个开箱即用的组件vertx-zipkin,可以让我们轻松的使用Zipkin跟踪Vertx编写的服务的调用。

首先需要添相关依赖添:

<dependency>
	<groupId>io.vertx</groupId>
	<artifactId>vertx-zipkin</artifactId>
	<version>4.5.10</version>
</dependency>

使用vertx-zipkin非常简单,只要为Vertx实例指定相应的zipkin跟踪配置(ZipkinTracingOptions)即可:

import io.vertx.core.Vertx;
import io.vertx.core.VertxOptions;
import io.vertx.core.http.HttpMethod;
import io.vertx.core.http.HttpServer;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.Router;
import io.vertx.mysqlclient.MySQLBuilder;
import io.vertx.mysqlclient.MySQLConnectOptions;
import io.vertx.sqlclient.PoolOptions;
import io.vertx.sqlclient.Row;
import io.vertx.sqlclient.SqlClient;
import io.vertx.sqlclient.Tuple;
import io.vertx.tracing.zipkin.HttpSenderOptions;
import io.vertx.tracing.zipkin.ZipkinTracingOptions;

public class API01 {
	public static void main(String[] args) {
		String senderEndpoint = "http://172.18.240.73:9411/api/v2/spans"; // zipkin server
		Vertx vertx = Vertx.vertx(new VertxOptions().setTracingOptions(new ZipkinTracingOptions()
				.setSenderOptions(new HttpSenderOptions().setSenderEndpoint(senderEndpoint)).setServiceName("API01"))); // 必须指定唯一的服务名
		
		MySQLConnectOptions connectOptions = new MySQLConnectOptions()
				.setHost("127.0.0.1").setPort(3306)
				.setUser("root").setPassword("Passw0rd")
				.setDatabase("hr").setConnectTimeout(2000)
				.addProperty("autoReconnect", "true")
				.addProperty("useSSL","false")
				.addProperty("rewriteBatchedStatements", "true");
		
		PoolOptions poolOptions = new PoolOptions().setMaxSize(5);
		
		SqlClient client = MySQLBuilder.client().using(vertx)
				.with(poolOptions)
				.connectingTo(connectOptions)
				.build();
		HttpServer server = vertx.createHttpServer();
		Router router = Router.router(vertx);
		router.route(HttpMethod.GET, "/api/v2/api01/:empNo").handler(routingContext ->{
			String en = routingContext.pathParam("empNo");
			int empNo = 0;
			try {
				empNo = Integer.parseInt(en);
			} catch(Exception e) {}
			String sqlText = "select empno, ename, job from emp where empno = ?";
			client.preparedQuery(sqlText).execute(Tuple.of(empNo)).onSuccess(rows -> {
				JsonArray result = new JsonArray();
				for (Row row : rows) {
					JsonObject json = row.toJson();
					result.add(json);
				}
				HttpServerResponse response = routingContext.response();
				response.putHeader("content-type", "application/json");
				response.end(result.toString());
			}).onFailure(exception -> {
				routingContext.fail(exception);
			});
		});
		server.requestHandler(router).listen(8001);
	}
}

启动并调用我们编写的接口,即可在zipkin服务端跟踪我们的调用信息。

访问zipkin服务器"http://172.18.240.73:9411/zipkin/“,点击"Find a trace” -> 点红色的"+“号图标,指定"serviceName”,然后点击"RUN QUERY"按钮进行查询。
在这里插入图片描述
可以看到本次api01调用耗时5.583ms,其中数据库耗时3.407ms。没有其它分布式调用。

设计一个复杂的案例,假设有一个接口api04,在api04中,分别调用api03和api02接口,而在api02中又调用api01接口。调用http://127.0.0.1:8004/api/v2/api04, 来看看zipkin跟踪效果:
在这里插入图片描述
是不是很酷,整个调用链都清晰的显示出来,可以非常直观的看到api04的耗时,包括其内部分布式子调用的顺序和耗时,而我们要做的仅仅是添加几行zipkin配置代码。完整案例代码见文章顶部。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值