前言

我们使用我前面搭建的微服务架构进行演示

教程路径:https://blog.csdn.net/weixin_56320090/article/details/117323546

关于搭建基础的微服务架构大家可以参考我的这个项目。

nacos+openfegin注册调用微服务

Nacos (服务治理 配置中心)简介

Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您快速 实现动态服务发现、服务配置、服务元数据及流量管理。 从上面的介绍就可以看出,nacos的作用就是一个注册中心,用来管理注册上来的各个微服务。

nacos实战

接下来,我们就在现有的环境中加入nacos,并将我们的两个微服务注册上去.

搭建nacos环境

1.安装nacos

下载地址: https://github.com/alibaba/nacos/releases
下载zip格式的安装包,然后进行解压缩操作

在这里插入图片描述
2.启动nacos(切换到nacos解压的路径下)

进入nacos的bin目录点击startup.cmd脚本运行
1.
在这里插入图片描述2.在这里插入图片描述

注意:nacos1.3.2版本后默认以集群模式启动,如果想要单机启动需要使用一下命令启动(任何版本都支持命令启动)

#命令启动
startup.cmd -m standalone

3.访问客户端的nacos页面
在这里插入图片描述成功访问代表启动成功,账号和密码都是“nacos”
在这里插入图片描述可以看到现在我们的服务是没有的,接下来我们把我们的微服务注册到nacos上

微服务注册到nacos

1.添加依赖

在需要注册的微服务工程的pom.xml中添加依赖

       <!-- 添加nacos的发现依赖-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
            <version>2.2.0.RELEASE</version>
        </dependency>

在这里插入图片描述

2.在application.properties配置文件中添加配置
# 注册微服务的名称
spring.application.name=shop-product

#要注册到的nacos的ip
spring.cloud.nacos.discovery.server-addr=192.168.31.89:8899

在这里插入图片描述

openfegin实战(基于OpenFeign实现服务调用)

OpenFeign简介

Feign是Spring Cloud提供的一个声明式的伪Http客户端, 它使得调用远程服务就像调用本地服务一样简单, 只需要创建一个接口并添加一个注解即可。
Nacos很好的兼容了Feign, Feign默认集成了 Ribbon, 所以在Nacos下使用Fegin默认就实现了负载均衡的效果。

Feign的使用

1.添加依赖

在需要调用其他微服务的工程中加入此依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

在这里插入图片描述

2.在主启动类上加入开启feign的注解
@SpringBootApplication
@EnableDiscoveryClient //开启nacos的注解
@EnableFeignClients //开启feign的注解
public class OrderApplication {
  public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class,args);
    }
}
3.创建fegin接口
//声明此接口连接的微服务
@FeignClient(value = "shop-product")
public interface ProductFeign {
    public Product findByIdProduct(@PathVariable("pid") Integer pid );
}

使用openfeign的注意事项

//@GetMapping("/product/findByIdProduct/{pid}")需要访问的其他微服务的请求路径
@GetMapping("/product/findByIdProduct/{pid}")
// public Product findByIdProduct(@PathVariable(“pid”) Integer pid );
//方法名,返回类型,权限修饰符,参数都要与要访问的方法一致,强烈建议直接把方法复制过来去掉方法体。

比如:我们这边要访问的是 名为“shop-product”的微服务,访问路径全名为“/product//findByIdProduct/{pid}”,方法为“ public Product findByIdProduct(@PathVariable(“pid”) Integer pid )”

一定要保证路径正确,方法一致,微服务名正确

在我们注入 private ProductFeign productFeign;这个接口后,我们调用此接口的方法时,就会调用对应微服务的方法来获取数据。

4.修改controller的代码
@RestController
@CrossOrigin
@RequestMapping("/order")
public class OrderController_openfeign {
    @Resource
    private OrderDao dao;
    @Autowired
    private ProductFeign productFeign;//修改处
    @GetMapping("payOrder")
    public String payOrder(Integer pid , Integer num){
        Order order = new Order();
        order.setUid(1);
        order.setNumber(num);
        order.setUsername("沈金坡");
        order.setPid(pid);
        Product product = productFeign.findByIdProduct(pid); //修改处
        if (product!=null){
                order.setPname(product.getPname());
                order.setPprice(product.getPprice());
            }else {
                throw new RuntimeException("您购买的商品已下架");
            }
        int i = dao.insert(order);
        if(i>0){
            return  "下单成功";
        }
        return  "失败";
    }
}

测试

启动两个微服务。调用order的方法,此时order的方法会调用product微服务内的方法

nacos注册检查:
在这里插入图片描述两个微服务注册成功

功能演示:
在这里插入图片描述
自此,微服务注册调用都成功

gateway网关

网关简介

大家都都知道在微服务架构中,**一个系统会被拆分为很多个微服务。**那么作为客户端(pc androud ios 平板)要如何去调用这么多的微服务呢?如果没有网关的存在,我们只能在客户端记录每个微服务的地址,然后分别去调用。

在这里插入图片描述这样的架构,会存在着诸多的问题:

  • 客户端多次请求不同的微服务,增加客户端代码或配置编写的复杂性
  • 认证复杂,每个服务都需要独立认证。
  • 存在跨域请求,在一定场景下处理相对复杂。
    (跨域: 浏览器的ajax从一个地址访问另一个地址:
    协议://ip:port 如果三则有一个不同,则会出现跨域问题。
    http://192.168.10.11:8080 ----->https://192.168.10.11:8080
    http://127.0.0.1:8080—>http://localhost:8080 跨域

上面的这些问题可以借助API网关来解决。
所谓的API网关,就是指系统的统一入口,它封装了应用程序的内部结构,为客户端提供统一服 务,一些与业务本身功能无关的公共逻辑可以在这里实现,诸如认证、鉴权、监控(黑白名单)、路由转发等等。 添加上API网关之后,系统的架构图变成了如下所示:
在这里插入图片描述我们使用Spring Cloud Gateway来做网关。

Gateway简介

Spring Cloud Gateway是Spring公司基于Spring 5.0,Spring Boot 2.0 和 Project Reactor 等术开发的网关,**它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。**它的目标是替代 Netflix Zuul,其不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控和限流。

优点:

  • 功能强大:内置了很多实用的功能,例如转发、监控、限流等
  • 设计优雅,容易扩展

缺点:

  • 其实现依赖Netty与WebFlux,不是传统的Servlet编程模型,学习成本高
  • 不能将其部署在Tomcat、Jetty等Servlet容器里,只能打成jar包执行 web.Jar
  • 需要Spring Boot 2.0及以上的版本,才支持

Gateway快速入门

要求: 通过浏览器访问api网关,然后通过网关将请求转发到商品微服务

1.创建shop-gateway工程

在这里插入图片描述我这边创建在了CSDN父工程下

2. 创建一个api-gateway的工程并加入依赖

  <dependencies>
  <!--gateway依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
          <!--nacos依赖 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
          <!--fastjson依赖 在全局过滤器内用到-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.75</version>
        </dependency>
    </dependencies>

3.创建启动类

@SpringBootApplication
public class MyGatway {
    public static void main(String[] args) {
        SpringApplication.run(MyGatway.class,args);
    }
}

4.配置application.yml文件(yml哦)

yml书写格式在这里比较方便

<!-- 定端口-->
server:
  port: 9000
<!-- 注册的服务名--> 
spring:
  application:
    name: shop-gateway
  cloud:
  <!-- 注册到那个nacos--> 
  nacos:
      discovery:
        server-addr: 192.168.31.89:8899
   <!-- 注册到那个nacos-->   
    gateway:
      routes:
        - id: shop-product # 路由的唯一标识,只要不重复都可以,如果不写默认会通过UUID产生,一般写成被路由的服务名称
          uri: lb://shop-product  # 被路由的地址
          order: 0  #表示优先级  数字越小优先级越高
          predicates:  #断言: 执行路由的判断条件
            - Path=/product/** #请求同中是以/product开头的请求会被路由到 shop-product 微服务中
           
          
        - id: shop-order
          uri: lb://shop-order
          order: 0
          predicates:
            - Path=/order/**
  zipkin:
    base-url: http://localhost:9411
    sleuth:
      sampler:
        probability: 1.0

在这里插入图片描述

5.启动项目, 并通过网关去访问微服务

在这里插入图片描述

执行流程

在这里插入图片描述执行流程大体如下:

  1. Gateway Client向Gateway Server发送请求
  2. 请求首先会被HttpWebHandlerAdapter进行提取组装成网关上下文
  3. 然后网关的上下文会传递到DispatcherHandler,它负责将请求分发给 RoutePredicateHandlerMapping
  4. RoutePredicateHandlerMapping负责路由查找,并根据路由断言判断路由是否可用
  5. 如果过断言成功,由FilteringWebHandler创建过滤器链并调用
  6. 请求会一次经过PreFilter–微服务–PostFilter的方法,最终返回响应

断言

Predicate(断言, 谓词) 用于进行条件判断,只有断言都返回真,才会真正的执行路由。
断言就是说: 在 什么条件下 才能进行路由转发

内置路由断言工厂

SpringCloud Gateway包括许多内置的断言工厂,所有这些断言都与HTTP请求的不同属性匹配体如下:

  • 1.基于Datetime类型的断言工厂
    此类型的断言根据时间做判断,主要有三个:

AfterRoutePredicateFactory: 接收一个日期参数,判断请求日期是否晚于指定日期

BeforeRoutePredicateFactory: 接收一个日期参数,判断请求日期是否早于指定日期

BetweenRoutePredicateFactory: 接收两个日期参数,判断请求日期是否在指定时间段内

实例:
-After=2019-12-31T23:59:59.789+08:00[Asia/Shanghai]

  • 2.基于远程地址的断言工RemoteAddrRoutePredicateFactory:

接收一个IP地址段,判断请求主机地址是否在地址段中
-RemoteAddr=192.168.1.1/24

  • 3.基于Cookie的断言工厂

CookieRoutePredicateFactory:接收两个参数,cookie 名字和一个正则表达式。 判断请求
cookie是否具有给定名称且值与正则表达式匹配。
-Cookie=chocolate, ch.

  • 4.基于Header的断言工厂

HeaderRoutePredicateFactory:接收两个参数,标题名称和正则表达式。 判断请求Header是否
具有给定名称且值与正则表达式匹配。
-Header=X-Request-Id, \d+

  • 5.基于Host的断言工厂

HostRoutePredicateFactory:接收一个参数,主机名模式。判断请求的Host是否满足匹配规则。
-Host=**.testhost.org

  • 6.基于Method请求方法的断言工厂

MethodRoutePredicateFactory:接收一个参数,判断请求类型是否跟指定的类型匹配。
-Method=GET

  • 7.基于Path请求路径的断言工厂

PathRoutePredicateFactory:接收一个参数,判断请求的URI部分是否满足路径规则。
-Path=/foo/{segment}基于Query请求参数的断言工厂
QueryRoutePredicateFactory :接收两个参数,请求param和正则表达式, 判断请求参数是否具
有给定名称且值与正则表达式匹配。
-Query=baz, ba.

  • 8基于路由权重的断言工厂

WeightRoutePredicateFactory:接收一个[组名,权重], 然后对于同一个组内的路由按照权重转发
routes:
-id: weight_route1 uri: host1 predicates:
-Path=/product/**
-Weight=group3, 1
-id: weight_route2 uri: host2 predicates:
-Path=/product/**
-Weight= group3, 9

过滤器

过滤器的作用

1 作用: 过滤器就是在请求的传递过程中,对请求和响应做一些手脚
2 生命周期: Pre Post
3 分类: 局部过滤器(作用在某一个路由上) 全局过滤器(作用全部路由上)

在Gateway中, Filter的生命周期只有两个:“pre” 和 “post”。

  • PRE: 这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。
  • POST:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。

在这里插入图片描述

Gateway 的Filter从作用范围可分为两种: GatewayFilter与GlobalFilter。

  • GatewayFilter:应用到单个路由或者一个分组的路由上。
  • GatewayFilter:应用到单个路由或者一个分组的路由上。

局部过滤器

局部过滤器是针对单个路由的过滤器。
内置过滤器:
在SpringCloud Gateway中内置了很多不同类型的网关路由过滤器。
在这里插入图片描述

全局过滤器

全局过滤器作用于所有路由, 无需配置。通过全局过滤器可以实现对权限的统一校验,安全性验证等功能。

内置全局过滤器

SpringCloud Gateway内部也是通过一系列的内置全局过滤器对整个路由转发进行处理如下:
在这里插入图片描述

自定义全局过滤器

—————内置的过滤器已经可以完成大部分的功能,但是对于企业开发的一些业务功能处理,还是需要我们自己编写过滤器来实现的,那么我们一起通过代码的形式自定义一个过滤器,去完成统一的权限校验。
开发中的鉴权逻辑:

  • 当客户端第一次请求服务时,服务端对用户进行信息认证(登录)
  • 认证通过,将用户信息进行加密形成token,返回给客户端aaaa,作为登录凭证
  • 认证通过,将用户信息进行加密形成token,返回给客户端aaaa,作为登录凭证
  • 服务端对token进行解密,判断是否有效。
    在这里插入图片描述如上图,对于验证用户是否已经登录鉴权的过程可以在网关统一检验。
    检验的标准就是请求中是否携带token凭证以及token的正确性。
    下面的我们自定义一个GlobalFilter,去校验所有请求的请求参数中是否包含“token”,如何不包含请求参数“token”则不转发路由,否则执行正常的逻辑
1.创建filter

自定义全局过滤器 要求:必须实现GlobalFilter,Order接口

@Component
public class LoginFilter  implements Ordered, GlobalFilter {}
2.重写filter和getOrder方法
     public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)  {
        //获取请求头中携带的token数据
        String token = exchange.getRequest().getQueryParams().getFirst("token");
        //获取请求对象
        ServerHttpRequest request = exchange.getRequest();
        //获取响应对象
        ServerHttpResponse response = exchange.getResponse();
        //判断token中是否有数据
        if(StringUtils.isNotEmpty(token)){
            //不为空就放行
            return  chain.filter(exchange);
        }
        //判断是否为登录请求
        if(exchange.getRequest().getPath().toString().contains("/login")){
            //是请求路径就放行
            return chain.filter(exchange);
        }
        //如果未登录,自定义响应内容
        DataBuffer buffer=null;
        try{
            HashMap<String, Object> commonResult = new HashMap<>();
            commonResult.put("code",401);
            commonResult.put("msg","登录失效");
            byte[] bytes = JSON.toJSONString(commonResult).getBytes("utf-8");
            buffer = response.bufferFactory().wrap(bytes);
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            response.getHeaders().add("Content-type","application/json;charset=UTF-8");
        }catch (UnsupportedEncodingException e){
            e.printStackTrace();
        }
        //返回指定的数据
        return response.writeWith(Mono.just(buffer));
    }

//此方法就是声明拦截器的优先级 数越小,优先级越大
    @Override
    public int getOrder() {
        return 0;
    }

自此,拦截器配置成功。

Sleuth–链路追踪

1.链路追踪介绍

**在大型系统的微服务化构建中,一个系统被拆分成了许多模块。**这些模块负责不同的功能,组合成系统,最终可以提供丰富的功能。在这种架构中,一次请求往往需要涉及到多个服务。互联网应用构建在不同的软件模块集上,这些软件模块,有可能是由不同的团队开发、可能使用不同的编程语言来实现、有可能布在了几千台服务器,横跨多个不同的数据中心,也就意味着这种架构形式也会存在一些问题:

  • 如何快速发现问题?
  • 如何判断故障影响范围?
  • 如何梳理服务依赖以及依赖的合理性?
  • 如何分析链路性能问题以及实时容量规划?

在这里插入图片描述分布式链路追踪(Distributed Tracing),就是将一次分布式请求还原成调用链路,进行日志记录,性能监控并将一次分布式请求的调用情况集中展示。比如各个服务节点上的耗时、请求具体到达哪台机器上、每个服务节点的请求状态等等。

在这边我们使用“Sleuth”+“Zipkin”来记录

Sleuth入门

sleuth介绍

SpringCloud Sleuth主要功能就是在分布式系统中提供追踪解决方案。它大量借用了Google Dapper的设计, 先来了解一下Sleuth中的术语和相关概念。

Trace (一条完整链路–包含很多span(微服务接口))

由一组Trace Id(贯穿整个链路)相同的Span串联形成一个树状结构。为了实现请求跟踪,当请求到达分布式系统的入口端点时,只需要服务跟踪框架为该请求创建一个唯一的标识(即TraceId),同时在分布式系统内部流转的时候,框架始终保持传递该唯一值,直到整个请求的返回。那么我们就可以使用该唯一标识将所有的请求串联起来,形成一条完整的请求链路。

Span

代表了一组基本的工作单元。为了统计各处理单元的延迟,当请求到达各个服务组件的时候,也通过一个唯一标识(SpanId)来标记它的开始、具体过程和结束。通过SpanId的开始和结束时间戳,就能统计该span的调用时间,除此之外,我们还可以获取如事件的名称。请求信息等元数据。

Annotation

用它记录一段时间内的事件,内部使用的重要注释:

  • cs(Client Send)客户端发出请求,开始一个请求的生命
  • sr(Server Received)服务端接受到请求开始进行处理, sr-cs = 网络延迟(服务调用的时间)
  • ss(Server Send)服务端处理完毕准备发送到客户端,ss - sr = 服务器上的请求处理时间
  • cr(Client Reveived)客户端接受到服务端的响应,请求结束。 cr - sr = 请求的总时间

在这里插入图片描述

Sleuth使用

1.配置文件

我这里在最大的父工程内添加,就等于在所有的子工程下都加入了依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>

在这里插入图片描述

2.启动项目并测试

功能演示:
在这里插入图片描述后台展示:
在这里插入图片描述
可以看到,再加入Sleuth后,在调用此微服务时,就会生成日志文件

Zipkin使用

ZipKin介绍

Zipkin 是 Twitter 的一个开源项目,它基于Google Dapper实现,它致力于收集服务的定时数据,以解决微服务架构中的延迟问题,包括数据的收集、存储展现、查找和我们可以使用它来收集各个服务器上请求链路的跟踪数据,并通过它提供的REST API接口来辅助我们查询跟踪数据以实现对分布式系统的监控程序,从而及时地发现系统中出现的延迟升高问题并找出系统性能瓶颈的根源

除了面向开发的 API 接口之外,它也提供了方便的UI组件来帮助我们直观的搜索跟踪信息和分析请求链路明细,比如:可以查询某段时间内各用户请求的处理时间等。

Zipkin 提供了可插拔数据存储方式:In-Memory、MySql、Cassandra 以及 Elasticsearch。

在这里插入图片描述Zipkin 分为两端,一个是 Zipkin 服务端,一个是 Zipkin 客户端,客户端也就是微服务的应用。客户端会配置服务端的 URL 地址,一旦发生服务间的调用的时候,会被配置在微服务里面的 Sleuth 的监听器监听,并生成相应的 Trace 和 Span 信息发送给服务端。

zipkin使用

1.下载ZipKin的jar包

Zipkin的 github 地址:https://github.com/apache/incubator-zipkin

2.启动服务

在放有此jar包的路径下打开cmd执行此命令

java -jar zipkin-server-2.12.9-exec.jar

3.通过浏览器访问

http://localhost:9411(路径)

4.Zipkin客户端集成

ZipKin客户端和Sleuth的集成非常简单,只需要在微服务中添加其依赖和配置即可。

5.在每个微服务上添加依赖

我这里在最大的父工程内添加,就等于在所有的子工程下都加入了依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>

在这里插入图片描述

6.添加配置

在每个需要链路追踪的微服务中加入配置

yml文件下配置:注意缩进

spring:
  application:

    nacos:
      discovery:
        server-addr: 192.168.31.89:8899

  zipkin:
    base-url: http://localhost:9411
    sleuth:
      sampler:
        probability: 1.0

properties文件配置:

spring.zipkin.base-url=http://localhost:9411
spring.sleuth.sampler.probability=1.0

连接ZipKin的路径
spring.zipkin.base-url=http://localhost:9411
样本抽取比例1.0就是100%
spring.sleuth.sampler.probability=1.0

7.访问微服务

http://localhost:7000/order-serv/order/prod/1

8.访问zipkin的UI界面,观察效果

在这里插入图片描述点击其中一条记录,可观察一次访问的详细线路
在这里插入图片描述

ZipKin数据持久化

Zipkin Server默认会将追踪数据信息保存到内存,但这种方式不适合生产环境。Zipkin支持将追踪数据持久化到mysql数据库或elasticsearch中。

第1步: 创建mysql数据环境
REATE TABLE IF NOT EXISTS zipkin_spans (
 `trace_id_high` BIGINT NOT NULL DEFAULT 0 COMMENT 'If non zero, this means the trace uses 128 bit traceIds instead of 64 bit', 
`trace_id` BIGINT NOT NULL, 
`id` BIGINT NOT NULL, 
`name` VARCHAR(255) NOT NULL, 
`parent_id` BIGINT, 
`debug` BIT(1), 
`start_ts` BIGINT COMMENT 'Span.timestamp(): epoch micros used for endTs query and to implement TTL',
`duration` BIGINT COMMENT 'Span.duration(): micros used for minDuration and maxDuration query' )
 ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci;

ALTER TABLE zipkin_spans ADD UNIQUE KEY(`trace_id_high`, `trace_id`, `id`) COMMENT 'ignore insert on duplicate'; 
ALTER TABLE zipkin_spans ADD INDEX(`trace_id_high`, `trace_id`, `id`) COMMENT 'for joining with zipkin_annotations'; 
ALTER TABLE zipkin_spans ADD INDEX(`trace_id_high`, `trace_id`) COMMENT 'for getTracesByIds';
 ALTER TABLE zipkin_spans ADD INDEX(`name`) COMMENT 'for getTraces and getSpanNames';
 ALTER TABLE zipkin_spans ADD INDEX(`start_ts`) COMMENT 'for getTraces ordering and range';
CREATE TABLE IF NOT EXISTS zipkin_annotations (
 `trace_id_high` BIGINT NOT NULL DEFAULT 0 COMMENT 'If non zero, this means the trace uses 128 bit traceIds instead of 64 bit', 
`trace_id` BIGINT NOT NULL COMMENT 'coincides with zipkin_spans.trace_id', 
`span_id` BIGINT 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 NOT NULL COMMENT 'BinaryAnnotation.type() or -1 if Annotation', 
`a_timestamp` BIGINT COMMENT 'Used to implement TTL; Annotation.timestamp or zipkin_spans.timestamp',
 `endpoint_ipv4` INT COMMENT 'Null when Binary/Annotation.endpoint is null', 
`endpoint_ipv6` BINARY(16) COMMENT 'Null when Binary/Annotation.endpoint is null, or no IPv6 address', 
`endpoint_port` SMALLINT COMMENT 'Null when Binary/Annotation.endpoint is null',
`endpoint_service_name` VARCHAR(255) COMMENT 'Null when Binary/Annotation.endpoint is null' )
 ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci;
ALTER TABLE zipkin_annotations ADD UNIQUE KEY(`trace_id_high`, `trace_id`, `span_id`, `a_key`, `a_timestamp`) COMMENT 'Ignore insert on duplicate'; 
ALTER TABLE zipkin_annotations ADD INDEX(`trace_id_high`, `trace_id`, `span_id`) COMMENT 'for joining with zipkin_spans'; 
ALTER TABLE zipkin_annotations ADD INDEX(`trace_id_high`, `trace_id`) COMMENT 'for getTraces/ByIds'; 
ALTER TABLE zipkin_annotations ADD INDEX(`endpoint_service_name`) COMMENT 'for getTraces and getServiceNames';

ALTER TABLE zipkin_annotations ADD INDEX(`a_type`) COMMENT 'for getTraces';
 ALTER TABLE zipkin_annotations ADD INDEX(`a_key`) COMMENT 'for getTraces'; 
ALTER TABLE zipkin_annotations ADD INDEX(`trace_id`, `span_id`, `a_key`) COMMENT 'for dependencies job';
CREATE TABLE IF NOT EXISTS zipkin_dependencies ( 
`day` DATE NOT NULL, 
`parent` VARCHAR(255) NOT NULL, 
`child` VARCHAR(255) NOT NULL,
 `call_count` BIGINT ) 
ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci; 
ALTER TABLE zipkin_dependencies ADD UNIQUE KEY(`day`, `parent`, `child`);
第2步: 在启动ZipKin Server的时候,指定数据保存的mysql的信息
java -jar zipkin-server-2.12.9-exec.jar --STORAGE_TYPE=mysql -- 
MYSQL_HOST=127.0.0.1 --MYSQL_TCP_PORT=3306 --MYSQL_DB=zipkin --MYSQL_USER=root - 
-MYSQL_PASS=root

当ZipKin 服务关闭后,数据都被持久化到mysql中,下次启动还会有记录

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐