设想公司有两个datacenter.
1.出于性能考虑, 每个datacenter都有独立的zookeeper.
2.datacentor内有若干snowflake的实例,都放在docker里面运行, 通过RESTful API来生成全局流水号.
可批量生成, 比如每次生成8000个流水号.
3.datacentor用kubernetes来管理所有的docker实例.
那么, 我们知道, snowflake需要两个关键配置: datacentorId和workerId. 一般在kubernetes环境, 我们可以把datacentorId和workerId放在kubernetes的configMap中. 但configMap也有不足之处:
1. 需要人工管理workerId的分配, 并且手动将分配的workerId配置到configMap.
2. 不能从技术上杜绝workerId重复的可能.
3. 不能动态跟踪实际活动的worker的变化, 不能动态分配workerId和动态回收workerId.
综上, 我们希望实现这样的功能:
1. datacenter是极少变化的, 所以可以放到kubernetes的configMap中.
2. workerId将结合zookeeper, 实现动态分配和回收, 不需要人工干预.
原理:
1. docker容器启动后, 启动snowflake服务实例.
2. snowflake服务尝试在zookeeper中创建名"workerIdN"的临时节点(0<=N<=31>), 如果节点已经存在则跳过, 如果创建成功则立即终止,从0到31一共尝试32次; 如果32次都没成功, 就是说已经有32个snowflake实例了, 则实例数量已经饱和, 该snowflake将不能提供流水号生成服务.
在该临时节点中可以存储当前docker容器的HOSTNAME, 便于跟踪调试. kubernetes确保了该HOSTNAME是唯一的.
3. 创建临时节点workerIdN成功后, snowflake服务从configMap中取得datacenterId, 完成初始化, 开始对外提供基于RESTful的流水号生成服务.
这样, 在configMap中就不需要配置workerId. 随着容器的启动和下线, workerId就可以实现动态分配. 当然这需要一些简单的开发工作, 再次就不赘述了.