# springcloud_demo **Repository Path**: liu_fei_4552/springcloud_demo ## Basic Information - **Project Name**: springcloud_demo - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-08-30 - **Last Updated**: 2021-09-07 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 学习springcloud所搭建 ## eureka显示注册ip ##### 在服务提供者,通过instance.instance-id配置控制台显示服务ip ## eureka服务剔除问题 ##### 默认每隔30秒发送一次心跳,如果90秒内没有发送心跳就认为宕机,在服务的提供者设置心跳间隔,设置续约到期时间 ## eureka的自我保护机制(统计宕机服务超过百分之八十五就会自动启用自我保护,不再提出服务) ```yaml server: enable-self-preservation: false #关闭自我保护机制 eviction-interval-timer-in-ms: 4000 #设置提出服务间隔 ``` ### 上面参数只是建议开发时使用,生产保持默认值就好 #### Ribbon 就是一个负载均衡器,有助于控制HTTP和TCP客户端行为。在SpringCloud中,Eureka一般配合Ribbon进行使用,Ribbon提供了客户端负载均衡的功能,Ribbon利用从Eureka中读取到的服务信息,在调用服务节点提供的服务时,会合理的进行负载。 #### 1. 服务调用 :基于Ribbon实现服务调用,是通过拉取到的所有服务列表组成(服务名-请求路径的)映射关系。借助RestTemplate最终进行调用 #### 2. 负载均衡(服务端的负载均衡:nginx f5;客户端的负载均衡:Ribbon是一个典型的客户端负载均衡器,Ribbon会获取服务的所有地址,根据内部的负载均衡算法获取本次请求的有效地址) * com.netflix.loadbalancer.RoundRobinRule :以轮询的方式进行负载均衡。 * com.netflix.loadbalancer.RandomRule :随机策略 * com.netflix.loadbalancer.RetryRule :重试策略。 * com.netflix.loadbalancer.WeightedResponseTimeRule :权重策略。会计算每个服务的权 重,越高的被调用的可能性越大。 * com.netflix.loadbalancer.BestAvailableRule :最佳策略。遍历所有的服务实例,过滤掉 故障实例,并返回请求数最小的实例返回。 * com.netflix.loadbalancer.AvailabilityFilteringRule :可用过滤策略。过滤掉故障和请 求数超过阈值的服务实例,再从剩下的实力中轮询调用。 ```yaml service-product: ribbon: NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule ``` ### 重试机制 ```xml org.springframework.retry spring-retry ``` ```yaml service-product: ribbon: #重试配置 ConnectTimeout: 250 # Ribbon的连接超时时间 ReadTimeout: 1000 # Ribbon的数据读取超时时间 OkToRetryOnAllOperations: true # 是否对所有操作都进行重试 MaxAutoRetriesNextServer: 1 # 切换实例的重试次数 MaxAutoRetries: 1 # 对当前实例的重试次数 ``` ## consul注册中心 #### 1.强一致性(cp) #### 2.eureka 最终一致性(ap) ### 安装consul #### 1.下载安装就好了 [consul下载地址](https://www.consul.io/downloads) #### 2.进入开发者模式快速启动 ```shell ##以开发者模式快速启动 consul agent -dev -client=0.0.0.0 ``` #### 3.进入到管理后台界面 http://localhost:8500 ### 将微服务注册到注册中心consul #### 1.添加依赖 ```xml org.springframework.cloud spring-cloud-starter-consul-discovery org.springframework.boot spring-boot-starter-actuator ``` #### 2.yml配置 ```yaml cloud: consul: host: 127.0.0.1 #主机地址 port: 8500 #端口 discovery: register: true #是否需要注册 #注册的实例id(唯一标识) instance-id: ${spring.application.name}-1 #服务名称 service-name: ${spring.application.name} #服务请求端口 port: ${server.port} #指定开启ip地址注册 prefer-ip-address: true #当前服务的请求ip ip-address: ${spring.cloud.client.ip-address} ``` ##### 特别注意在服务起名字时如果使用下划线调用时不通过,可以使用中划线 ### 将微服务注册到注册中心consul ##### 由于SpringCloud对Consul进行了封装。对于在消费者端获取服务提供者信息和Eureka是一致的。同样使用 DiscoveryClient 完成调用获取微服务实例信息 ## consul集群 #### [集群搭建](https://www.bilibili.com/video/BV1eE41187Ug?p=40&spm_id_from=pageDriver) ## Feign组件 #### 1.导入依赖 ```xml org.springframework.cloud spring-cloud-starter-openfeign ``` #### 2.配置调用接口 ```java /** * @ClassNameProductFeignClient * @Description 声明需要调用的微服务名称 * @Author liufei * @Date2021/9/1 14:47 * @Version V1.0 * @FeignClient * name:服务提供者的名称 **/ @FeignClient(name = "service-product") public interface ProductFeignClient { /** * 配置需要调用的微服务接口 */ @RequestMapping(value = "/product/{id}",method = RequestMethod.GET) public Product findById(@PathVariable("id") Long id); } ``` #### 3.在启动类上激活feign ```java @SpringBootApplication @EntityScan("com.java.entity") @EnableEurekaClient @EnableFeignClients public class OrderApplication {} ``` #### 4.通过自动的接口调用远程微服务 ```java @RestController @RequestMapping("/order") @Slf4j public class OrderController { //注入restTemplate对象 @Autowired private RestTemplate restTemplate; /** * 注入DiscoveryClient : * springcloud提供的获取原数组的工具类 * 调用方法获取服务的元数据信息 * */ @Autowired private DiscoveryClient discoveryClient; @Autowired private ProductFeignClient productFeignClient; @RequestMapping(value = "/buy/{id}",method = RequestMethod.GET) public Product findById(@PathVariable Long id) { Product product = null; product =productFeignClient.findById(id); return product; } } ``` ### 5.打印feign日志 ```yaml #配置feign日志的输出 #日志配置: #NONE :不输出日志 #BASIC :适用于生产环境追踪问题 #HEADERS :在BASIC的基础上,记录请求头和响应头信息 #FULL :记录所有 feign: client: config: service-product: loggerLevel: FULL logging: level: com.java.feign.ProductFeignClient: debug ``` ## Hystrix组件 #### 1.对Feign的支持 引入依赖,因为feign中已经包含所以不需要另外增加依赖 #### 2.在fenign的配置文件中开启hystrix ```yaml feign: client: config: service-product: loggerLevel: FULL hystrix: enabled: true ``` #### 3.自定义一个接口实现类,这个实现类就是熔断触发的降级逻辑 ```java /** * @ClassNameProductFeignClientCallBack * @Description * @Author liufei * @Date2021/9/1 18:04 * @Version V1.0 **/ @Component public class ProductFeignClientCallBack implements ProductFeignClient{ /** * *熔断降级的方法 * @param id */ @Override public Product findById(Long id) { Product product=new Product(); product.setProductName("触发降级方法"); return product; } } ``` #### 4.修改feginClient接口添加降级方法的支持 ```java @FeignClient(name = "service-product",fallback = ProductFeignClientCallBack.class) public interface ProductFeignClient {} ``` #### 5.hystrix的超时时间 当在规定的时间内,没有获取到微服务的数据,这个时候会自动的触发熔断降级方法 ```yaml hystrix: command: default: excution: isolation: thread: timeoutInMilliseconds: 3000 #默认的连接超时时间为1秒 ``` #### 6.hystrix监控 #### * 添加坐标 ```xml org.springframework.boot spring-boot-starter-actuator org.springframework.cloud spring-cloud-starter-netflix-hystrix org.springframework.cloud spring-cloud-starter-netflix-hystrix-dashboard ``` #### * 在启动类上激活hystrix ```java //激活hystrix @EnableHystrix ``` #### * 增加配置 ```yaml #hystrix监控所需 management: endpoints: web: exposure: include: '*' ``` #### * 页面上访问 http://localhost:9002/actuator/hystrix.stream #### * 监控地址为 http://localhost:9002/hystrix ### turbine监控系统可以监控所有的想监控的服务 #### * 生产上使用单独的监控服务 监控地址http://localhost:8031/turbine.stream 页面访问地址为 http://localhost:8031/hystrix ## Sentinel组件 #### * Sentinel控制台下载安装 [官网地址](https://github.com/alibaba/Sentinel/releases) #### * 启动命令 ```shell script java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.6.3.jar ``` #### * 启动之后的访问地址为 http://localhost:8080 默认账号和密码都是 sentinel #### * 父pom中增加依赖 ```yaml com.alibaba.cloud spring-cloud-alibaba-dependencies 2.1.0.RELEASE pom import ``` #### * 在需要的项目中增加依赖 ```yaml com.alibaba.cloud spring-cloud-starter-alibaba-sentinel ``` #### * 增加注解编写降级方法 ```java @RestController @RequestMapping("/order") @Slf4j public class OrderController { @Autowired private ProductFeignClient productFeignClient; @RequestMapping(value = "/buy/{id}",method = RequestMethod.GET) /** *@SentinelResource(blockHandler = "orderBlockHandler",fallback = "orderFallback") * blockHandler 熔断执行的方法 * fallback 异常执行的方法 * value 资源名称 不设置就是类名加方法名 */ @SentinelResource(value ="orderBuyId",blockHandler = "orderBlockHandler",fallback = "orderFallback") public Product findById(@PathVariable Long id) { if(id != 1){ throw new RuntimeException("错误"); } Product product = null; product =productFeignClient.findById(id); return product; } /** * 定义降级逻辑 * hystrix和sentinel区别 * hystrix只有一个方法 * sentinel熔断执行熔断的方法、抛出异常执行异常的方法 * @param id * @return */ public Product orderBlockHandler(Long id){ Product product=new Product(); product.setProductName("触发熔断的降级方法"); return product; } public Product orderFallback(Long id){ Product product=new Product(); product.setProductName("触发抛出异常的方法"); return product; } } ``` #### * 加在本地配置规则source下面增加一个json,yml中增加配置 ```yaml cloud: sentinel: transport: dashboard: localhost:8080 datasource: #因为sentinel读取内存中的数据每次项目重启就会导致配置消失,我们可以读取本地资源配置 ds1: file: file: classpath:flowrule.json data-type: json rule-type: flow ``` ## Sentinel对feign支持 #### 1.引入依赖 ```yaml com.alibaba.cloud spring-cloud-starter-alibaba-sentinel ``` #### 1.在yml上打开sentinel 其他的和hystrix一样 ```yaml #激活sentinel的支持 feign: sentinel: enabled: true ``` ## 微服务网关,主要解决客户端需要记录各个微服务的ip地址及出现跨域及各个微服务独立认证登录信息等情况(身份验证、监控、缓存、负载均衡、请求分片、静态响应) ### zuul网关 #### 创建zuul网关服务 #### 增加坐标 ```xml org.springframework.cloud spring-cloud-starter-netflix-zuul ``` #### 增加配置 ```yaml server: port: 8080 #端口 spring: application: name: api-zuul-server #服务名称 ``` #### 开启zull注解 ```java @SpringBootApplication //开启zuul网关功能 @EnableZuulProxy public class ZuulServerApplication { public static void main(String[] args) { SpringApplication.run(ZuulServerApplication.class,args); } } ``` #### 路由:根据请求的url将请求分配到对应的微服务中进行处理 ```yaml # 路由配置 zuul: routes: #商品微服务 product-server: #路由id,随便写 path: /product-service/** #localhost:8080/product-service/***** url: http://127.0.0.1:9011 #映射路径实际对应的微服务 ``` #### 集成eureka ```xml org.springframework.cloud spring-cloud-starter-netflix-eureka-client ``` ```yaml # 路由配置 zuul: routes: #商品微服务 product-server: #路由id,随便写 path: /product-service/** #localhost:8080/product-service/***** #url: http://127.0.0.1:9011 #映射路径实际对应的微服务 serviceId: service-product #配置转发的微服务的服务名称 #配置Eureka eureka: client: service-url: defaultZone: http://localhost:9000/eureka/,http://localhost:8000/eureka/ instance: prefer-ip-address: true #使用ip地址注册 instance-id: ${spring.cloud.client.ip-address}:${server.port} #向注册中心中注册服务id lease-renewal-interval-in-seconds: 5 #向注册中心中注册服务id lease-expiration-duration-in-seconds: 10 #续约到期的时间 ``` #### 简化路由配置 ```yaml # 路由配置 zuul: routes: #商品微服务 #product-server: #路由id,随便写 #path: /product-service/** #localhost:8080/product-service/***** #serviceId: service-product #配置转发的微服务的服务名称 #如果路由id和对应的微服务的serviceId一致的话 service-product: /product-service/** ``` #### 路由如果当前的服务名称service-product,默认的请求映射路径 /service-product/** #### zuul网关过滤器 * pre 转发到微服务之前执行的过滤器 * routing:在路由请求时执行的过滤器 * post:执行微服务获取返回值之后执行的过滤器 * error:在整个阶段抛出异常的时候执行的过滤器 #### 自定义过滤器 ```java /** * @ClassNameLoginFilter * @Description 自定义zuul过滤器 * @Author liufei * @Date2021/9/3 11:42 * @Version V1.0 **/ @Component public class LoginFilter extends ZuulFilter { /** * 定义过滤器类型 * pre * routing * post * error * @return */ @Override public String filterType() { return "pre"; } /** * 指定过滤器的执行顺序 * 返回值越小,执行顺序越高 * @return */ @Override public int filterOrder() { return 1; } /** * 过滤器是否生效 * true:使用此过滤器 * false:不使用此过滤器 * @return */ @Override public boolean shouldFilter() { return true; } /** * 执行过滤器的业务逻辑 * @return * @throws ZuulException */ @Override public Object run() throws ZuulException { System.out.println("执行了过滤器"); return null; } } ``` #### zuul网关的不足 1.同步servlet的形式就是一个请求一个线程去执行完才会释放,如果请求量过大就会导致线程阻塞。(同步阻塞式网关) 2.zuul网关不支持websocket ## Springcloud Gateway网关 #### 路由配置 1. 创建工程导入坐标(注意gateway和startweb冲突所以要摒弃web才能启动成功) ```xml org.springframework.cloud spring-cloud-starter-gateway ``` 2. 编写启动类 ```java @SpringBootApplication public class GatewayServerApplication { public static void main(String[] args) { SpringApplication.run(GatewayServerApplication.class,args); } } ``` 3. 编写yaml ```yaml server: port: 8080 #端口 spring: application: name: api-gateway-server #服务名称 #配置springcloudgateway的路由 cloud: gateway: routes: #配置路由 :路由id,路由到微服务的uri,断言(判断条件) - id: service-product uri: http://127.0.0.1:9011 predicates: - Path=/product/** ``` 4. 路由规则 ```yaml #路由断言之后匹配 spring: cloud: gateway: routes: - id: after_route uri: https://xxxx.com #路由断言之前匹配 predicates: - After=xxxxx #路由断言之前匹配 spring: cloud: gateway: routes: - id: before_route uri: https://xxxxxx.com predicates: - Before=xxxxxxx #路由断言之间 spring: cloud: gateway: routes: - id: between_route uri: https://xxxx.com predicates: - Between=xxxx,xxxx #路由断言Cookie匹配,此predicate匹配给定名称(chocolate)和正则表达式(ch.p) spring: cloud: gateway: routes: - id: cookie_route uri: https://xxxx.com predicates: - Cookie=chocolate, ch.p #路由断言Header匹配,header名称匹配X-Request-Id,且正则表达式匹配\d+ spring: cloud: gateway: routes: - id: header_route uri: https://xxxx.com predicates: - Header=X-Request-Id, \d+ #路由断言匹配Host匹配,匹配下面Host主机列表,**代表可变参数 spring: cloud: gateway: routes: - id: host_route uri: https://xxxx.com predicates: - Host=**.somehost.org,**.anotherhost.org #路由断言Method匹配,匹配的是请求的HTTP方法 spring: cloud: gateway: routes: - id: method_route uri: https://xxxx.com predicates: - Method=GET #路由断言匹配,{segment}为可变参数 spring: cloud: gateway: routes: - id: host_route uri: https://xxxx.com predicates: - Path=/foo/{segment},/bar/{segment} #路由断言Query匹配,将请求的参数param(baz)进行匹配,也可以进行regexp正则表达式匹配 (参数包含 foo,并且foo的值匹配ba.) spring: cloud: gateway: routes: - id: query_route uri: https://xxxx.com predicates: - Query=baz 或 Query=foo,ba. #路由断言RemoteAddr匹配,将匹配192.168.1.1~192.168.1.254之间的ip地址,其中24为子网掩码位 数即255.255.255.0 spring: cloud: gateway: routes: - id: remoteaddr_route uri: https://example.org predicates: - RemoteAddr=192.168.1.1/2 ``` 5.动态路由 ```yaml server: port: 8080 #端口 spring: application: name: api-gateway-server #服务名称 #配置springcloudgateway的路由 cloud: gateway: routes: #配置路由 :路由id,路由到微服务的uri,断言(判断条件) - id: service-product #uri: http://127.0.0.1:9011 uri: lb://service-product #lb://根据微服务名称从注册中心拉取服务请求路径 predicates: - Path=/product/** ``` 6.开启微服务名称的转发 ```yaml #配置自动的根据微服务名称进行路由转发 discovery: locator: enabled: true #开启根据服务名称自动转发 lower-case-service-id: true #微服务名称以小写形式呈现 ``` #### 过滤器 1. springcloud Gateway 的filter的生命周期不想zuul的那么丰富,它只有:"pre"和"post" 2. pre 这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。 3. post 这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的http head、收集统计信息和指标、将响应从微服务发送给客户端等。 #### 统一鉴权 ```java @Component public class LoginFilter implements GlobalFilter, Ordered { /** * 执行过滤器中的业务逻辑 * 对请求参数中的access-token进行认证 * 如果存在此参数:代表已经认证成功 * 如果不存在此参数:认证失败 * ServerWebExchange:相当于请求和响应的上下文(zuul中的RequestContext) * @param exchange * @param chain * @return */ @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { System.out.println("执行了自定义的全局过滤器"); //获取请求参数access-token String token = exchange.getRequest().getQueryParams().getFirst("access-token"); //判断 if(StringUtils.isEmpty(token)){ System.out.println("没有登录"); exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); //请求结束 return exchange.getResponse().setComplete(); } //如果存在继续执行 return chain.filter(exchange); } /** * 指定过滤器的执行顺序,返回值越小执行优先级越高 * @return */ @Override public int getOrder() { return 0; } } ``` #### 网关限流 1. 计数器算法 2. 漏桶算法 3. 令牌桶算法 #### 网关实现方式 1. 基于Filter的限流(基于redis) * 准备redis * 在工程中引入redis的相应依赖 ```xml org.springframework.boot spring-boot-starter-actuator org.springframework.boot spring-boot-starter-data-redis-reactive ``` * 修改网关中的application.yml配置 ```yaml server: port: 8080 #端口 spring: application: name: api-gateway-server #服务名称 redis: host: localhost pool: 6379 database: 0 #配置springcloudgateway的路由 cloud: gateway: routes: #配置路由 :路由id,路由到微服务的uri,断言(判断条件) - id: service-product #uri: http://127.0.0.1:9011 uri: lb://service-product #lb://根据微服务名称从注册中心拉取服务请求路径 predicates: #- Path=/product/** - Path=/product-service/** #将当前的请求转发到 http://127.0.0.1:9011/product/1 filters: #使用限流过滤器,是springcloud gataway提供 - name: RequestRateLimiter args: key-resolver: '#{@pathKeyResolver}' redis-rate-limiter.replenishRate: 1 #向令牌桶中填充的速率 redis-rate-limiter-bursCapacity: 3 # 令牌桶的容量 - RewritePath=/product-service/(?.*),/$\{segment} #路径重写的过滤器,yml中$写为$\ #配置自动的根据微服务名称进行路由转发 discovery: locator: enabled: true #开启根据服务名称自动转发 lower-case-service-id: true #微服务名称以小写形式呈现 #配置Eureka eureka: client: service-url: defaultZone: http://localhost:9000/eureka/,http://localhost:8000/eureka/ instance: prefer-ip-address: true #使用ip地址注册 instance-id: ${spring.cloud.client.ip-address}:${server.port} #向注册中心中注册服务id lease-renewal-interval-in-seconds: 5 #向注册中心中注册服务id lease-expiration-duration-in-seconds: 10 #续约到期的时间 ``` * 配置redis中key的解析器KeySesolver ```java @Configuration public class KeyResolverConfiguration { /** * 编写基于请求路径的限流规则 * 基于ip * 基于参数 */ @Bean public KeyResolver pathKeyResolver(){ //自定义的keyResolver return new KeyResolver() { @Override /** * ServerWebExchange * 上下文参数 */ public Mono resolve(ServerWebExchange exchange) { return Mono.just(exchange.getRequest().getPath().toString()); } }; } } ``` 2. 基于Sentinel的限流 #### 网关的高可用 使用Nginx做高可用 ## 链路追踪 #### seluth入门 1. 导入坐标 ```xml org.springframework.cloud spring-cloud-starter-sleuth ``` 2. 增加yaml配置 ```yaml logging: level: root: INFO com.java.feign.ProductFeignClient: debug org.springframework.web.servlet.DispatcherServlet: DEBUG org.springframework.cloud.sleuth: DEBUG ``` #### zipkin 1. zipkin server [zipkin官网](https://zipkin.io/) 2. 添加zipkin依赖 ```xml org.springframework.cloud spring-cloud-starter-zipkin ``` 3.增加配置yaml ````yaml spring: zipkin: base-url: http://127.0.0.1:9411/ sender: type: web #数据的传输方式,以http的形式向server发送数据 sleuth: sampler: probability: 1 #采样比 ```` 4.数据持久化 启动服务命令为 创建数据库为zipkin 表为 ````sql /* SQLyog Ultimate v11.33 (64 bit) MySQL - 5.5.58 : Database - zipkin ********************************************************************* */ /*!40101 SET NAMES utf8 */; /*!40101 SET SQL_MODE=''*/; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; CREATE DATABASE /*!32312 IF NOT EXISTS*/`zipkin` /*!40100 DEFAULT CHARACTER SET utf8 */; USE `zipkin`; /*Table structure for table `zipkin_annotations` */ DROP TABLE IF EXISTS `zipkin_annotations`; CREATE TABLE `zipkin_annotations` ( `trace_id_high` bigint(20) NOT NULL DEFAULT '0' COMMENT 'If non zero, this means the trace uses 128 bit traceIds instead of 64 bit', `trace_id` bigint(20) NOT NULL COMMENT 'coincides with zipkin_spans.trace_id', `span_id` bigint(20) NOT NULL COMMENT 'coincides with zipkin_spans.id', `a_key` varchar(255) NOT NULL COMMENT 'BinaryAnnotation.key or Annotation.value if type == -1', `a_value` blob COMMENT 'BinaryAnnotation.value(), which must be smaller than 64KB', `a_type` int(11) NOT NULL COMMENT 'BinaryAnnotation.type() or -1 if Annotation', `a_timestamp` bigint(20) DEFAULT NULL COMMENT 'Used to implement TTL; Annotation.timestamp or zipkin_spans.timestamp', `endpoint_ipv4` int(11) DEFAULT NULL COMMENT 'Null when Binary/Annotation.endpoint is null', `endpoint_ipv6` binary(16) DEFAULT NULL COMMENT 'Null when Binary/Annotation.endpoint is null, or no IPv6 address', `endpoint_port` smallint(6) DEFAULT NULL COMMENT 'Null when Binary/Annotation.endpoint is null', `endpoint_service_name` varchar(255) DEFAULT NULL COMMENT 'Null when Binary/Annotation.endpoint is null', UNIQUE KEY `trace_id_high` (`trace_id_high`,`trace_id`,`span_id`,`a_key`,`a_timestamp`) COMMENT 'Ignore insert on duplicate', KEY `trace_id_high_2` (`trace_id_high`,`trace_id`,`span_id`) COMMENT 'for joining with zipkin_spans', KEY `trace_id_high_3` (`trace_id_high`,`trace_id`) COMMENT 'for getTraces/ByIds', KEY `endpoint_service_name` (`endpoint_service_name`) COMMENT 'for getTraces and getServiceNames', KEY `a_type` (`a_type`) COMMENT 'for getTraces', KEY `a_key` (`a_key`) COMMENT 'for getTraces', KEY `trace_id` (`trace_id`,`span_id`,`a_key`) COMMENT 'for dependencies job' ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPRESSED; /*Data for the table `zipkin_annotations` */ /*Table structure for table `zipkin_dependencies` */ DROP TABLE IF EXISTS `zipkin_dependencies`; CREATE TABLE `zipkin_dependencies` ( `day` date NOT NULL, `parent` varchar(255) NOT NULL, `child` varchar(255) NOT NULL, `call_count` bigint(20) DEFAULT NULL, UNIQUE KEY `day` (`day`,`parent`,`child`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPRESSED; /*Data for the table `zipkin_dependencies` */ /*Table structure for table `zipkin_spans` */ DROP TABLE IF EXISTS `zipkin_spans`; CREATE TABLE `zipkin_spans` ( `trace_id_high` bigint(20) NOT NULL DEFAULT '0' COMMENT 'If non zero, this means the trace uses 128 bit traceIds instead of 64 bit', `trace_id` bigint(20) NOT NULL, `id` bigint(20) NOT NULL, `name` varchar(255) NOT NULL, `parent_id` bigint(20) DEFAULT NULL, `debug` bit(1) DEFAULT NULL, `start_ts` bigint(20) DEFAULT NULL COMMENT 'Span.timestamp(): epoch micros used for endTs query and to implement TTL', `duration` bigint(20) DEFAULT NULL COMMENT 'Span.duration(): micros used for minDuration and maxDuration query', UNIQUE KEY `trace_id_high` (`trace_id_high`,`trace_id`,`id`) COMMENT 'ignore insert on duplicate', KEY `trace_id_high_2` (`trace_id_high`,`trace_id`,`id`) COMMENT 'for joining with zipkin_annotations', KEY `trace_id_high_3` (`trace_id_high`,`trace_id`) COMMENT 'for getTracesByIds', KEY `name` (`name`) COMMENT 'for getTraces and getSpanNames', KEY `start_ts` (`start_ts`) COMMENT 'for getTraces ordering and range' ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPRESSED; /*Data for the table `zipkin_spans` */ /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; ```` ````shell script java -jar zipkin-server-2.12.9-exec.jar --STORAGE_TYPE=mysql --MYSQL_HOST=127.0.0.1 --MYSQL_TCP_PORT=3306 --MYSQL_USER=root --MYSQL_PASS=root --MYSQL_DB=zipkin ```` 5. 修改消息传输方式(使用消息中间件): - 准备rabbitmq服务器 - 修改zipkin客户端将消息发送到中间件 - 修改zipkin服务端,从rabbit中拉取消息 ## springcloud Stream(主要是封装消息中间件,如果需要切换只需要更改配置就好了) ## 配置中心 #### 常见的配置中心 1. springcloud config 2. Apollo 3. Disconf #### springcloud config入门