分布式唯一ID (一)

169 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第6天,点击查看活动详情

使用场景

分布式唯一ID的使用场景主要用在分库分表的主键使用,那为什么数据库的自增id不可以呢?MySQL部署在一台服务器上,数据量过大时,一台服务器肯定是放不下的,此时就必须要进行分库,在多台服务器上部署你的数据库,把原来的表分散在多台服务器中,此时数据库的自增ID显然不能满足需求,所以需要一个能够生成全局唯一ID的系统是非常必要的。

常见的几种解决方案及优缺点对比

数据库自增

专门搞一个数据库,搞一张表吗,专门用于生成全局唯一id

优点:代码方便,数字id天然排序
缺点:单库单表,并发抗不住,一旦达到每秒几千的高并发;不停的在表里插入数据获取id,表数据会越来越多,还得定期清理,很麻烦

UUID

除数据库主键之外的其他唯一场景,都比较适合,但是这个方案一般不考虑

优点:本地生成,没有并发压力,性能好
缺点:太长了,如果作为数据库主键会导致数据库页分裂比较频繁,存储空间比较大

Snowflake

Twitter开源Snowflake,64个bit位,41位放时间(最多使用69年),10位放机器标识(最多把snowflake程序部署在1024台机器上),12位放序号(每毫秒,每台机器,可以顺序生成4096个ID),最高位1个bit是0

优点:高性能、高并发、分布式、可伸缩,不依赖于数据库,灵活方便,且性能优于数据库。
缺点:有独立部署和维护的成本,有时钟回拨的问题(由于每台机器上的时钟不可能完全同步)

Redis自增机制

可以使用Redis的原子操作INCR和INCRBY来实现,可以使用Redis集群来获取更高的吞吐量。比如5台机器,那么每台机器的初始值依次为1、2、3、4、5,每台机器的自增步长是5,第1台机器就是1、6、11、16、21,第2台机器就是2、7、12、17、22,以此类推,直到第5台机器就是5、10、15、20、25

优点:可以不用额外的开发,一般公司都有redis的集群
缺点:客户端需要自己去封装,如果基于Jedis去封装,客户端需要写死Redis的机器数量,那么就会导致扩容麻烦。

基于时间+业务id的组合

比如打车软件,可以用时间戳+起点编号+车牌号作为一个id,业务组合上是不会重复的,在比如订单号,可以用时间戳+用户id,同样一般也不会重复

优点:实现简单、没有并发扩容之类的问题
缺点:有些业务场景根本不可能通过业务来组合

flickr

flickr(雅虎旗下的图片分享平台)的数据库唯一id生成方案
CREATE TABLE uid_sequence (  

  id bigint(20) unsigned NOT NULL auto_increment,  

  stub char(1) NOT NULL default '',  

  PRIMARY KEY  (id),  

  UNIQUE KEY stub (stub)  

) ENGINE=MyISAM;

REPLACE INTO uid_sequence (stub) VALUES ('test');  

SELECT LAST_INSERT_ID();

replace into语法替代insert into,避免表行数过大,一张表就一行数据,然后再select获取这个表的最新id

这个方案本质跟第一个方案没区别,唯一优化就是用replace into替代了insert into,避免表数据量过大,缺点也在于数据库并发能力不高,所以适用场景,就是分库分表的时候,低并发,用这个方案生成唯一id,低并发场景下可以用于生产

Leaf

Leaf 提供两种生成的ID的方式(号段模式和snowflake模式),可以同时开启两种方式,也可以指定开启某种方式(默认两种方式为关闭状态),Leaf具备高可靠、低延迟、全局唯一等特点。