python UUID与雪花ID
在分布式架构中经常需要要使用到唯一的ID值,该ID值的生成一般会要求:全局唯一性、递增性、高可用性、高性能性。这时候常见的方法有使用UUID和雪花算法实现ID两种机制。UUID这个比较好理解,在linux下/etc/fstab中我们经常就会用uuid=xxx代表某个分区。而雪花算法SnowFlake是Twitter公司采用的一种算法,目的是在分布式系统中产生全局唯一且趋势递增的ID。这里分别用python来实现上如何实现生成这种某一值。
一、python下生成uuid
python下直接有个uuid模块,只需提供了以下几种常见的uuid生成方法,可以根据实际需要选择任一种:
1>>> import uuid
2# make a UUID based on the host ID and current time
3>>> uuid.uuid1() # doctest: +SKIP
4UUID('a8098c1a-f86e-11da-bd1a-00112444be1e')
5# make a UUID using an MD5 hash of a namespace UUID and a name
6>>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org')
7UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e')
8# make a random UUID
9>>> uuid.uuid4() # doctest: +SKIP
10UUID('16fd2706-8baf-433b-82eb-8c7fada847da')
11# make a UUID using a SHA-1 hash of a namespace UUID and a name
12>>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org')
13UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d')
二、python雪花id生成
雪花id的生成原理如下:
组成部分(64bit)
1.第一位 占用1bit,其值始终是0,没有实际作用。
2.时间戳 占用41bit,精确到毫秒,总共可以容纳约69年的时间。
3.工作机器id 占用10bit,其中高位5bit是数据中心ID,低位5bit是工作节点ID,做多可以容纳1024个节点。 4.序列号 占用12bit,每个节点每毫秒0开始不断累加,最多可以累加到4095,一共可以产生4096个ID。
SnowFlake算法在同一毫秒内最多可以生成多少个全局唯一ID呢:: 同一毫秒的ID数量 = 1024 X 4096 = 4194304
代码如下:
1# coding: utf-8
2import time
3class InvalidSystemClock(Exception):
4 """
5 时钟回拨异常
6 """
7 pass
8# 64位ID的划分
9WORKER_ID_BITS = 5
10DATACENTER_ID_BITS = 5
11SEQUENCE_BITS = 12
12# 最大取值计算
13MAX_WORKER_ID = -1 ^ (-1 << WORKER_ID_BITS) # 2**5-1 0b11111
14MAX_DATACENTER_ID = -1 ^ (-1 << DATACENTER_ID_BITS)
15# 移位偏移计算
16WOKER_ID_SHIFT = SEQUENCE_BITS
17DATACENTER_ID_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS
18TIMESTAMP_LEFT_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS + DATACENTER_ID_BITS
19# 序号循环掩码
20SEQUENCE_MASK = -1 ^ (-1 << SEQUENCE_BITS)
21# 开始时间截 (2015-01-01)
22TWEPOCH = 1420041600000
23class IdWorker(object):
24 """
25 用于生成IDs
26 """
27 def __init__(self, datacenter_id, worker_id, sequence=0):
28 """
29 初始化
30 :param datacenter_id: 数据中心(机器区域)ID
31 :param worker_id: 机器ID
32 :param sequence: 起始序号
33 """
34 # sanity check
35 if worker_id > MAX_WORKER_ID or worker_id < 0:
36 raise ValueError('worker_id值越界')
37 if datacenter_id > MAX_DATACENTER_ID or datacenter_id < 0:
38 raise ValueError('datacenter_id值越界')
39 self.worker_id = worker_id
40 self.datacenter_id = datacenter_id
41 self.sequence = sequence
42 self.last_timestamp = -1 # 上次计算的时间戳
43 def _gen_timestamp(self):
44 """
45 生成整数时间戳
46 :return:int timestamp
47 """
48 return int(time.time() * 1000)
49 def get_id(self):
50 """
51 获取新ID
52 :return:
53 """
54 timestamp = self._gen_timestamp()
55 # 时钟回拨
56 if timestamp < self.last_timestamp:
57 raise InvalidSystemClock
58 if timestamp == self.last_timestamp:
59 self.sequence = (self.sequence + 1) & SEQUENCE_MASK
60 if self.sequence == 0:
61 timestamp = self._til_next_millis(self.last_timestamp)
62 else:
63 self.sequence = 0
64 self.last_timestamp = timestamp
65 new_id = ((timestamp - TWEPOCH) << TIMESTAMP_LEFT_SHIFT) | (self.datacenter_id << DATACENTER_ID_SHIFT) | \
66 (self.worker_id << WOKER_ID_SHIFT) | self.sequence
67 return new_id
68 def _til_next_millis(self, last_timestamp):
69 """
70 等到下一毫秒
71 """
72 timestamp = self._gen_timestamp()
73 while timestamp <= last_timestamp:
74 timestamp = self._gen_timestamp()
75 return timestamp
76if __name__ == '__main__':
77 worker = IdWorker(0, 0)
78 print(worker.get_id())
三、uuid和雪花算法的比较
相比常见的64位数字字母随机数的UUID,使用雪花算法(snowflake)生成雪花数的方法更好,具体比较结果如下:
UUID | 雪花数 | |
---|---|---|
全局唯一 | 支持 | 支持 |
有序,可以支持排序、比较 | 无序 | 支持,大致有序,按时间排序 |
节约存储空间 | 64位数字字母随机组合的字符串 | 19位正整数,更节约存储空间 |
根据UID查询速度快,且稳定 | 数据库根据索引查询速度不稳定 | 数据库根据索引查询速度快且稳定 |
防止被恶意推测 | 支持 | 支持 |
带有业务属性 | 无 | 无 |
限制条件 | 全局唯一性依赖于生成随机数的种子和随机数的长度 | 需要单独部署雪花数生成器;依赖于生成器的时间戳。 |
捐赠本站(Donate)
如您感觉文章有用,可扫码捐赠本站!(If the article useful, you can scan the QR code to donate))
- Author: shisekong
- Link: https://blog.361way.com/python-uuid-snowflake/6536.html
- License: This work is under a 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议. Kindly fulfill the requirements of the aforementioned License when adapting or creating a derivative of this work.