这里的博客版本都不会被更新维护。查看最新的版本请移步: http://neojos.com
全称Universally Unique Identifier
,UUID
占128bit
,也就是16个英文字符的长度(16byte
),须要强调的是,它的生成无需中心处理程序。html
UUID
被用来标识URN(Uniform Resource Names)
,对于Transaction ID
以及其余须要惟一标志的场景均可以使用它。java
UUID
是空间和时间上的惟一标识,它长度固定,内部中包含时间信息。若是服务器时间存在不一样步的状况,UUID
可能会出现重复。node
UUID
构成基本格式,由6部分组成:mysql
time-low - time-mide - time-high-and-version - clock-seq-and-reserved & clock-seq-low - node
一个URN
示例:f81d4fae-7dec-11d0-a765-00a0c91e6bf6
。sql
由于UUID
占128bit
,16进制数占4bit
,因此转换成16进制0-f
的字符串总共有32位。组成的各个部分具体由几位16进制表示,请查阅 Namespace Registration Template
mongodb
由于UUID
太长且无序,致使其不适合作MySQL
的主键索引。并且MySQL
自带的auto-increment
功能,选择bigint
的话也只占用64bit
。数组
All indexes other than the clustered index are known as secondary indexes. InInnoDB
, each record in a secondary index contains the primary key columns for the row, as well as the columns specified for the secondary index.InnoDB
uses this primary key value to search for the row in the clustered index.If the primary key is long, the secondary indexes use more space, so it is advantageous to have a short primary key.缓存
MongoDB's ObjectId
ObjectId
由占4-byte
的时间戳、3-byte
的机器标识、2-byte
的进程ID
以及3-byte
的计数组成,总共仍是占用96bit
。服务器
这些ID
组成包括时间、机器标识、随机数,在UUID
生成时还使用到MAC
地址。这些参数中时间是关键,保证集群服务器的时钟准确很是重要。分布式
Twitter Snowflake
Twitter Snowflake
生成的ID
占64bit
,跟bigint
大小一致。由41 bit
毫秒精度的时间戳、10bit
的机器ID
以及12 bit
的序列号组成(计数每4096就从新开始一轮),剩下的1 bit
奉献给将来。
做者修改了它的原始设定,将剩下的1 bit
给了时间戳。使用机器MAC
地址的HASH
值做为当前机器的ID
。
服务全局保存最近一次生成ID
的时间戳lastTimestamp
,做为生成新ID
的判断依据,避免时间回溯。详细代码请参照[1]
。
// Block and wait till next millisecond private long waitNextMillis(long currentTimestamp) { while (currentTimestamp == lastTimestamp) { currentTimestamp = timestamp(); } return currentTimestamp; }
同时将sequence
也声明为全局变量,每间隔4096次就从新开始计数。主要用于应对:当时间戳相同时保证生成的ID
是不一样的。
if (currentTimestamp == lastTimestamp) { sequence = (sequence + 1) & maxSequence; if(sequence == 0) { // Sequence Exhausted, wait till next millisecond. currentTimestamp = waitNextMillis(currentTimestamp); } } else { // reset sequence to start with zero for the next millisecond sequence = 0; }
Database Ticket Servers
该方式经过中心的DB
服务来生成惟一自增ID
,但DB
服务的写操做会成为系统的瓶颈。若是后台是单个DB
服务的话,存在单点问题。
参考Flickr
的方法,后台使用两个DB
来生成ID
,其中auto-increment
一个按照奇数步长增加,另外一个按照偶数步长增加。MySQL
内部使用REPLACE
来实现,经过一条冲突的记录,来持续生成自增的主键ID
。
REPLACE
makes sense only if a table has aPRIMARY KEY
orUNIQUE
index. Otherwise, it becomes equivalent toINSERT
, because there is no index to be used to determine whether a new row duplicates another.
结合Twitter Snowflake
对ID
作以下调整:41-bit
的毫秒时间戳、13-bit
的数据逻辑分区以及10-bit
的自增序列。自增序列对1024取余,每一个分区每毫秒内能生成1024
个自增ID
。
Flickr
中各个数据表按照不一样的步长增加,当须要分表的时候就会存在巨复杂的数据迁移问题。为了解决这个问题,便引入了逻辑分区Shard ID
。经过逻辑上的Shard
,将数据分散在不一样的数据表中。这样后续的分库分表均可以经过操做逻辑上Shard
来实现,将DB
从具体的实现中解脱出来。
关于获取MySQL
自增ID
,代码没法批量获取插入的所有自增ID
列表,MySQL
只会返回第一条记录的自增ID
。由于自增ID
是连续的,因此能够经过计算的方式来计算出ID
列表。
If you insert multiple rows using a singleINSERT
statement,LAST_INSERT_ID()
returns the value generated for the first inserted row only. The reason for this is to make it possible to reproduce easily the sameINSERT
statement against some other server.
关于Shard
能够查看本地缓存BigCache
,颇有参考意义(我以为)。
文中介绍了ID
的两种生成方式,核心的区别在于:整个系统的ID
是否支持单调递增。Twitter Snowflake
以及UUID
能够保证生成的数据惟一,但多台服务器的话,没法保证生成的数据有序。而Ticket Servers
经过结合MySQL
的auto-increment
解决了这个问题。
参考文章: