分布式场景下,如何设计唯一键?
我想到的思路有如下几种:
方法1、集群中每个机器分配一个唯一的id,比如用1、2、3、4来标识,那么每个机器生成唯一键的时候,只需要考虑在自己内部唯一即可,然后加上个用自己的机器id的前缀或者后缀。
这种方法最简单,实现起来也方便。
方法2、用zookeeper做一个分布式锁,在生成id的时候,先获取这个锁,然后生成唯一键,然后释放,然后下一次生成。
方法2.1、类似于方法2,我们可以单独写一个应用来生成唯一id,而让其它需要唯一键的地方,来请求这个服务。
方法3、数据库sequence方法,比较早的系统很多使用了这种方法。
3.1通过设置每个DB集群中自增 ID 起始点(auto_increment_offset),将各个集群的ID进行绝对的分段来实现全局唯一。当遇到某个集群数据增长过快后,通过命令调整下一个 ID 起始位置跳过可能存在的冲突。优点是实现简单,且比较容易根据 ID 大小直接判断出数据处在哪个集群,对应用透明。缺点是维护相对较复杂,需要高度关注各个集群 ID 增长状况。
比如集群1的id从0开始,集群2从10000开始,集群3从20000开始。。。当然起点还可以跨度更大。
3.2通过设置每个DB集群中自增 ID 起始点(auto_increment_offset)以及 ID 自增步长(auto_increment_increment),让目前每个集群的起始点错开 1,步长选择大于将来基本不可能达到的切分集群数,达到将 ID 相对分段的效果来满足全局唯一的效果。优点是实现简单,后期维护简单,对应用透明。缺点是第一次设置相对较为复杂。
比如集群中三个机器a,b,c,那么各自起点设置为1、2、3,自增步长为8,那么机器a的id为1、9、17、25。。。
这也是目前使用最广泛的一种方式。
分布式的唯一键最好不要自增的,这样会给以后的进一步扩展带来不便,也就是我不建议使用第三种方式。