Dubbo使用Kryo序列化协议的思考
本文是使用Dubbo
过程中的一些思考,不足以作为参考,只为留存记录。
前言
Dubbo
官方推荐使用kryo
或者fst
作为RPC
序列化协议,原因是这两款序列化协议,性能显著优于其他序列化协议。虽然高效,但其实Dubbo
对这两款的支持却不是那么理想,导致使用过程中出现了一些问题
多服务下kryo
序列化问题
Q1、无法使用kryo
类索引红利
在多模块协作的系统中,无法保证服务提供方和消费方
DTO
数量以及注册顺序的一致,可能A作为服务提供方,提供了DTO
,而B作为消费方,可能同时消费A、C的服务,同时自身也对外提供服务,在使用Kryo
序列化时,需要同时注册A、B、C服务的DTO
。
例如A系统的SerializationOptimizer
实现
1 | public class ASerializationOptimizerImpl implements SerializationOptimizer { |
B系统的SerializationOptimizer
实现
1 | public class BSerializationOptimizerImpl implements SerializationOptimizer { |
这里需要说明的是,kryo
之所以高效,不仅仅是因为其二进制序列化,更由于其可以预先为待序列化的类指定索引,在RPC
传输过程中,只需要使用索引代替全类名,在类使用非常频繁的情况下,可以节省大量字节,从而大大提升传输效率。
而Dubbo
似乎也意识到了这个问题,所以将一些使用频繁的类进行了预处理,见org.apache.dubbo.common.serialize.kryo.utils.AbstractKryoFactory#create
但是其中很重要的一处
1 | SerializableClassRegistry.getRegisteredClasses().forEach((clazz, ser) -> { |
使用的是kryo.register(clazz)
,无法指定kryo class index
,这里我分析了一下,可能是为了兼容老的序列化协议,比如json
等,而且SerializableClassRegistry
是很早就有的接口,并没有考虑到类索引的问题。
所以这里要注册的话,只能将项目内所有类都写到同一个jar
中,然后写一个统一的SerializationOptimizer
实现。
这在微服务系统中是无法实现的,因为每个服务必然会提供自己的dto.jar
和dubbo-service.jar
,而且服务之间也不可能依赖其他所有的服务,所以这一条无法满足。
这样一来,类的注册顺序不能保证,类的数量也无法保证,所以Dubbo
的kryo
序列化只能说在一定程度上提升了效率,但是并没有完全发挥出kryo
的性能优势。
Q2、社区不活跃
虽然阿里重启了
Dubbo
,并且加入了Apache
进行孵化,但是社区相较于Spring Cloud
,还是不够活跃,而且阿里的开源产品,多多少少带了点阿里内部的味道,不如Spring Cloud
通用和考虑周全。一些功能我们不需要(比如dubbo
注册时的一堆参数,很多都是需要阿里的一套开发体系才能使用到),我们需要的又迟迟不添加(kryo
的ClassId
支持)。
所以目前项目已经全面切换到Spring Cloud Kubernetes
,有时间也会总结一下Dubbo
切换到Spring Cloud
的经验,以及在云原生时代Spring Cloud
所做出的努力。