生成全局唯一Id

本文探讨了生成全局唯一ID的方法与实现细节,包括UUID、时间戳+随机数及优化后的62进制时间戳策略,分析了各自优缺点,并提供了一种改进的62进制时间戳生成ID的方法,旨在提供高效且唯一的ID生成解决方案。

生成全局唯一Id

参考了: http://www.cnblogs.com/heyuquan/p/global-guid-identity-maxId.html

  1. GUID
import uuid
uuid.uuid1()

优点: 确保唯一, 速度快

缺点: 太长, 不友好, 不好索引

  1. 数据库唯一索引

时间戳加上随机数,然后通过数据库做唯一性校验

import time
import random
import string

m = time.strftime('%y%m%d%H%M%S') + ''.join([random.choice(string.lowercase + string.digits) for _ in range(5)])
#检查m在数据库中是否存在,存在则重复上述过程,不存在则存入数据库并返回

优点:适合简单应用,id较短,有一定亲和力

缺点:每秒id总数有限制,并发越大性能越低, 加大数据库访问压力,需要锁表

优化:将时间戳转成62进制数

digit62 = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
#整数转化为62进制字符串
#入口:
#   x : 整数
#返回: 字符串
def int_to_str62( x ):
    try:
        x=int(x)
    except:
        x=0
    if x<0:
        x=-x
    if x==0:
        return "0"
    s=""
    while x>=62:
        x1= x % 62
        s = digit62[x1]+s
        x = x // 62
    if x>0:
       s = digit62[x]+s
    return s

#62进制字符串转化为整数
#入口:
#   s : 62进制字符串
#返回: 整数
def str62_to_int( s ):
    x = 0
    s = str(s).strip()
    if s=="":
        return x
    for y in s:
        k = digit62.find(y)
        if k>=0:
           x=x*62+k
    return x

import time
import random
import string

t = time.strftime('%y%m%d%H%M%S')
cut = [ t[i:i+2] for i in range(0, len(t), 2) ]
62t = ''.join([ int_to_str62(int(x)) for x in cut])

m = 62t + ''.join([random.choice(string.lowercase + string.digits) for _ in range(6)])

再ps. 有人说random.choice慢而且随机不均匀,我就写了两个小程序测试一下

import random
import time
import string
import timeit
import hashlib
import uuid
import threading

def randomchoice():
    return ''.join([ random.choice(string.lowercase + string.digits) for _ in range(6)])

def _time(f, n=1000000):
    print 'start timeit function ', f
    t = timeit.timeit(f, number=n)
    print 'repeat %s times and used %ss' % (n, t)
    print 'end timeit function ', f
    print

_time(randomchoice)

result

start timeit function  <function randomchoice at 0x2a7d6e0>
repeat 1000000 times and used 3.97338795662s
end timeit function  <function randomchoice at 0x2a7d6e0>

随机分布

from random import choice
import string
import collections
from matplotlib.pyplot import plot, show, barh, yticks, xlabel, title, figure
import numpy as np

tables = string.ascii_letters + string.digits

counter = collections.Counter()

for _ in range(1000000):
    counter[choice(tables)] += 1

alphats = counter.keys()
y_pos = np.arange(len(alphats))
freq = counter.values()

figure(figsize=(100,100))
barh(y_pos, freq, align='edge', alpha=1, height=0.05)
yticks(y_pos, alphats)
xlabel('frequence')
title('random choice')

show()

结果图:


可见分布还是比较平均的

  1. like mongo objectid
      时间 + md5(hostname) + pid + 递增id

import struct
import socket
import os
import time
from hashlib import md5
import threading
import random
import binascii

_inc = random.randint(0, 0xFFFFFF)
_inc_lock = threading.Lock()

oid = ""

oid += struct.pack(">i", int(time.time()))

m = md5()
m.update(socket.gethostname())
oid += m.digest()[0:3]

oid += struct.pack(">H", os.getpid() % 0xFFFF)

_inc_lock.acquire()
oid += struct.pack(">i", _inc)[1:4]
_inc = (_inc + 1) % 0xFFFFFF
_inc_lock.release()

print len(oid)
print binascii.hexlify(oid)
在分布式系统中生成全局唯一ID(Global Unique ID,GUID)是解决数据分库分表、消息队列、日志追踪等场景下唯一标识问题的关键。常见的生成全局唯一ID的方法或算法包括以下几种: ### 1. UUID(Universally Unique Identifier) UUID 是一种标准化的唯一标识生成方式,通常由 128 位数字组成,以 36 位字符串形式表示。UUID 的版本包括时间戳、MAC 地址、随机数等生成方式。虽然 UUID 保证了全局唯一性,但其长度较长,且不具备有序性,不利于数据库索引优化[^2]。 ```python import uuid print(uuid.uuid4()) # 生成基于随机数的 UUID ``` ### 2. Snowflake 算法 Snowflake 是 Twitter 开源的一种分布式 ID 生成算法,生成ID 是一个 64 位的整数,包含时间戳、工作节点 ID 和序列号等信息。其优点是生成速度快、有序、适合数据库索引使用。但需要确保节点 ID唯一性,并且在高并发下需处理序列号冲突问题[^1]。 ```python # 伪代码示例 class Snowflake: def __init__(self, node_id): self.node_id = node_id self.last_timestamp = -1 self.sequence = 0 self.sequence_bits = 12 self.max_sequence = ~(-1 << self.sequence_bits) def next_id(self): timestamp = self._current_timestamp() if timestamp < self.last_timestamp: raise Exception("时钟回拨") if timestamp == self.last_timestamp: self.sequence = (self.sequence + 1) & self.max_sequence if self.sequence == 0: timestamp = self._til_next_millis(self.last_timestamp) else: self.sequence = 0 self.last_timestamp = timestamp return (timestamp << (self.sequence_bits + node_bits)) \ | (self.node_id << self.sequence_bits) \ | self.sequence ``` ### 3. 号段模式(Segment ID) 号段模式通过从中心化服务(如数据库)批量获取一段 ID 号段,本地缓存并逐个分配。该方法减少了对中心服务的依赖频率,提高了性能,但需要处理号段分配冲突和节点故障转移问题[^2]。 ### 4. Redis 生成 利用 Redis 的原子操作(如 `INCR`)生成递增 ID。Redis 提供了高性能的单点递增能力,适用于中小规模的系统。但在大规模分布式系统中,Redis 成为单点瓶颈,需引入集群部署和分片机制[^1]。 ```python import redis r = redis.StrictRedis(host='localhost', port=6379, db=0) unique_id = r.incr("global_id") print(unique_id) ``` ### 5. Leaf(美团点评开源) Leaf 是美团开源的一种分布式 ID 生成服务,支持号段模式和 Snowflake 模式。Leaf 提供了更高的可用性和扩展性,适用于大规模分布式系统。 ### 6. 其他变种算法 - **TinyID**:基于号段模式的开源分布式 ID 生成方案。 - **UidGenerator(百度开源)**:基于 Snowflake 的改进版本,解决了时间回拨问题。 - **RidGenerator(滴滴开源)**:结合时间戳和随机数生成唯一 ID。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值