继上一篇 添加链接描述我们简单搭建了关于springcloud的服务链路追踪与分析,本篇我们在此基础上加入rabbitmq的整合,从而搭建一套简易的使用rabbitmq进行服务追踪的框架;
正常情况下,zipkin的原理是,服务之间的调用关系会通过http的方式上报到zipkin-server,然后交由zipkin-server管理服务之间的调用关系链,然后我们通过ui界面去追踪服务之间的调用链路,
但这样做可能存在一个问题就是,如果哪天在某个服务调用另外一个服务端额时候,调用链路上出现网络的闪断或者其他故障,层级简单的调用还容易排查定位,但是调用层级复杂的话这就有点儿坑了,这样一来,zipkin-server由于服务无法追踪而导致问题无从排查,
试想,某个服务在调用另外一个服务的时候,除了zipkin-server,还能通过某个消息存储的容器将本次调用其他服务的消息数据进行持久化存储,这样不就可以解决问题吗?这就是使用zipkin配合rabbitMq进行服务追踪的来源,即服务之间的调用关系不仅发到zipkin-server,而且还会发到mq中,当然也可以使用mysql进行存储,原理都类似,了解了这个原理,下面我们就开始整合使用的搭建;
这里我们使用官方的jar包进行启动,注意的是,这里加入了rabbitMq,因此启动的参数要加上mq的命令,如下,这个是默认的,默认情况下,使用guest即可
java -jar zipkin-server-2.11.8-exec.jar --zipkin.collector.rabbitmq.addresses=localhost
如果是自己指定的用户名和密码可以参考下面的启动命令,
java -jar zipkin-server-2.11.8-exec.jar --zipkin.collector.rabbitmq.addresses=localhost --zipkin.collector.rabbitmq.username=guest --zipkin.collector.rabbitmq.password=guest
启动顺利的话,我们再去rabbitMq的管控台上可以看到,多了一个zipkin的队列,
同时可以浏览器访问zipkin-ui界面,http://localhost:9411/zipkin/
第二个不是必须的,
org.springframework.cloud
spring-cloud-stream-binder-rabbit
org.springframework.boot
spring-boot-starter-amqp
但是我看到网上有些资料加了下面的配置,可能是版本的原因,但是不影响使用,现贴出来供参考
#如果是使用rabbitmq则需要下面的配置
spring.zipkin.sender.type= rabbit
#添加rabbitmq的配置
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.poassword=guest
spring.rabbitmq.listener.direct.retry.enabled=true
spring.rabbitmq.listener.simple.retry.enabled=true
这里说明一下,为了模拟服务之间的调用,这里在service-b中有一个接口,接口的数据需要调用service-b,下面贴出主要的代码,
service-a
@Autowired
private RestTemplate restTemplate;
@RequestMapping("/getServerPort")
@ResponseBody
public String getMember() {
//String url = "http://PROVIDER2/getMsgFromProvider2";
//String result = restTemplate.getForObject(url, String.class);
//System.out.println("restTemplate 调用 第二个服务提供者的服务 服务提供者服务 :" + result);
String result = "我是服务提供者1";
return result;
}
就是一个简单的测试接口,再看service-b,
@RequestMapping("/getFromProvider")
public String getFromProvider() {
// 有两种方式,一种是采用服务别名方式调用,另一种是直接调用 使用别名去注册中心上获取对应的服务调用地址
String url = "http://PROVIDER1/getServerPort";
String result = restTemplate.getForObject(url, String.class);
System.out.println("restTemplate 调用 服务提供者服务 :" + result);
return result;
}
然后我们在浏览器输入url,http://localhost:8102/getFromProvider,可以看到,调用成功了,
这时候再到zipkin-ui界面可以查到刚刚调用的过程,
怎么知道消息发送到了rabbitmq了呢?网上一些资料给出的答案在这个地方都是模棱两可,含糊不清的,我自己测试的时候也发现了,不管怎么快速切换窗口,也没有看到队列里面的消息,但是下面的这个截图却反映了,在某个时间节点确实有消息存在,可能底层使用的是非持久化队列,即一旦消息确认后就从队列删掉了,这个问题以后可以深入的研究下,
但是为了解除心中的疑惑,我还是想了个办法,既然看不到消息的投递过程,我总可以监听这个队列吧?于是在demo中添加了如下的消息监听的代码,如下,
@Component
public class RabbitListener {
@org.springframework.amqp.rabbit.annotation.RabbitListener(queues = "zipkin")
private void handleMessage(Message message){
String messageBody = new String(message.getBody());
System.out.println("收到了消息是 : " + messageBody);
}
}
然后再在浏览器调用一下接口,这时候可以看到控制台输出如下信息,
把这段信息格式化一下后再看,是不是很熟悉,没错,这就是在zipkin-ui界面上的那些服务追踪的调用原始数据啊,
{
"traceId": "62a188578548b630",
"parentId": "62a188578548b630",
"id": "5285419bdf818c1b",
"kind": "CLIENT",
"name": "get",
"timestamp": 1568376783321306,
"duration": 2942299,
"localEndpoint": {
"serviceName": "consumer1",
"ipv4": "192.168.9.184"
},
"tags": {
"http.method": "GET",
"http.path": "/getServerPort"
}
}, {
"traceId": "62a188578548b630",
"id": "62a188578548b630",
"kind": "SERVER",
"name": "get",
"timestamp": 1568376782888402,
"duration": 3473998,
"localEndpoint": {
"serviceName": "consumer1",
"ipv4": "192.168.9.184"
},
"remoteEndpoint": {
"ipv6": "::1",
"port": 52465
},
"tags": {
"http.method": "GET",
"http.path": "/getFromProvider",
"mvc.controller.class": "ConsumerController",
"mvc.controller.method": "getFromProvider"
}
}
也就是说,案例中的两个服务之间在互相调用的时候,确实不仅将数据发送到了zipkin-server,也发到了rabbitMq的zipkin队列中去了,即通过这种方式,实现了微服务调用链路上数据的存储与解耦,即使网络断掉,消息依然可以追踪,本篇到这里就结束了,最后感谢观看!
附上源码和zipkin的jar包地址,如有需要可以前往下载:https://download.csdn.net/download/zhangcongyi420/11739881