分布式发号器-Fly

引言

  前不久看到一篇文章,如何做一个靠谱的发号器,觉得是个挺好的设计,于是使用Java实现了一番。

Fly

  发号器,取名fly的意思是,像有无数飞虫一样,不断产生,取之不尽。查看项目地址

持久化

  UID的生成记录会写入ZooKeeper,服务初始化/重启时从ZooKeeper读取配置信息。使用初始化作为持久化的原因是,ZooKeeper是强一致的,在全局单调ID的生成模式下,如果主服务器宕机,可以切换备服务器工作,备服务器从ZooKeeper读取配置,保证发出的ID是唯一的。
  如果采用MySQL和Redis产生ID的实现,由于MySQL和Redis的复制机制无法保证强一致,当MySQL或Redis发生主备切换,备机尚未完全同步的话,还是会发出重复的ID。

通信协议

  实现TLV格式的协议。

高可用方案设计

  对于全局单调ID的生成,需要使用主备模式;对于全局唯一ID的生成,主备模式和负载均衡模式均可实现。在实际使用时,我们倾向于全局单调ID使用主备模式,全局唯一ID使用负载均衡模式部署服务。

主备模式

架构图

选主

  部署服务的实例会在zk进行master节点抢占,抢占成功的实例会成为master,执行id的生成和分配。其他服务器会成为备服务器,执行客户端请求的转发,保障高可用。

ID的生成规则

  全局单调性,目前实现是一个不断递增的整数。

主备切换

  当前运行的服务端会写到zk里,如果异常/下线将触发事件通知其他运行实例进行抢占执行。注意,因为服务端实现了转发,对客户端来说是无感知的,当客户端连接原master异常时,会自动尝试连接其他服务地址。

缺点

  服务非负载均衡。

负载均衡模式

架构图

部署

  所有服务实例都是平等的对外提供服务。没有主从之分。

ID的生成规则

  基于Twitter的SnowFlake算法,具体规则:参考

服务宕机

  客户端自动尝试连接其他服务地址。

缺点

  UUID的取用非全局单调。

主要代码

FlyService

  接收处理客户端请求,默认端口是8888。对于当前非master的服务实例,将执行转发请求到master服务实例。

ForwardService

  提供转发服务。具体实现是维护到master的连接池,同时当有请求发出的时候,将异步结果获取转为同步。

StateMachine

  维护当前服务实例的状态,是否是master,是否avaliable等。当有master状态转变时,需要实时更新资源。

FlyManager

  负责与zk的交互,执行master抢占和监听。

TODO

  1. 考虑到如果zk服务出现异常,我们可以降级到通过数据库实现UUID生成。
  2. 转发协议,压测转发处理的性能,以及连接池的优化;客户端连接管理。
  3. 完成客户端实现。