Python实现Twitter Snowflake雪花算法详解与自定义位划分

唐可
唐可
发布时间:2026-10-13 | 5人浏览过
原创

本文详解基于Python实现Twitter Snowflake雪花算法的过程。文章解析了64位ID中符号位、时间戳、机器ID及序列号的划分标准,并结合高QPS场景演示如何自定义位分配以优化扩展性。重点介绍了通过抛出InvalidSystemClock异常来处理时钟回拨问题,确保ID生成的唯一性与系统稳定性。

本文详细解析了如何使用Python实现Twitter Snowflake雪花算法,通过具体代码示例展示了核心逻辑,为开发者在项目中应用该算法提供实用的参考。

Snowflake算法64位ID结构解析

Snowflake算法由Twitter提出,旨在生成一个64位的整数ID,其结构由多个字段拼接而成。

  • 最高位为1个bit,通常作为符号位,在实际生成中不做处理,保持为0。
  • 接下来的41个bit用于存储时间戳,可支持约69年的跨度。若设定起始时间为2018年,则该方案可使用至2089年;考虑到系统在此周期内通常会经历多次重构,这一时间窗口通常足够。
  • 随后的10个bit用于标识机器ID,理论上可支持1024台机器。一般实践中,前5位代表数据中心ID,后5位代表该数据中心内的机器ID。
  • 最后的12个bit为序列号位,用于在同一毫秒内生成不同的ID。12位最多支持4095个ID,即单台机器在同一毫秒内最多生成4095个ID;若超出此限制,则需等待至下一毫秒继续生成。

基于业务场景的自定义位划分策略

上述64位划分仅为一种标准模式,实际应用中可根据具体业务场景灵活调整各字段的位数分配。以下结合一个具体业务场景进行说明。

  • 当前服务QPS约为10万,预计未来几年内将增长至百万级别。
  • 机器部署于三个地域:上海、北京和深圳。
  • 当前服务器数量约为10台,预计未来将扩展至百台规模。
  • 基于上述场景,可对62位有效ID进行重新划分。鉴于QPS未来可能达到百万,每毫秒请求量约为千级。当前10台机器每台承担百级请求,为保证扩展性,可将序列号位限制为1024(即2的10次方),因此10位序列号已足够。

针对三地部署,可用3bit表示机房位置(共8种状态);当前10台机器并预留至百台扩展,可用7bit表示机器ID(共128种状态)。时间位仍保持41bit。计算剩余位数:64 - 10(序列号)- 3(机房)- 7(机器ID)- 41(时间)- 1(符号位)= 2bit,剩余2bit可用于未来扩展。

时钟回拨问题的处理机制

时钟回拨是雪花算法需要处理的关键问题之一。

由于机器系统时间调整可能导致时间回拨,而雪花算法强依赖单调递增的时间戳。若发生回拨,可能生成重复ID。在上述nextId实现中,通过比较当前时间与上一次时间戳,若当前时间小于上次时间,则判定为回拨,并直接抛出异常以阻止错误ID生成。


# Twitter's Snowflake algorithm implementation which is used to generate distributed IDs.
# https://github.com/twitter-archive/snowflake/blob/snowflake-2010/src/main/scala/com/twitter/service/snowflake/IdWorker.scala

import time
import logging

from .exceptions import InvalidSystemClock


# 64位ID的划分
WORKER_ID_BITS = 5
DATACENTER_ID_BITS = 5
SEQUENCE_BITS = 12

# 最大取值计算
MAX_WORKER_ID = -1 ^ (-1 << WORKER_ID_BITS) # 2**5-1 0b11111
MAX_DATACENTER_ID = -1 ^ (-1 << DATACENTER_ID_BITS)

# 移位偏移计算
WOKER_ID_SHIFT = SEQUENCE_BITS
DATACENTER_ID_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS
TIMESTAMP_LEFT_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS + DATACENTER_ID_BITS

# 序号循环掩码
SEQUENCE_MASK = -1 ^ (-1 << SEQUENCE_BITS)

# Twitter元年时间戳
TWEPOCH = 1288834974657


logger = logging.getLogger('flask.app')


class IdWorker(object):
  """
  用于生成IDs
  """

  def __init__(self, datacenter_id, worker_id, sequence=0):
    """
    初始化
    :param datacenter_id: 数据中心(机器区域)ID
    :param worker_id: 机器ID
    :param sequence: 其实序号
    """
    # sanity check
    if worker_id > MAX_WORKER_ID or worker_id < 0:
      raise ValueError('worker_id值越界')

    if datacenter_id > MAX_DATACENTER_ID or datacenter_id < 0:
      raise ValueError('datacenter_id值越界')

    self.worker_id = worker_id
    self.datacenter_id = datacenter_id
    self.sequence = sequence

    self.last_timestamp = -1 # 上次计算的时间戳

  def _gen_timestamp(self):
    """
    生成整数时间戳
    :return:int timestamp
    """
    return int(time.time() * 1000)

  def get_id(self):
    """
    获取新ID
    :return:
    """
    timestamp = self._gen_timestamp()

    # 时钟回拨
    if timestamp < self.last_timestamp:
      logging.error('clock is moving backwards. Rejecting requests until {}'.format(self.last_timestamp))
      raise InvalidSystemClock

    if timestamp == self.last_timestamp:
      self.sequence = (self.sequence + 1) & SEQUENCE_MASK
      if self.sequence == 0:
        timestamp = self._til_next_millis(self.last_timestamp)
    else:
      self.sequence = 0

    self.last_timestamp = timestamp

    new_id = ((timestamp - TWEPOCH) << TIMESTAMP_LEFT_SHIFT) | (self.datacenter_id << DATACENTER_ID_SHIFT) | \
         (self.worker_id << WOKER_ID_SHIFT) | self.sequence
    return new_id

  def _til_next_millis(self, last_timestamp):
    """
    等到下一毫秒
    """
    timestamp = self._gen_timestamp()
    while timestamp <= last_timestamp:
      timestamp = self._gen_timestamp()
    return timestamp

if __name__ == '__main__':
  worker = IdWorker(1, 2, 0)
  print(worker.get_id())

Python代码实现与配置

在同级目录下创建exceptions.py文件,用于定义相关异常类。


class InvalidSystemClock(Exception):
  """
  时钟回拨异常
  """
  pass

在配置文件中设置机器ID和序列号初始值,具体配置如下。


  # Snowflake ID Worker 参数
  DATACENTER_ID = 0
  WORKER_ID = 0
  SEQUENCE = 0

以上即为基于Python实现雪花算法的完整过程与关键细节,希望能为相关学习与实践提供帮助。

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表