一、升级前必须做的3件事(踩坑前的“安全锁”)

很多人升级Zipkin时会直接跳过准备工作,觉得“只是版本升级,改个镜像/依赖就行”,结果上线后要么链路全断,要么旧业务查不到历史数据,甚至出现“升级后新链路能追踪、旧链路完全失联”的诡异问题。这3件事是必须按顺序做的,缺一不可。

1.1 先查官方兼容矩阵(别自己瞎猜版本)

Zipkin的版本迭代分两种:一种是功能迭代(比如2.20.x到2.21.x),一种是重大变更(比如2.12.x之前的旧版到2.12.x之后的新版,或者2.23.x之后的新架构)。不同版本对依赖的组件(比如存储、客户端、中间件)的兼容要求完全不同,比如旧版Zipkin用的是Spring Boot 1.x,新版用Spring Boot 2.x甚至3.x,直接升级会导致依赖冲突。

举个实际的例子:假设你现在用的是Zipkin 2.11.0(旧版),想升级到2.23.0(新版),先去官方的兼容矩阵查:

  • 存储兼容:旧版支持Cassandra 3.x,新版只支持Cassandra 4.x;
  • 客户端兼容:旧版Java客户端用的是io.zipkin.java:zipkin包,新版必须用io.zipkin.reporter2:zipkin-reporter-brave;
  • 部署兼容:旧版支持独立部署的Zipkin服务,新版必须搭配Zipkin Collector、Query、UI三个组件分开部署(或用K8s的StatefulSet)。

1.2 备份所有配置和数据(出问题能回滚)

很多人升级时会忽略备份,觉得“升级不会坏数据”,但Zipkin的存储格式在版本升级时可能会变,比如旧版把链路ID存在表的trace_id字段,新版可能改成trace_id_high+trace_id_low的组合(因为新版支持128位链路ID,旧版只支持64位),如果不备份,升级后旧数据可能读不出来,甚至被覆盖。

备份要做两件事:

  1. 备份配置:包括Zipkin的启动配置(比如zipkin.server.port、zipkin.storage.type)、客户端的链路追踪配置(比如采样率、上报地址);
  2. 备份存储数据:如果用的是MySQL、Cassandra等持久化存储,要做全量备份;如果用的是内存存储(测试环境),要导出所有链路数据(可以用Zipkin的API导出)。

1.3 做灰度测试(别直接全量升级)

灰度测试是规避生产环境故障的核心,正确的灰度流程是:先搭一个和生产环境完全一致的测试环境(包括存储、客户端版本、业务逻辑),然后在测试环境升级Zipkin,验证以下内容:

  • 新链路是否能正常上报、查询;
  • 旧链路(升级前的)是否能正常查询;
  • 客户端上报是否正常(有没有报错、采样率是否符合预期);
  • 存储是否正常(有没有数据丢失、存储格式是否兼容)。

举个灰度测试的示例(技术栈:Java + Spring Boot + Zipkin):

// 测试环境的Zipkin客户端配置(旧版配置)
@Configuration
public class ZipkinConfig {
    @Bean
    public Reporter<Span> zipkinReporter() {
        // 旧版配置:上报地址是测试环境的旧Zipkin地址
        return AsyncReporter.create(URLConnectionSender.create("http://test-zipkin-old:9411/api/v2/spans"));
    }
}

然后在测试环境升级Zipkin到新版,修改客户端配置为新版:

// 测试环境的Zipkin客户端配置(新版配置)
@Configuration
public class ZipkinConfig {
    @Bean
    public Reporter<Span> zipkinReporter() {
        // 新版配置:上报地址是测试环境的新Zipkin地址,必须用Reporter2的Sender
        return AsyncReporter.create(OkHttpSender.create("http://test-zipkin-new:9411/api/v2/spans"));
    }
}

然后验证:旧的测试链路(升级前的)在新Zipkin里能查到,新的测试链路(升级后的)也能查到,没有报错。

二、升级中必须注意的4个兼容点(踩坑重灾区)

即使做了准备工作,升级过程中还是可能出现兼容问题,这4个点是最容易出问题的,必须重点关注。

2.1 存储兼容:别让旧数据“读不出来”

Zipkin的存储格式在版本升级时可能会有变化,最常见的是链路ID的格式变化:旧版Zipkin只支持64位链路ID(长度16),新版支持128位链路ID(长度32),如果旧版的存储里存的是64位ID,新版Zipkin查询时可能会把它当成无效的128位ID,导致查不到旧数据。

解决方法:

  1. 升级前先检查存储里的链路ID长度,如果都是16位,升级时要在Zipkin的配置里加参数ZIPKIN_STORAGE_TRACE_ID_128_BIT_ENABLED=false,让新版Zipkin兼容旧的64位ID;
  2. 升级后如果需要支持128位ID,要先把旧数据批量转成128位(可以写个脚本遍历旧数据,把16位的ID补成32位,前面加16个0)。

举个存储参数配置的示例(技术栈:Docker + Zipkin):

# 旧版Zipkin的Docker启动命令(默认用64位ID)
docker run -d -p 9411:9411 openzipkin/zipkin:2.11.0

# 新版Zipkin的Docker启动命令(兼容旧的64位ID)
docker run -d -p 9411:9411 \
  -e ZIPKIN_STORAGE_TRACE_ID_128_BIT_ENABLED=false \
  openzipkin/zipkin:2.23.0

2.2 客户端兼容:别让链路“断了线”

Zipkin的客户端在版本升级时,依赖包和配置都会变,最常见的是依赖包的变化:旧版Java客户端用的是io.zipkin.java:zipkin,新版必须用io.zipkin.reporter2:zipkin-reporter-brave,如果客户端不升级,会出现“客户端上报的链路格式不兼容新版Zipkin”的问题,导致链路丢失。

解决方法:

  1. 先升级所有业务的Zipkin客户端到新版(和Zipkin服务端版本兼容的);
  2. 升级客户端时要修改配置:比如旧版的采样率配置是zipkin.sampler.rate=0.1,新版是zipkin.sampler.rate=0.1(配置名没变,但依赖包变了);旧版的上报地址是http://zipkin:9411/api/v1/spans,新版必须是http://zipkin:9411/api/v2/spans(注意是v2接口)。

举个客户端升级的示例(技术栈:Java + Spring Boot):

<!-- 旧版Zipkin客户端的依赖(pom.xml) -->
<dependency>
    <groupId>io.zipkin.java</groupId>
    <artifactId>zipkin</artifactId>
    <version>2.11.0</version>
</dependency>

<!-- 新版Zipkin客户端的依赖(pom.xml) -->
<dependency>
    <groupId>io.zipkin.reporter2</groupId>
    <artifactId>zipkin-reporter-brave</artifactId>
    <version>2.16.3</version>
</dependency>

2.3 接口兼容:别让旧工具“用不了”

Zipkin的API接口在版本升级时可能会有变化,最常见的是查询接口的变化:旧版的查询接口是http://zipkin:9411/api/v1/traces,新版改成了http://zipkin:9411/api/v2/traces,如果旧的监控工具(比如Prometheus、Grafana)用的是旧接口,升级后会查不到数据。

解决方法:

  1. 先检查所有用到Zipkin API的工具(包括监控、日志分析、自动化测试),把旧接口改成新接口;
  2. 如果有些工具暂时改不了,可以在新版Zipkin的前面加一个反向代理(比如Nginx),把旧接口的请求转发到新接口。

举个Nginx反向代理的示例(技术栈:Nginx + Zipkin):

# Nginx配置:把旧的v1接口转发到新的v2接口
server {
    listen 80;
    server_name zipkin-proxy;

    # 转发旧的v1查询接口到新的v2接口
    location /api/v1/traces {
        proxy_pass http://zipkin:9411/api/v2/traces;
    }

    # 转发旧的v1 span接口到新的v2接口
    location /api/v1/spans {
        proxy_pass http://zipkin:9411/api/v2/spans;
    }

    # 其他请求正常转发到Zipkin
    location / {
        proxy_pass http://zipkin:9411;
    }
}

2.4 部署兼容:别让架构“乱了套”

Zipkin的部署架构在版本升级时可能会有变化,最常见的是架构拆分:旧版Zipkin是一个单体服务(包括Collector、Query、UI),新版把这三个组件拆成了独立的服务,部署时必须分开部署,或者用K8s的StatefulSet来管理。

解决方法:

  1. 先了解新版Zipkin的部署架构:Collector负责接收链路数据,Query负责查询链路数据,UI负责展示链路数据;
  2. 部署时要确保三个组件的配置一致:比如存储配置、链路ID配置、采样率配置;
  3. 如果是K8s部署,要给每个组件配置对应的Service,确保组件之间能正常通信。

举个K8s部署新版Zipkin的示例(技术栈:K8s + Zipkin):

# Collector的Deployment配置(负责接收链路数据)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: zipkin-collector
spec:
  replicas: 1
  selector:
    matchLabels:
      app: zipkin-collector
  template:
    metadata:
      labels:
        app: zipkin-collector
    spec:
      containers:
      - name: zipkin-collector
        image: openzipkin/zipkin-collector:2.23.0
        ports:
        - containerPort: 9411
        env:
        - name: ZIPKIN_STORAGE_TYPE
          value: mysql
        - name: ZIPKIN_STORAGE_MYSQL_HOST
          value: mysql-service
        - name: ZIPKIN_STORAGE_TRACE_ID_128_BIT_ENABLED
          value: "false"

三、升级后必须做的2件事(确认升级成功)

升级完成后,不能直接认为“升级成功”,必须做验证和监控,确保没有潜在的问题。

3.1 全量验证功能(别漏了旧业务)

升级后要验证的内容包括:

  1. 新链路:随机选几个新的业务请求,检查是否能在Zipkin UI里查到,链路是否完整(包括所有服务的调用链);
  2. 旧链路:随机选几个升级前的业务请求,检查是否能在Zipkin UI里查到,链路是否完整;
  3. 接口:检查所有用到Zipkin API的工具(比如监控、日志)是否能正常获取数据;
  4. 性能:检查Zipkin的性能是否正常(比如上报速度、查询速度、存储占用)。

举个功能验证的示例(技术栈:Postman + Zipkin):

# 用Postman调用新Zipkin的查询接口,检查旧链路是否能查到
curl -X GET "http://zipkin-new:9411/api/v2/traces?serviceName=order-service&startTs=1620000000000&endTs=1620000000000"
# 预期结果:返回升级前的order-service的链路数据

3.2 持续监控(别让问题“潜伏”)

升级后要持续监控Zipkin的状态,监控的内容包括:

  1. 链路上报成功率:如果上报成功率低于99%,说明有客户端上报失败;
  2. 链路查询成功率:如果查询成功率低于99%,说明有链路数据丢失;
  3. 存储占用:如果存储占用突然增加,说明有链路数据重复或格式错误;
  4. 错误日志:检查Zipkin的日志,有没有“invalid trace id”、“storage error”等错误。

举个监控配置的示例(技术栈:Prometheus + Grafana):

# Prometheus配置:监控Zipkin的上报成功率
scrape_configs:
  - job_name: 'zipkin'
    static_configs:
      - targets: ['zipkin-new:9411']
    metrics_path: '/actuator/prometheus'
    params:
      metric[]: ['zipkin_collector_spans_received_total', 'zipkin_collector_spans_dropped_total']

四、常见应用场景、优缺点及注意事项

4.1 应用场景

Zipkin版本升级的常见应用场景包括:

  1. 功能需求:新版Zipkin支持更多的功能(比如分布式追踪的链路可视化、服务依赖分析、性能监控),旧版无法满足;
  2. 安全需求:旧版Zipkin存在安全漏洞(比如CVE-2021-28164),需要升级到新版修复;
  3. 兼容需求:旧版Zipkin不支持新的依赖组件(比如Spring Boot 3.x、Cassandra 4.x),需要升级到新版兼容;
  4. 性能需求:新版Zipkin优化了性能(比如存储速度、查询速度、内存占用),旧版无法满足高并发场景。

4.2 技术优缺点

升级Zipkin的优点:

  1. 功能更丰富:新版支持更多的功能,比如链路的火焰图、服务的依赖拓扑、性能的瓶颈分析;
  2. 安全性更高:新版修复了旧版的安全漏洞,避免被攻击;
  3. 兼容性更好:新版支持新的依赖组件,能和新的业务系统集成;
  4. 性能更优:新版优化了性能,能处理更高的并发量。

升级Zipkin的缺点:

  1. 兼容问题:升级过程中可能会出现链路丢失、旧数据读不出来、接口不兼容等问题;
  2. 成本较高:升级需要做准备工作、灰度测试、验证和监控,耗费较多的时间和人力;
  3. 架构变化:新版的部署架构可能会变化,需要重新部署和配置。

4.3 注意事项

  1. 不要跳过准备工作:准备工作是规避故障的核心,不要因为觉得麻烦而跳过;
  2. 不要直接全量升级:灰度测试是必须的,能避免生产环境的故障;
  3. 不要忽略旧数据:旧数据是业务的重要资产,升级时要确保旧数据能正常查询;
  4. 不要忽略监控:升级后要持续监控,及时发现潜在的问题。

五、文章总结

Zipkin版本升级是一个复杂的过程,容易出现兼容问题,导致功能异常。要规避这些问题,必须做好升级前的准备工作(查兼容矩阵、备份、灰度测试),升级中重点关注存储、客户端、接口、部署的兼容问题,升级后做全量验证和持续监控。

升级的核心原则是“稳”,不要为了升级而升级,要根据业务的实际需求来决定是否升级,升级前要充分评估风险,升级过程中要按步骤操作,升级后要及时验证和监控。