58集团RPC框架SCF的设计与实践( 二 )


上述过期算法存在有两个关键点需要注意:

  1. 过期时间存在误差 , 误差范围是每个格子代表的时间 。
  2. 扫描任务过期的线程应该和执行过期操作的线程独立 , 避免执行过期操作影响到后续任务的过期扫描 。
3.5序列化
在网络中传输的数据只能是 0 和 1 组成的二进制数据 , 而通常我们请求的数据信息是面向对象中具体类的对象 , 序列化就是实现对象的状态信息转换为可以存储或传输的形式的过程 , 反序列化是序列化的逆过程 。
SCF 框架采用了自定义的序列化实现方式 , 下面主要介绍序列化是如何实现非对称序列化和泛型序列化 。
【58集团RPC框架SCF的设计与实践】3.5.1非对称序列化
互联网是一个变化非常快的行业 , 在发布一个接口之后 , 随着业务的发展必然会产生对接口传输对象进行调整的情况 , 因此就有了增加或删除类中的成员变量的需求 。如果不能支持服务方和调用方的类存在非对称的成员 , 业务升级将会非常麻烦 。
SCF 序列化对非对称类处理的思想是对类的成员变量进行编号 , 在写数据流的过程中 , 成员变量根据编号 (id)+ 数据长度 (length)+ 数据 (value) 的方式依次写入二进制流 , 反序列化则从流中先读取 id , 判断需要赋值的类是否存在该 id 的成员 , 如果存在继续读取长度和数据部分 , 如果不存在该 id , 则根据读取的长度跳过二进制流中该 id 成员对应的数据部分 , 从而实现忽略不存在成员的目的 。
58集团RPC框架SCF的设计与实践

文章插图
image
针对以上两个版本的实体 , 左边是编号 1、2、3 的成员 , 右边是 1、4 的成员 。序列化和反序列化过程如下:
58集团RPC框架SCF的设计与实践

文章插图
image

58集团RPC框架SCF的设计与实践

文章插图
image
使用基本的 id + length + value 的方式可以实现非对称序列化 , 但是对所有的成员都需要写入 id 和 length 两个特殊的标识 , 增加了二进制数据的大小 。而对于基本类型 , 其实长度是已知的 。通过对数据类型按下面 type 进行划分:
58集团RPC框架SCF的设计与实践

文章插图
image
只需要 3bit 就可以表示说要的数据类型 , 因此采用 tag = (id << 3)|type 的方式 , 将 type 嵌入到 tag 字段中 , 实现基本类型的数据只需要写入 tag 数据 , 不需要写入 length 字段 , 有效减少二进制数据大小 。
3.5.2泛型序列化
泛型序列化是指在类中存在非具体类型成员变量(JAVA 中的基类 Object)的对象序列化 。
SCF 中使用全限定类名 hash 的方式 , 为每一个类生成唯一 typeId , 在写入泛型成员时 , 先写入类的 typeId , 再写入 value 数据 。读取时一样通过先读取 typeId , 查找具体类型 , 再根据类型读取 value 数据 。
四、服务注册与发现调用方通过网络调用服务方 , 必须要知道服务方节点的 IP 列表 , 才能发起调用 。最原始的方式是通过在调用方使用配置文件的方式指定 , 但是这种方式在实际使用中不能动态感知服务方节点的变化 , 不够灵活也无法时间服务的自动化扩缩容 。
服务注册与发现即自动发现服务的节点信息 , 并且调用方能及时感知服务方节点的变化情况 , 自动调整流量切换到新的节点 。
58集团RPC框架SCF的设计与实践

文章插图
image
SCF 使用 ETCD 集群管理服务节点 , 每一个服务节点对应 ETCD 中的一个 key , 并且为 key 设置一个 TTL 过期时间 。通过心跳刷新 TTL 的方式维持服务节点在线状态 。为隔离 ETCD 集群与业务部署环境 , 避免服务节点的增加造成 ETCD 集群的连接数过高等问题 , 封装了一层服务管理节点做代理 , 转发服务心跳并维护服务方和调用方的状态信息 。
58集团RPC框架SCF的设计与实践

文章插图
image
当服务节点下线 , ETCD 集群通知服务管理节点对应的 key , 服务管理节点实时推送最新的服务节点列表信息给调用方 , 调用方动态更新并切换流量 。同时为了兼容推送失败的异常情况 , 增加了调用方定时根据时间戳校验拉取的策略 , 保证服务节点信息的最终一致 。


推荐阅读