为什么存在全局ID这个问题?
在分布式环境下,数据库是可以拆分(sharding)的,一张表的自增机制(比如MySQL)只能保证该表唯一,在 数据合并到历史库,迁移或查询,如果出现id冲突无异于噩梦。那么业界有哪些方案呢?
- UUID
首先,UUID有以下几部分组成:- 当前日期和时间,UUID的第一个部分与时间有关,如果你在生成一个UUID之后,过几秒又生成一个UUID,则第一个部分不同,其余部分相同。
- 时钟序列
- 全局唯一的IEEE机器识别号。如果有网卡,从网卡MAC地址获得,没有网卡从其他地方获得。
优势:API简单、易用。
不足: 占用空间大,字符串本身无法加工,可读性不强。
- ID生成表模式
使用Mysql自增长ID的机制,先创建单独的数据库,然后创建一个表:CREATE TABLE `tickets` { `id` bigint(20) unsigned NOT NULL auto_increment, `stub` char(1) NOT NULL default '', PRIMARY KEY(`ID`), UNIQUE KEY `stub` (`stub`) } ENGINE=MyISAM
可以使用 如下的SQL,在一个事务里提交
REPLACE INTO ticket(stub) VALUES('a'); SELECT LAST_INSERT_Id();
这个方案优势简单易用,也有一定的高可用性方案,不足是使用了mysql数据库的独特语法 REPLACE INTO
- redis生成ID
Redis的所有命令操作都是单线程的,本身提供像 incr 和 incrby这样的自增原子命令,所以能保证生成的ID肯定是唯一有序的。
优点:不依赖与数据库,灵活方便,且性能高于数据库;数字ID天然排序,对分页或者需要排序的结果很有帮助。
缺点:如果系统中没有Redis,还需要引入新的组件,增加系统复杂度;需要编程编程和配置的工作量比较大。 - Snowflake
Twitter开发了一套全局的ID生成服务:Snowflake。snowflake系统生成64位的ID。由3部分组成:- 41位的时间序列(精确到毫秒,41位的长度可以使用69年)
- 10位的机器标识(10位的长度最多支持部署1024个节点)
- 12位的计数顺序号(12位的计数顺序号支持每个节点每毫秒产生4096个ID序号)
优点:高性能、低延迟;独立的应用;按时间有序
缺点:需要独立的开发和部署