zipkin实现SpringCloud链路追踪 快来打我* 2024-04-17 06:03 15阅读 0赞 ## 一、概述 ## 在微服务架构中,涉及服务与服务间的依赖关系非常复杂,SpringCloud 官方推荐 sleuth + zipkin 方式实现链路追踪,zipkin web 管理页面中,可以每个请求的依赖关系、请求时间、返回时间、服务与服务间的依赖图等。 在本文中主要介绍两种服务依赖情况 * 微服务调用微服务 * 微服务通过RabbitMQ发送消息 环境依赖: <table> <thead> <tr> <th>名称</th> <th>值</th> <th>备注</th> </tr> </thead> <tbody> <tr> <td>JDK</td> <td>1.8</td> <td></td> </tr> <tr> <td>RabbitMQ</td> <td>3.5.6</td> <td>在演示中需要启用RabbitMQ,详细介绍 https://blog.csdn.net/qq_36918149/article/details/100006373</td> </tr> <tr> <td>SpringCloud</td> <td>Greenwich.SR1</td> <td></td> </tr> <tr> <td>Consul</td> <td>1.5.2</td> <td>注册中心,Consul安装及介绍 https://mp.csdn.net/mdeditor/95372805#</td> </tr> <tr> <td>zipkin</td> <td>最新版</td> <td>zipkin安装配置 https://mp.csdn.net/mdeditor/100068323#</td> </tr> </tbody> </table> 演示数据流转图: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2OTE4MTQ5_size_16_color_FFFFFF_t_70] customer-service 请求下单 waiter-service 生产订单,MQ通知barista-service制作咖啡,咖啡制作完成后MQ通知customer-service取coffee barista-service 制作coffee,制作完成后MQ通知waiter-service ## 二 、代码 ## **2.1 zipkin 启动并连上RabbitMQ** java -jar zipkin.jar --zipkin.collector.rabbitmq.addresses=100.61.11.211:5672 **2.2 customer-service (顾客服务)** **1 ) 主要pom依赖** <properties> <java.version>1.8</java.version> <spring-cloud.version>Greenwich.SR1</spring-cloud.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-httpclient</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-stream-rabbit</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zipkin</artifactId> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.7</version> </dependency> </dependencies> **2 ) 配置文件** application.properties spring.application.name=customer-service server.port=8090 customer.name=spring-${server.port} #zipkin 地址 spring.zipkin.base-url=http://127.0.0.1:9411/ #zipkin 日志采样比例 spring.sleuth.sampler.probability=1.0 #zipkin 推送方式 spring.zipkin.sender.type=web # spring总是输出日志 spring.output.ansi.enabled=ALWAYS #rabbitmq配置 spring.rabbitmq.host=100.61.11.211 spring.rabbitmq.port=5672 spring.rabbitmq.username=1234567 spring.rabbitmq.password=1234567 # 名称为:notifyOrders 的Exchange绑定消费端路由key为spring-8090 spring.cloud.stream.rabbit.bindings.notifyOrders.consumer.binding-routing-key=${customer.name} **3 ) CoffeeOrderService (rpc调用waiter-service接口)** @FeignClient(name = "waiter-service", contextId = "coffeeOrder") public interface CoffeeOrderService { @PostMapping("/order/{id}") boolean createOrder(@PathVariable("id") Long id); } **4 ) CustomerController(客户订单触发接口)** @RestController @RequestMapping("/customer") @Slf4j public class CustomerController { @Autowired private CoffeeOrderService coffeeOrderService; @PostMapping(value = "/create/order/{id}") public Boolean createOrder(@PathVariable("id") Long id){ log.info("customer create order no: {}",id); return coffeeOrderService.createOrder(id); } **5 ) Waiter (服务启动时消息绑定接口)** public interface Waiter { String NOTIFY_ORDERS = "notifyOrders"; @Input(NOTIFY_ORDERS) SubscribableChannel notification(); } **6 ) NotificationListener(接受coffee订单用餐通知)** @Component @Slf4j public class NotificationListener { @StreamListener(Waiter.NOTIFY_ORDERS) public void takeOrder(@Payload Long id) { log.info("Order No: {} is Fish, I'll take it.", id); } } **7 ) CustomerServiceApplication 启动类** @SpringBootApplication @Slf4j @EnableDiscoveryClient @EnableFeignClients @EnableAspectJAutoProxy @EnableBinding(Waiter.class) public class CustomerServiceApplication { public static void main(String[] args) { SpringApplication.run(CustomerServiceApplication.class, args); } @Bean public CloseableHttpClient httpClient() { return HttpClients.custom() .setConnectionTimeToLive(30, TimeUnit.SECONDS) .evictIdleConnections(30, TimeUnit.SECONDS) .setMaxConnTotal(200) .setMaxConnPerRoute(20) .disableAutomaticRetries() .setKeepAliveStrategy(new CustomConnectionKeepAliveStrategy()) .build(); } } 备注:@EnableBinding(Waiter.class) 绑定了MQ接口 **2.3 waiter-service(服务员服务)** **1 ) 主要pom依赖** <properties> <java.version>1.8</java.version> <spring-cloud.version>Greenwich.SR1</spring-cloud.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-config</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-stream-rabbit</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zipkin</artifactId> </dependency> </dependencies> **2 ) 配置文件** application.properties spring.application.name=customer-service server.port=8080 #zipkin 地址 spring.zipkin.base-url=http://127.0.0.1:9411/ #zipkin 日志采样比例 spring.sleuth.sampler.probability=1.0 #zipkin 推送方式 spring.zipkin.sender.type=web # spring总是输出日志 spring.output.ansi.enabled=ALWAYS #rabbitmq配置 spring.rabbitmq.host=100.61.11.211 spring.rabbitmq.port=5672 spring.rabbitmq.username=1234567 spring.rabbitmq.password=1234567 #Exchange 交换机: finishedOrders 绑定到Queue 队列: finishedOrders.waiter-service spring.cloud.stream.bindings.finishedOrders.group=waiter-service #notifyOrders 生产者路由根据 headers.customer spring.cloud.stream.rabbit.bindings.notifyOrders.producer.routing-key-expression=headers.customer **3 ) Barista(服务启动时消息绑定接口)** public interface Barista { String NEW_ORDERS = "newOrders"; String FINISHED_ORDERS = "finishedOrders"; @Input SubscribableChannel finishedOrders(); @Output MessageChannel newOrders(); } **4 ) Customer(服务启动时消息绑定接口)** public interface Customer { String NOTIFY_ORDERS = "notifyOrders"; @Output(NOTIFY_ORDERS) MessageChannel notification(); } **5 ) CoffeeOrderController(提供rpc下单接口,及给barista发下单MQ)** @RestController @RequestMapping("/order") @Slf4j public class CoffeeOrderController { @Autowired private Barista barista; @PostMapping("/{id}") public boolean createOrder(@PathVariable( "id") Long id){ // 通知咖啡师有新的coffee有新的订单 barista.newOrders().send(MessageBuilder.withPayload(id).build()); return true ; } } **6 ) OrderListener(监听咖啡完成MQ及给customer-service 发取餐MQ)** @Component @Slf4j public class OrderListener { @Autowired private Customer customer; @Autowired private CoffeeOrderService orderService; @StreamListener(Barista.FINISHED_ORDERS) public void listenFinishedOrders(Long id) { log.info("We've finished an order no [{}].", id); String customerName = "张三"; Message<Long> message = MessageBuilder.withPayload(id) .setHeader("customer", customerName) .build(); log.info("Notify the customer: {}", customerName); customer.notification().send(message); } } **7 ) WaiterServiceApplication启动类(绑定启动了对应MQ接口)** @SpringBootApplication @EnableDiscoveryClient @EnableBinding({ Barista.class, Customer.class }) public class WaiterServiceApplication implements WebMvcConfigurer { public static void main(String[] args) { SpringApplication.run(WaiterServiceApplication.class, args); } } 备注:@EnableBinding(\{ Barista.class, Customer.class \}) 这里是在绑定相应的MQ **2.4 barista-service(制作coffee服务)** **1 ) 主要pom依赖** <properties> <java.version>1.8</java.version> <spring-cloud.version>Greenwich.SR1</spring-cloud.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-stream-binder-rabbit</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zipkin</artifactId> </dependency> </dependencies> **2 ) 配置文件** application.properties #服务名称 spring.application.name=barista-service #服务端口,0表示随机端口 server.port=0 #总是推送链路到zipkin中 spring.output.ansi.enabled=ALWAYS #zipkin中日志抽样比例 spring.sleuth.sampler.probability=1.0 #zipkin中采集日志的模式 spring.zipkin.sender.type=rabbit #actuator 相关配置 management.endpoints.web.exposure.include=* management.endpoint.health.show-details=always spring.rabbitmq.host=100.61.11.211 spring.rabbitmq.port=5672 spring.rabbitmq.username=1234567 spring.rabbitmq.password=1234567 #生成名称为newOrders的exchange,并绑定到 名称为 newOrders.barista-service 的Queue 上 spring.cloud.stream.bindings.newOrders.group=barista-service **3 ) Waiter (服务启动时消息绑定接口)** public interface Waiter { String NEW_ORDERS = "newOrders"; String FINISHED_ORDERS = "finishedOrders"; @Input(NEW_ORDERS) SubscribableChannel newOrders(); @Output(FINISHED_ORDERS) MessageChannel finishedOrders(); } **4 ) OrderListener (消息监听及发送类)** @Component @Slf4j public class OrderListener { @Autowired @Qualifier(Waiter.FINISHED_ORDERS) private MessageChannel finishedOrdersMessageChannel; @StreamListener(Waiter.NEW_ORDERS) public void processNewOrder(Long id) { log.info("Barista start make coffer order no {} .", id); try { Thread.sleep(200L); } catch (Exception e) { } finishedOrdersMessageChannel.send(MessageBuilder.withPayload(id).build()); log.info("Barista notify Waiter finish coffee order no {} .", id); } } **5 ) BaristaServiceApplication(启动类)** @EnableJpaRepositories @SpringBootApplication @EnableBinding(Waiter.class) public class BaristaServiceApplication { public static void main(String[] args) { SpringApplication.run(BaristaServiceApplication.class, args); } } 注意:@EnableBinding(Waiter.class) 是绑定消息接口。 ## 三、结果演示 ## **3.1 客户下单** url :http://localhost:8090/customer/create/order/230 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2OTE4MTQ5_size_16_color_FFFFFF_t_70 1] **3.2 服务调用链路** ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2OTE4MTQ5_size_16_color_FFFFFF_t_70 2] **3.3 服务依赖关系图** ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2OTE4MTQ5_size_16_color_FFFFFF_t_70 3] **3.4 rabbitMQ** ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2OTE4MTQ5_size_16_color_FFFFFF_t_70 4] ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2OTE4MTQ5_size_16_color_FFFFFF_t_70 5] ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2OTE4MTQ5_size_16_color_FFFFFF_t_70 6] ## 四、总结 ## 1)在项目中,可以通过http 向zipkin推送链路信息, 但是如果在生成环境数据量太大势必会有性能问题; 2)zipkin 关于海量日志数据如何保存, 还需在后期研究一下。 [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2OTE4MTQ5_size_16_color_FFFFFF_t_70]: https://image.dandelioncloud.cn/pgy_files/images/2024/04/16/af8387c2ea5b4ad7acda249bb7c755b9.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2OTE4MTQ5_size_16_color_FFFFFF_t_70 1]: https://image.dandelioncloud.cn/pgy_files/images/2024/04/16/2ba703d1380c4f4a9f56fdde76fc960e.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2OTE4MTQ5_size_16_color_FFFFFF_t_70 2]: https://image.dandelioncloud.cn/pgy_files/images/2024/04/16/0b6fb3748ac341b3b7e94911ce8d768b.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2OTE4MTQ5_size_16_color_FFFFFF_t_70 3]: https://image.dandelioncloud.cn/pgy_files/images/2024/04/16/29c07cf134ae439795079dd4dc608e78.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2OTE4MTQ5_size_16_color_FFFFFF_t_70 4]: https://image.dandelioncloud.cn/pgy_files/images/2024/04/16/fcc891b50d7140cbb1e1e5211505a931.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2OTE4MTQ5_size_16_color_FFFFFF_t_70 5]: https://image.dandelioncloud.cn/pgy_files/images/2024/04/16/48b1d474528a4f93bca153c513037a36.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2OTE4MTQ5_size_16_color_FFFFFF_t_70 6]: https://image.dandelioncloud.cn/pgy_files/images/2024/04/16/7aa205d9a8f84bc6bcd6a8dc3c30532d.png
还没有评论,来说两句吧...