Zipkin的使用 冷不防 2022-05-24 09:26 352阅读 0赞 我这边在初识Zipkin的时候使用了这样一个策略,在阿里云服务器上启动zipkin,然后在本地4个测试项目上配置Zipkin节点,进行一个服务间调用的监控。 ### 1、首先在服务器上启动Zipkin ### 这个详见[上一章节内容][Link 1] ### 2、建立测试项目 ### 建立4个项目`zipkin`,`zipkin2`,`zipkin3`,`zipkin4`,下面以zipkin项目为例,brave作为各调用链路,只需要负责将指定格式的数据发送给zipkin即可,利用brave可快捷完成操作,这里利用idea创建`springboot`工程: ##### 1)、添加pom依赖 ##### <dependency> <groupId>io.zipkin.brave</groupId> <artifactId>brave-core</artifactId> <version>3.9.0</version> </dependency> <!-- https://mvnrepository.com/artifact/io.zipkin.brave/brave-http --> <dependency> <groupId>io.zipkin.brave</groupId> <artifactId>brave-http</artifactId> <version>3.9.0</version> </dependency> <dependency> <groupId>io.zipkin.brave</groupId> <artifactId>brave-spancollector-http</artifactId> <version>3.9.0</version> </dependency> <dependency> <groupId>io.zipkin.brave</groupId> <artifactId>brave-web-servlet-filter</artifactId> <version>3.9.0</version> </dependency> <dependency> <groupId>io.zipkin.brave</groupId> <artifactId>brave-okhttp</artifactId> <version>3.9.0</version> </dependency> ##### 2)、添加配置项 ##### 可以在配置文件`application.properties`中配置相关信息 com.zipkin.serviceName=service1 com.zipkin.url=http://106.14.150.41:9411 com.zipkin.connectTimeout=6000 com.zipkin.readTimeout=6000 com.zipkin.flushInterval=1 com.zipkin.compressionEnabled=true server.port=8080 这里的`http://106.14.150.41:9411`你需要替换成你的Zipkin所在的ip。 ##### 3)、添加自定义配置项对应的java类 ##### package com.example.zipkin; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; /** * @description: 自定义配置项对应配置类 * @author: chenyang * @create: 2018-05-23 **/ @Data @Configuration @ConfigurationProperties(prefix = "com.zipkin") public class ZipkinProperties { private String serviceName; private String url; private int connectTimeout; private int readTimeout; private int flushInterval; private boolean compressionEnabled; } ##### 4)、创建Zipkin的配置类 ##### package com.example.zipkin4; import com.github.kristofa.brave.Brave; import com.github.kristofa.brave.EmptySpanCollectorMetricsHandler; import com.github.kristofa.brave.Sampler; import com.github.kristofa.brave.SpanCollector; import com.github.kristofa.brave.http.DefaultSpanNameProvider; import com.github.kristofa.brave.http.HttpSpanCollector; import com.github.kristofa.brave.okhttp.BraveOkHttpRequestResponseInterceptor; import com.github.kristofa.brave.servlet.BraveServletFilter; import okhttp3.OkHttpClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @description: Zipkin配置类 * @author: chenyang * @create: 2018-05-23 **/ @Configuration public class ZipkinConfig { @Autowired private ZipkinProperties properties; @Bean public SpanCollector spanCollector() { HttpSpanCollector.Config config = HttpSpanCollector.Config.builder().connectTimeout(properties.getConnectTimeout()).readTimeout(properties.getReadTimeout()) .compressionEnabled(properties.isCompressionEnabled()).flushInterval(properties.getFlushInterval()).build(); return HttpSpanCollector.create(properties.getUrl(), config, new EmptySpanCollectorMetricsHandler()); } @Bean public Brave brave(SpanCollector spanCollector){ Brave.Builder builder = new Brave.Builder(properties.getServiceName()); //指定state builder.spanCollector(spanCollector); builder.traceSampler(Sampler.ALWAYS_SAMPLE); Brave brave = builder.build(); return brave; } @Bean public BraveServletFilter braveServletFilter(Brave brave){ BraveServletFilter filter = new BraveServletFilter(brave.serverRequestInterceptor(),brave.serverResponseInterceptor(),new DefaultSpanNameProvider()); return filter; } @Bean public OkHttpClient okHttpClient(Brave brave){ OkHttpClient client = new OkHttpClient.Builder() .addInterceptor(new BraveOkHttpRequestResponseInterceptor(brave.clientRequestInterceptor(), brave.clientResponseInterceptor(), new DefaultSpanNameProvider())) .build(); return client; } } ###### bean介绍(可以先跳过) ###### * `SpanCollector` @Bean public SpanCollector spanCollector() { HttpSpanCollector.Config config = HttpSpanCollector.Config.builder().connectTimeout(properties.getConnectTimeout()).readTimeout(properties.getReadTimeout()) .compressionEnabled(properties.isCompressionEnabled()).flushInterval(properties.getFlushInterval()).build(); return HttpSpanCollector.create(properties.getUrl(), config, new EmptySpanCollectorMetricsHandler()); } 从名称上看HttpSpanCollector是基于http的span收集器,因此超时配置是必须的,默认给出的超时时间较长,flushInterval表示span的传递 间隔,实际为定时任务执行的间隔时间.在HttpSpanCollector中覆写了父类方法sendSpans @Override protected void sendSpans(byte[] json) throws IOException { // intentionally not closing the connection, so as to use keep-alives HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection(); connection.setConnectTimeout(config.connectTimeout()); connection.setReadTimeout(config.readTimeout()); connection.setRequestMethod("POST"); connection.addRequestProperty("Content-Type", "application/json"); if (config.compressionEnabled()) { connection.addRequestProperty("Content-Encoding", "gzip"); ByteArrayOutputStream gzipped = new ByteArrayOutputStream(); try (GZIPOutputStream compressor = new GZIPOutputStream(gzipped)) { compressor.write(json); } json = gzipped.toByteArray(); } connection.setDoOutput(true); connection.setFixedLengthStreamingMode(json.length); connection.getOutputStream().write(json); try (InputStream in = connection.getInputStream()) { while (in.read() != -1) ; // skip } catch (IOException e) { try (InputStream err = connection.getErrorStream()) { if (err != null) { // possible, if the connection was dropped while (err.read() != -1) ; // skip } } throw e; } } } 可以看出最终span信息是通过HttpURLConnection实现的,同样道理就可以推理brave对brave-spring-resttemplate-interceptors模块的实现, 只是换了一种http封装。 * `Brave` @Bean public Brave brave(SpanCollector spanCollector){ Brave.Builder builder = new Brave.Builder(properties.getServiceName()); //指定state builder.spanCollector(spanCollector); builder.traceSampler(Sampler.ALWAYS_SAMPLE); Brave brave = builder.build(); return brave; } Brave类包装了各种工具类 public Brave build() { return new Brave(this); } 创建一个Brave private Brave(Builder builder) { serverTracer = ServerTracer.builder() .randomGenerator(builder.random) .spanCollector(builder.spanCollector) .state(builder.state) .traceSampler(builder.sampler).build(); clientTracer = ClientTracer.builder() .randomGenerator(builder.random) .spanCollector(builder.spanCollector) .state(builder.state) .traceSampler(builder.sampler).build(); localTracer = LocalTracer.builder() .randomGenerator(builder.random) .spanCollector(builder.spanCollector) .spanAndEndpoint(SpanAndEndpoint.LocalSpanAndEndpoint.create(builder.state)) .traceSampler(builder.sampler).build(); serverRequestInterceptor = new ServerRequestInterceptor(serverTracer); serverResponseInterceptor = new ServerResponseInterceptor(serverTracer); clientRequestInterceptor = new ClientRequestInterceptor(clientTracer); clientResponseInterceptor = new ClientResponseInterceptor(clientTracer); serverSpanAnnotationSubmitter = AnnotationSubmitter.create(SpanAndEndpoint.ServerSpanAndEndpoint.create(builder.state)); serverSpanThreadBinder = new ServerSpanThreadBinder(builder.state); clientSpanThreadBinder = new ClientSpanThreadBinder(builder.state); } 封装了\*Tracer,\*Interceptor,\*Binder等。其中 serverTracer当服务作为服务端时处理span信息,clientTracer当服务作为客户端时处理span信息 * `Filter` BraveServletFilter是http模块提供的拦截器功能,传递serverRequestInterceptor,serverResponseInterceptor,spanNameProvider等参数 其中spanNameProvider表示如何处理span的名称,默认使用method名称,spring boot中申明的filter bean 默认拦截所有请求 详情见:[https://blog.csdn.net/liaokailin/article/details/52077620][https_blog.csdn.net_liaokailin_article_details_52077620] -------------------- ##### 5)、创建Controller对外提供服务 ##### package com.example.zipkin; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.io.IOException; import java.util.Random; import java.util.concurrent.TimeUnit; /** * @description: ${description} * @author: chenyang * @create: 2018-05-23 **/ @RestController public class HomeController { @Autowired private OkHttpClient client; private Random random = new Random(); @RequestMapping("/start") public String start() throws InterruptedException, IOException { int sleep= random.nextInt(100); TimeUnit.MILLISECONDS.sleep(sleep); Request request = new Request.Builder().url("http://localhost:8081/service2").get().build(); Response response = client.newCall(request).execute(); return "[service1]:" + response.body().toString(); } } `HomeController`中利用`OkHttpClient`调用发起http请求。在每次发起请求时则需要通过`brave`记录`Span`信息,并异步传递给`zipkin` 到这里,service1就写好了。同样的道理,其他的工程就修改配置文件(调整`com.zipkin.serviceName`,以及`server.port`)以及`controller`对应的方法构造若干服务。 下面是其他zipkin区别于第一个项目的地方: `zipkin2`: * `HomeController` @RequestMapping("/service2") public String foo() throws InterruptedException, IOException { int sleep= random.nextInt(100); TimeUnit.MILLISECONDS.sleep(sleep); Request request = new Request.Builder().url("http://localhost:8082/service3").get().build(); //service3 Response response = client.newCall(request).execute(); String result = response.body().string(); request = new Request.Builder().url("http://localhost:8083/service4").get().build(); //service4 response = client.newCall(request).execute(); result += response.body().string(); return "[service2]:" + result; } * `application.properties` com.zipkin.serviceName=service2 com.zipkin.url=http://106.14.150.41:9411 com.zipkin.connectTimeout=6000 com.zipkin.readTimeout=6000 com.zipkin.flushInterval=1 com.zipkin.compressionEnabled=true server.port=8081 -------------------- `zipkin3`: * `HomeController` @RequestMapping("/serivce3") public String bar() throws InterruptedException, IOException { //service3 method int sleep= random.nextInt(100); TimeUnit.MILLISECONDS.sleep(sleep); return " [service3 sleep: " + sleep+" ms]"; } * `application.properties` com.zipkin.serviceName=service3 com.zipkin.url=http://106.14.150.41:9411 com.zipkin.connectTimeout=6000 com.zipkin.readTimeout=6000 com.zipkin.flushInterval=1 com.zipkin.compressionEnabled=true server.port=8082 -------------------- `zipkin4`: * `HomeController` @RequestMapping("/service4") public String tar() throws InterruptedException, IOException { //service4 method int sleep= random.nextInt(1000); TimeUnit.MILLISECONDS.sleep(sleep); return " [service4 sleep :" + sleep+" ms]"; } * `application.properties` com.zipkin.serviceName=service4 com.zipkin.url=http://106.14.150.41:9411 com.zipkin.connectTimeout=6000 com.zipkin.readTimeout=6000 com.zipkin.flushInterval=1 com.zipkin.compressionEnabled=true server.port=8083 最后,分别启动`zipkin`,`zipkin2`,`zipkin3`,`zipkin4`,在游览器调用`http://localhost:8080/start` 登录`web ui`界面查看`Zipkin`:`http://你的部署的IP:9411/zipkin` ![这里写图片描述][70] ![这里写图片描述][70 1] [Link 1]: https://blog.csdn.net/qq_20989105/article/details/80430356 [https_blog.csdn.net_liaokailin_article_details_52077620]: https://blog.csdn.net/liaokailin/article/details/52077620 [70]: /images/20220524/7eee6a479fee40a3a35b79a552192abe.png [70 1]: /images/20220524/12509f976b8a4e5aacf0ee06ceb403cd.png
还没有评论,来说两句吧...