Dubbo应用可观测性升级指南与踩坑记录

应用从dubbo-3.1.*升级到dubbo-*:3.2.*最新稳定版本,提升应用的可观测性和度量数据准确性

1. dubbo版本发布说明(可不关注)

dubbo版本发布

https://github.com/apache/dubbo/releases

2. 应用修改点

应用一般只需要升级dubbo-spring-boot-starter版本到3.2.10 ,相关组件版本检查 是否一致

要求

  • dubbo-spring-boot-starter版本3.2.10dubbo系列版本一样 (xxx-spring-boot-starter引入,项目里可不单独引用)
  • 【依赖可选】netty系列版本4.1.101.Final
  • 【依赖可选】fastjson2 版本2.0.46 (全部统一使用hessian2参数序列化方式)
  • 【依赖可选】protobuf-java版本3.24.2
  • 【依赖可选】t-digest版本3.3
  • 检查jar包dubbo-spring-boot-observability-starterspring-boot-starter-actuator是否存在。

版本检查

通过Maven依赖树命令 分析mvn dependency:tree > dependency-tree.txt

IDEA,通过Maven依赖分析功能,关键词搜索

2.1 jar包升级

pom.xml依赖声明

xml 复制代码
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.16</version>
    <relativePath/>
</parent>

<properties>
    <dubbo.version>3.2.10</dubbo.version>
    <netty.version>4.1.101.Final</netty.version>
    <micrometer.version>1.12.0</micrometer.version>
    <prometheus-client.version>0.16.0</prometheus-client.version>
    <prometheus-pushgateway.version>0.16.0</prometheus-pushgateway.version>
</properties>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>${dubbo.version}</version>
        </dependency>
    </dependencies>
</dependencyManagement>

pom.xml依赖

xml 复制代码
<dependencies>
    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-spring-boot-starter</artifactId>
    </dependency>
</dependencies>
  • 【版本检查】fastjson2版本升级到2.0.46

fastjson不太稳定,问题较多,风险较大。

参数序列化方式,建议保持不变。

全部统一使用hessian2参数序列化方式

2.2 属性配置

application.properties

yml 复制代码
management.server.port=18180
#management.server.base-path=
management.server.servlet.context-path=
management.endpoints.web.base-path=/
management.endpoints.web.exposure.include=prometheus
management.endpoints.web.exposure.exclude=metrics
management.endpoints.web.path-mapping.prometheus=metrics
management.metrics.export.prometheus.descriptions=false
management.metrics.tags.application=${spring.application.name}

# 消费者从提供者同步地址信息等元数据
dubbo.application.metadata-service-protocol=dubbo
dubbo.application.qos-port=22222
dubbo.metrics.protocol=prometheus
dubbo.metrics.enable-jvm=true
dubbo.metrics.enable-threadpool=true
dubbo.metrics.enable-registry=false
dubbo.metrics.enable-metadata=false
dubbo.metrics.export-metrics-service=false
dubbo.metrics.use-global-registry=true
dubbo.metrics.enable-rpc=true
dubbo.metrics.aggregation.enabled=true
dubbo.metrics.aggregation.enable-qps=true
dubbo.metrics.aggregation.enable-rt-pxx=true
dubbo.metrics.aggregation.enable-rt=true
dubbo.metrics.aggregation.enable-request=true
dubbo.metrics.histogram.enabled=true

【配置可选】Apollo统一的基础配置(集成外部配置数据源-配置中心)

建议使用Nacos

apollo-client依赖检查

yml 复制代码
apollo.bootstrap.enabled=true
apollo.bootstrap.namespaces=*,common-middleware-dubbo-metrics

2.3 类检查机制设置【升级必须设置】

若不设置,泛化调用可能会失败。

4-21 - 检测到不安全的序列化数据

出参入参对象 可能有些未实现Serializable序列化接口,引起调用异常。

解法详见【官方文档】类检查机制

【解法】AutoConfiguration-自动配置

java 复制代码
ApplicationConfig applicationConfig = new ApplicationConfig();
// 类检查机制
applicationConfig.setSerializeCheckStatus("DISABLE");
applicationConfig.setCheckSerializable(false);

【解法】属性文件

yml 复制代码
# 类检查机制
dubbo.application.serialize-check-status=DISABLE
dubbo.application.check-serializable=false

2.5 live存活探针日志-建议屏蔽

Kubernetes通过存活探针(liveness probe)检查容器是否还在运行,每隔2s探测一次,打印不少日志,建议屏蔽。

logback-k8s.xmllogback-spring.xml配置文件

xml 复制代码
<!-- k8s liveness probe qos日志很多,不打印 -->
<logger name="org.apache.dubbo.qos.command" level="warn" additivity="false"/>
yml 复制代码
logging.level.org.apache.dubbo.qos.command=warn

3. 踩过的坑

应用升级Dubbo3问题记录

3.1 检查系统最终组件版本

  • dubbo-boot-starter-*系列版本3.2.10 (xxx-spring-boot-starter引入,项目里可不单独引用)
  • fastjson2版本2.0.46 (全部统一使用hessian2参数序列化方式)
  • netty版本4.1.101.Final
  • protobuf-java版本3.24.2
  • t-digest版本3.3
  • 检查jar包dubbo-spring-boot-observability-starterspring-boot-starter-actuator是否存在。
  • micrometer系列组件版本是否一样
  • prometheussimpleclient系列组件版本是否一样

3.2 MetadataService报NPE异常

原因是提供者DubboAccessLogFilter抛出NPE异常,引起消费者获取应用地址等元数据信息失败。

dubbo过滤器加载机制调整

在Filter中调用RpcContext.getServiceContext().isConsumerSide()方法报空指针错误 · Issue #11716 · apache/dubbo

log 复制代码
2024-01-23 11:51:14,075 [Dubbo-framework-metadata-retry-thread-1] ERROR org.apache.dubbo.registry.client.metadata.MetadataUtils -  [DUBBO] Failed to get app metadata for revision 6dd35818cdc09f4b682f8ac3fe312847 for type local from instance 192.168.108.31:8504, dubbo version: 3.2.10, current host: 192.168.104.218, error code: 1-39. This may be caused by , go to https://dubbo.apache.org/faq/1/39 to find instructions. 
org.apache.dubbo.rpc.RpcException: Failed to invoke remote method: getMetadataInfo, provider: dubbo://192.168.108.31:8502/org.apache.dubbo.metadata.MetadataService?connections=1&corethreads=2&dubbo=2.0.2&group=member&port=8502&prefer.serialization=hessian2&protocol=dubbo&release=3.2.10&retries=0&side=consumer&threadpool=cached&threads=100&timeout=3000&version=1.0.0, cause: org.apache.dubbo.remoting.RemotingException: java.lang.NullPointerException
java.lang.NullPointerException
    at com.xxx.member.config.DubboAccessLogFilter.invoke$original$xDfvMLE5(DubboAccessLogFilter.java:44)

【解法】对于@Activate自动激活的过滤器,不能再显示配置Filter

java 复制代码
@Activate(group = CommonConstants.PROVIDER, order = 1)
public class DubboAccessLogFilter implements Filter {
    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        // ...
        RpcContextAttachment rpcContext = RpcContext.getServerAttachment();
        // ...
    }
}

3.3 netty版本冲突

netty版本要和dubbo依赖的版本一样或兼容

xml 复制代码
<properties>
    <netty.version>4.1.101.Final</netty.version>
    <micrometer.version>1.12.0</micrometer.version>
    <prometheus-client.version>0.16.0</prometheus-client.version>
    <prometheus-pushgateway.version>0.16.0</prometheus-pushgateway.version>
</properties>
log 复制代码
java.lang.NoSuchMethodError: io.netty.handler.codec.http2.Http2FrameCodecBuilder: method <init>()V not found
        at org.apache.dubbo.rpc.protocol.tri.TripleHttp2FrameCodecBuilder.<init>(TripleHttp2FrameCodecBuilder.java:32)
        at org.apache.dubbo.rpc.protocol.tri.TripleHttp2FrameCodecBuilder.fromConnection(TripleHttp2FrameCodecBuilder.java:37)

3.4 p95指标计算冲突

t-digest要高于3.3elasticsearch里引入了低版本。

xml 复制代码
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>5.3.3</version>
            <exclusions>
                <exclusion>
                    <groupId>com.tdunning</groupId>
                    <artifactId>t-digest</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
</dependencyManagement>

3.5 参数对象未实现Serializable序列化接口

4-21 - 检测到不安全的序列化数据

3.1 升级至 3.2

序列化协议升级

请求从消费者应用调用具体服务方法时,可能参数值为空,报如下异常。

log 复制代码
Serialized class com.xxx.perform.request.XxxRequest is not in allow list. Current mode is `STRICT`, will disallow to deserialize it by default. Please add it into security/serialize.allowlist or follow FAQ to configure it., dubbo version: 3.2.5, current host: 192.168.108.111, error code: 4-21. This may be caused by , go to https://dubbo.apache.org/faq/4/21 to find instructions

解法详见【官方文档】类检查机制

【解法】AutoConfiguration-自动配置

java 复制代码
ApplicationConfig applicationConfig = new ApplicationConfig();
// 类检查机制
applicationConfig.setSerializeCheckStatus("DISABLE");
applicationConfig.setCheckSerializable(false);

// 提供者配置层
ProviderConfig providerConfig = new ProviderConfig();
// 参数解析序列化方式
providerConfig.setPreferSerialization("hessian2");
providerConfig.setSerialization("hessian2");

【解法】属性文件

yml 复制代码
# 类检查机制
dubbo.application.serialize-check-status=DISABLE
dubbo.application.check-serializable=false
# 参数解析序列化方式
# 提供者配置层
dubbo.provider.prefer-serialization=hessian2
dubbo.provider.serialization=hessian2

3.6 使用 sharding-jdbc 造成 SQLFeatureNotSupportedException: isValid

暂时关闭actuator对db的监控

yml 复制代码
management.health.db.enabled=false

3.7 屏蔽dubbo访问警告日志

log 复制代码
[DUBBO] Will write to the default location, " + "please enable this feature by setting 'accesslog.fixed.path=true' and restart the process. " + "We highly recommend to not enable this feature in production for security concerns, " + "please be fully aware of the potential risks before doing so!, dubbo version: 3.2.10, current host: 192.168.107.130, error code: 0-28. This may be caused by Change of accesslog file path not allowed. , go to https://dubbo.apache.org/faq/0/28 to find instructions.

dubbo协议配置,不设置accesslog访问日志配置项。

yml 复制代码
# 删除这些
- protocolConfig.setAccesslog(false);
- protocolConfig.setAccesslog("false");

3.8 Spring应用上下文刷新两次

这些信息在应用启动日志里出现两次,ContextRefreshedEvent事件会被触发两次,Spring以父子容器模式运行。

log 复制代码
Initializing Spring embedded WebApplicationContext
Root WebApplicationContext: initialization completed

Tomcat initialized with port(s): 8080 (http)
Tomcat initialized with port(s): 18180 (http)

应用里有基于监听ContextRefreshedEvent事件的逻辑,可能会存在两次运行的风险。

防止重复触发

ContextRefreshedEvent使用注意事项

  • 方案一:增加一个是否初始化的标识,进行初始化前判断标识。
  • 方案二:改为监听ApplicationReadyEvent事件,只会触发一次。
java 复制代码
/**
 * 并发开关
 */
private final AtomicBoolean concurrentSwitch = new AtomicBoolean(false);

if (concurrentSwitch.compareAndSet(false, true)) {
    // do something
}

先前,18180 端口是以 Jetty 服务器进程启动,不是 Tomcat。

父子容器,应该是 8080 和 18180 都使用 Tomcat 容器启动 引入。

应用以 父容器 为主线。可以查看对象地址

log 复制代码
receive event org.springframework.context.event.ContextRefreshedEvent[source=org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@34766f4b, started on Wed Jan 10 10:07:53 CST 2024, parent: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@2dd80673]

receive event org.springframework.context.event.ContextRefreshedEvent[source=org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@2dd80673, started on Wed Jan 10 10:07:41 CST 2024]

3.9 应用未暴露18180端口

dubbo应用可能未依赖spring-boot-starter-web,未启动Servlet容器,进而未暴露18180端口。

因为18180端口暴露依赖于Servlet容器启动。

【可能解法】增加spring-boot-starter-web依赖可以解决

xml 复制代码
<!-- spring-boot -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

3.10 RPC调用消费者端反序列化响应对象时数据丢失一条

[FEATURE] 开启JSONWriter.Feature.ReferenceDetection序列化有java.util.List类型成员引用的对象能得到"$ref"序列化结果 · Issue #

RPC调用响应结构中的List某一条数据丢失问题,响应结构中存在外层字段引用List中的元素($ref),是fastjson2的问题,升级到fastjson2-2.0.46解决。

3.11 fastjson2 JSON反序列化异常

com.alibaba.fastjson2.JSONException: skip not support type INT32 68 · Issue #1257 · alibaba/fastjson

本问题是fastjson2的问题,升级到fastjson2-2.0.46解决。

log 复制代码
Caused by: org.apache.dubbo.remoting.RemotingException: java.io.IOException: org.apache.dubbo.common.serialize.SerializationException: com.alibaba.fastjson2.JSONException: skip not support type INT32 68

Caused by: org.apache.dubbo.remoting.RemotingException: java.io.IOException: org.apache.dubbo.common.serialize.SerializationException: com.alibaba.fastjson2.JSONException: skip not support type INT32 69

4. 应用部署后检查

应用观测指标

  • 收集观测指标

应用日志中搜索18180关键词

log 复制代码
> message:"18180" 

Tomcat started on port(s): 18180 (http) with context path ''

Tomcat initialized with port(s): 18180 (http)

应用本地启动并访问

http://localhost:18180/metrics

若指标URL访问不了,请检查下面这些配置项

yml 复制代码
management.server.port=18180
#management.server.base-path=
management.server.servlet.context-path=
management.endpoints.web.base-path=
management.endpoints.web.exposure.include=prometheus
management.endpoints.web.exposure.exclude=metrics
management.endpoints.web.path-mapping.prometheus=metrics

可观测工作台

应用名里搜索

triple协议

1.应用启动日志里搜索tri协议或8506端口

log 复制代码
ZookeeperRegistry -  [DUBBO] Register: tri://*.*.*.*:8506/com.xxx.consumer.api.Xxx

2.DubboKeeper工作台

内存满了,数据可能未及时更新

页面里查找8506

5. 升级进度

Dubbo-3.2升级进度表-飞书表格(配置各个环境的升级统计图)

相关推荐
修己xj8 分钟前
SpringBoot解析.mdb文件实战指南
java·spring boot·后端
Cyber4K23 分钟前
【Kubernetes专项】K8s 控制器 DaemonSet 从入门到企业实战应用
云原生·容器·kubernetes
lpfasd12326 分钟前
Spring Boot 定时任务详解(从入门到实战)
spring boot·后端·python
切糕师学AI34 分钟前
RKE(Rancher Kubernetes Engine) 是什么?
云原生·容器·kubernetes·rancher
码农小卡拉1 小时前
Prometheus 监控 SpringBoot 应用完整教程
spring boot·后端·grafana·prometheus
麦兜*1 小时前
深入剖析云原生Service Mesh数据平面Envoy核心架构:基于xDS协议与WebAssembly实现动态流量管理与安全策略的微服务治理实战指南
云原生·架构·service_mesh
牛奶咖啡131 小时前
Prometheus+Grafana构建云原生分布式监控系统(十五)_Prometheus中PromQL使用(二)
云原生·prometheus·集合运算·对查询结果排序·直方图原理·统计掉线的实例·检查节点或指标是否存在
计算机毕设VX:Fegn08951 小时前
计算机毕业设计|基于springboot + vue球鞋购物系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
苏渡苇1 小时前
用 Spring Boot 项目给工厂装“遥控器”:一行 API 控制现场设备!
java·人工智能·spring boot·后端·网络协议·边缘计算
像少年啦飞驰点、2 小时前
零基础入门 Spring Boot:从“Hello World”到独立可运行 Web 应用的完整学习闭环
java·spring boot·web开发·编程入门·后端开发