前言:
一些感念:
- Span:基本工作单元,例如,在一个新建的span中发送一个RPC等同于发送一个回应请求给RPC,span通过一个64位ID唯一标识,trace以另一个64位ID表示,span还有其他数据信息,比如摘要、时间戳事件、关键值注释(tags)、span的ID、以及进度ID(通常是IP地址)
span在不断的启动和停止,同时记录了时间信息,当你创建了一个span,你必须在未来的某个时刻停止它。 - Trace:一系列spans组成的一个树状结构,例如,如果你正在跑一个分布式大数据工程,你可能需要创建一个trace。
- Annotation:用来及时记录一个事件的存在,一些核心annotations用来定义一个请求的开始和结束
- cs - Client Sent -客户端发起一个请求,这个annotion描述了这个span的开始
- sr - Server Received -服务端获得请求并准备开始处理它,如果将其sr减去cs时间戳便可得到网络延迟
- ss - Server Sent -注解表明请求处理的完成(当请求返回客户端),如果ss减去sr时间戳便可得到服务端需要的处理请求时间
- cr - Client Received -表明span的结束,客户端成功接收到服务端的回复,如果cr减去cs时间戳便可得到客户端从服务端获取回复的所有所需时间
将Span和Trace在一个系统中使用Zipkin注解的过程图形化:
代码:
在springboot2.0,springcloud Finchley版本,不允许自己建zipkin server了,可以用jar包自己跑,也可以直接用docker运行,https://github.com/openzipkin/zipkin#quick-start 地址。
我就用docker了
docker run -d -p 9411:9411 --name zipkin openzipkin/zipkin
启动后访问 http://192.168.94.151:9411/zipkin/
然后创建一个eureka,一个两个有调用关系的为服务
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>springcloud16-zipkin</artifactId> <groupId>com.xhx.springcloud</groupId> <version>0.0.1-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>eureka-server</artifactId> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> </dependencies> </project>
application.yml
spring: application: name: eureka-server server: port: 8761 eureka: instance: hostname: localhost client: register-with-eureka: false fetch-registry: false service-url: default-zone: http://${eureka.instance.hostname}:${server.port}/eureka
启动类:
package com.xhx.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; /** * xuhaixing * 2018/6/16 16:34 */ @SpringBootApplication @EnableEurekaServer public class EurekaServerApplication { public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class,args); } }
pom.xml,增加sleuth和zipkin两个包
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>springcloud16-zipkin</artifactId> <groupId>com.xhx.springcloud</groupId> <version>0.0.1-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>user-service</artifactId> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-sleuth</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zipkin</artifactId> </dependency> </dependencies> </project>
application.yml,base-url指定zipkin的地址
spring: application: name: user-service zipkin: base-url: http://192.168.94.151:9411 #discovery-client-enabled: true # service: #name: zipkin-service enabled: true server: port: 8080 eureka: client: service-url: default-zone: http://locahost:8761/eureka feign: hystrix: enabled: true
启动类:
package com.xhx.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.cloud.client.SpringCloudApplication; import org.springframework.cloud.openfeign.EnableFeignClients; /** * xuhaixing * 2018/6/16 17:04 */ @SpringCloudApplication @EnableFeignClients public class UserServiceApplication { public static void main(String[] args) { SpringApplication.run(UserServiceApplication.class,args); } }提供接口的controller
package com.xhx.springcloud.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import java.util.HashMap; import java.util.Map; /** * xuhaixing * 2018/6/16 17:09 */ @RestController @RequestMapping(value = "user") public class UserController { @RequestMapping(value = "getUserInfo",method = RequestMethod.POST) public Map<String, String> getUserInfo(){ Map<String,String> user = new HashMap<>(); user.put("name","xuhaixing"); user.put("gender","man"); return user; } }
服务消费者
pom.xml和前面一样加入sleuth和zipkin
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>springcloud16-zipkin</artifactId> <groupId>com.xhx.springcloud</groupId> <version>0.0.1-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>order-service</artifactId> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-sleuth</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-sleuth-zipkin</artifactId> </dependency> </dependencies> </project>
application.yml
probability是被zipkin收集的概率,1为全部收集,因为现在是直接用http方式发送数据并且放在内存中,所以会影响性能。可以用消息队列或者mysql收集服务链路信息。
spring: application: name: order-service zipkin: #discovery-client-enabled: true #service: #name: zipkin-service enabled: true base-url: http://192.168.94.151:9411 sleuth: sampler: probability: 1 server: port: 8086 eureka: client: service-url: default-zone: http://locahost:8761/eureka feign: hystrix: enabled: true
feign
package com.xhx.springcloud.api; import com.alibaba.fastjson.JSONObject; import com.xhx.springcloud.hystrix.UserInfoApiHytrix; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import java.util.Map; /** * xuhaixing * 2018/6/16 17:19 */ @FeignClient(value = "user-service",path = "user",fallback = UserInfoApiHytrix.class) public interface UserInfoApi { @RequestMapping(value = "getUserInfo",method = RequestMethod.POST) JSONObject getUserInfo(); }
controller
package com.xhx.springcloud.controller; import com.alibaba.fastjson.JSONObject; import com.xhx.springcloud.api.UserInfoApi; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import java.util.Optional; /** * xuhaixing * 2018/6/16 17:19 */ @RestController @RequestMapping(value = "order") public class OrderController { @Autowired private UserInfoApi userInfoApi; @RequestMapping(value = "getUserOrder",method = RequestMethod.POST) public JSONObject getUserOrder(){ JSONObject userInfo = userInfoApi.getUserInfo(); Optional.ofNullable(userInfo).ifPresent(user->user.put("orderMoney",999)); return userInfo; } }
hystrix
package com.xhx.springcloud.hystrix; import com.alibaba.fastjson.JSONObject; import com.xhx.springcloud.api.UserInfoApi; import org.springframework.stereotype.Component; import java.util.Map; /** * xuhaixing * 2018/6/16 17:20 */ @Component public class UserInfoApiHytrix implements UserInfoApi { @Override public JSONObject getUserInfo() { return null; } }
请求一下
打开zipkin