记一次Dubbo版本升级历程

1.背景

发现Dubbo低版本安全问题,要求各业务团队升级dubbo版本到安全的版本(2.7.22及以上版本)

原因是因为dubbo泛型调用时存在反序列化漏洞,可能导致恶意代码执行。

2.Dubbo 2.7.1 -> 2.7.23 的几个较大的更新

1.服务配置中心模型(2.7.3)

  • https://github.com/chickenlj/incubator-dubbo-website/blob/3bcaeeddbc1dac69953ac371099d8528153935ee/docs/zh-cn/dev/configcenter/design.md

2.消费端线程模型(2.7.5)

老的线程池模型

记一次Dubbo版本升级历程_第1张图片

  1. 业务线程发出请求,拿到一个 Future 实例。
  2. 业务线程紧接着调用 future.get 阻塞等待业务结果返回。
  3. 当业务数据返回后,交由独立的 Consumer 端线程池进行反序列化等处理,并调用 future.set 将反序列化后的业务结果置回。
  4. 业务线程拿到结果直接返回

2.7.5 版本引入的线程池模型

记一次Dubbo版本升级历程_第2张图片

  1. 业务线程发出请求,拿到一个 Future 实例。
  2. 在调用 future.get() 之前,先调用 ThreadlessExecutor.wait(),wait 会使业务线程在一个阻塞队列上等待,直到队列中被加入元素。
  3. 当业务数据返回后,生成一个 Runnable Task 并放入 ThreadlessExecutor 队列 业务线程将 Task 取出并在本线程中执行:反序列化业务数据并 set 到 Future。
  4. 业务线程拿到结果直接返回

这样,相比于老的线程池模型,由业务线程自己负责监测并解析返回结果,免去了额外的消费端线程池开销。

3.结果值缓存(2.7.7)

使用url转字符串作为key,预设三种缓存实现:

  • org.apache.dubbo.cache.support.lru.LruCacheFactory
  • org.apache.dubbo.cache.support.threadlocal.ThreadLocalCacheFactory
  • org.apache.dubbo.cache.support.jcache.JCacheFactory

3.升级遇到的问题

3.1 序列化冲突

与低版本(2.7.1)的provider通讯报序列化解析失败。

原因:

  1. oppo-framework重写kryo序列化协议和protobuff序列化协议
  2. 其中重写的protobuff协议用的contentTypeId在后续dubbo版本更新中被使用。
  3. dubbo 2.7.1版本通过在/META-INF/dubbo-internal/com.xxxxx 自定义序列化协议会覆盖原生的实现。但是在高版本(2.7.x)开始,类加载器增加overrwrite属性,只有为true才能覆盖原生实现。而默认/META-INF/dubbo-internal/ 目录下的类加载策略的overwrite = false,如果出现重复key,则对新的key打印一行错误日志。
  4. pt

记一次Dubbo版本升级历程_第3张图片

dubbo 协议

记一次Dubbo版本升级历程_第4张图片

Dubbo 数据包分为消息头和消息体,消息头用于存储一些元信息,比如魔数(Magic),数据包类型(Request/Response),消息体长度(Data Length)等。消息体中用于存储具体的调用消息,比如方法名称,参数列表等。下面简单列举一下消息头的内容。

记一次Dubbo版本升级历程_第5张图片

  1. 类加载策略

记一次Dubbo版本升级历程_第6张图片

  • 指定加载目录
  • 选择类加载器
  • 指定的包不被加载
  • 是否支持覆盖

解决方法:

  1. 无视新增 contentTypeId,继续将该 contentTypeId 当作 protostuff 序列化实现处理。
  2. 将原本放在 /META-INF/dubbo-internal/org.apache.dubbo.common.serialize.Serialization SPI 配置文件改为放到/META-INF/dubbo/org.apache.dubbo.common.serialize.Serialization 下,该目录下的类加载策略 overwitte = true,如果发现有重复的实现则覆盖。

你可能感兴趣的:(dubbo,java,后端,分布式)