分布式环境下的id生成方法
前几天研究数据库分表分库的问题,其中有一个关键的地方就是生成唯一键的问题,假如数据表有1亿条数据,而且还在不断的增加,这里我们就需要考虑到分表分库,假设我们采用Hash或者是用户取模求余的方法将这个表拆分成10个表,每个表的结构相同,其中有一个主键id,那么10个表中的id需要唯一不同,在单表的时候,使用数据表自增长是没有问题的。当分成10个表后,就无法用到数据库自增长了。 当到这里的时候突然发现oracle数据库的序列真是好东西,在刚刚接触的时候还很郁闷这种设计真是没有mysql获sqlserver中的方便 目前做唯一id的做法基本有三种 1.使用uuid来实现,快速不重复,只是生成的id没有规则 2.使用外部的id分发中心来实现,生存的id简短有规则,缺点是依赖于单点 3.在数据库中做一个计数表来做,有点类是于oracle中的序列 以下内容大部分来自于网络: UUIDUUID的目的,是让分散式系统中的所有元素,都能有唯一的辨识信息,而不需要通过中央控制端来做辨识信息的指定。如此一来,每个人都可以创建不与其它人冲突的UUID。在这样的情况下,就不需考虑数据库创建时的名称重复问题。 一组UUID,是由一串16位组(亦称128位)的16进位数字所构成,是故UUID理论上的总数为216 x 8=2128,约等于3.4 x 1038。也就是说若每纳秒产生1兆个UUID,要花100亿年才会将所有UUID用完。 UUID的标准型式包含32个16进位数字,以连字号分为五段,形式为8-4-4-4-12的36个字符。示例:
? twitter的Snowflake(id分发中心)Snowflake是twitter开源的一款独立的适用于分布式环境的ID生成服务器。生成的ID是64Bits,同时满足高性能(>10K ids/s),低延迟(<2ms)和高可用。与MongoDB ObjectID类似这里生成的ID也是时间上有序的。编码方式也和ObjectID类似,如下: 0???????????41?????51?????64 +-----------+------+------+ |time???????|pc????|inc???| +-----------+------+------+
MongoDB ObjectID(类似UUID的方式)MongoDB中每一条记录都有一个’id’字段用来唯一标示本记录。如果用户插入数据时没有显示提供’id’字段,那么系统会自动生成一个。ObjectID一共12Bytes,设计的时候充分考虑了分布式环境下使用的情况,所以能保证在一个分布式MongoDB集群中唯一。ObjectID格式如下: 0????????4??????7????9??????12 +--------+------+----+------+ |time????|pc????|pid?|inc???| +--------+------+----+------+
最后生成的仍然是一个用16进制表示的串,如 Ticket Server(数据库生存方式)这个是Flickr在遇到生成全局ID问题时采用的办法。利用了数据库中auto_increment的特性和MySQL特有的
CREATE?TABLE?`Tickets64`?( ??`id`?bigint(20)?unsigned?NOT?NULL?auto_increment,??`stub`?char(1)?NOT?NULL?default?'',??PRIMARY?KEY??(`id`),??UNIQUE?KEY?`stub`?(`stub`) )?ENGINE=MyISAM
+-------------------+------+ |?id????????????????|?stub?| +-------------------+------+ |?72157623227190423?|????a?| +-------------------+------+
REPLACE?INTO?Tickets64?(stub)?VALUES?('a'); SELECT?LAST_INSERT_ID(); 另外为了防止这个Ticket Server单点故障,可以设置两个Ticket Server实例。其中一个产生奇数ID,另一个产生偶数ID。 TicketServer1: auto-increment-increment?=?2 auto-increment-offset?=?1 TicketServer2: auto-increment-increment?=?2 auto-increment-offset?=?2 应用交替请求两个Server,这样不仅压力减小一半,故障风险也降低一半。不过这里也有个问题,就是当一台机器故障时,另一台正常机器产生的ID将会领先故障机器一截,可能会造成不再是时间上有序的ID。按照Flickr的说法,这并不影响他们的应用。 Instagram采用的方式(UUID方式)Instagram要将其中存储的图片分片到多个PostgreSQL中,其中生成ID的方案和MongoDB ObjectID类似。整个ID的长度为64Bits,设定为这个长度是为了优化在redis中的存储。ID的编码格式如下:
ID的生成逻辑用PL/PGSQL语言写到PostgreSQL数据库中,当每次插入数据时由数据库自动计算生成。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |