基于python实现雪花算法过程详解


Posted in Python onNovember 16, 2019

这篇文章主要介绍了基于python实现雪花算法过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

Snowflake是Twitter提出来的一个算法,其目的是生成一个64bit的整数:

基于python实现雪花算法过程详解

  • 1bit:一般是符号位,不做处理
  • 41bit:用来记录时间戳,这里可以记录69年,如果设置好起始时间比如今年是2018年,那么可以用到2089年,到时候怎么办?要是这个系统能用69年,我相信这个系统早都重构了好多次了。
  • 10bit:10bit用来记录机器ID,总共可以记录1024台机器,一般用前5位代表数据中心,后面5位是某个数据中心的机器ID
  • 12bit:循环位,用来对同一个毫秒之内产生不同的ID,12位可以最多记录4095个,也就是在同一个机器同一毫秒最多记录4095个,多余的需要进行等待下毫秒。

上面只是一个将64bit划分的标准,当然也不一定这么做,可以根据不同业务的具体场景来划分,比如下面给出一个业务场景:

  • 服务目前QPS10万,预计几年之内会发展到百万。
  • 当前机器三地部署,上海,北京,深圳都有。
  • 当前机器10台左右,预计未来会增加至百台。
  • 这个时候我们根据上面的场景可以再次合理的划分62bit,QPS几年之内会发展到百万,那么每毫秒就是千级的请求,目前10台机器那么每台机器承担百级的请求,为了保证扩展,后面的循环位可以限制到1024,也就是2^10,那么循环位10位就足够了。

机器三地部署我们可以用3bit总共8来表示机房位置,当前的机器10台,为了保证扩展到百台那么可以用7bit 128来表示,时间位依然是41bit,那么还剩下64-10-3-7-41-1 = 2bit,还剩下2bit可以用来进行扩展。

基于python实现雪花算法过程详解

时钟回拨

因为机器的原因会发生时间回拨,我们的雪花算法是强依赖我们的时间的,如果时间发生回拨,有可能会生成重复的ID,在我们上面的nextId中我们用当前时间和上一次的时间进行判断,如果当前时间小于上一次的时间那么肯定是发生了回拨,算法会直接抛出异常.

# 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())

同文件夹下建立exceptions.py

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

配置文件中添加,对应的是机器ID和序列号

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python 字符串操作实现代码(截取/替换/查找/分割)
Jun 08 Python
用python + openpyxl处理excel2007文档思路以及心得
Jul 14 Python
如何解决django配置settings时遇到Could not import settings 'conf.local'
Nov 18 Python
Python自定义装饰器原理与用法实例分析
Jul 16 Python
Python实现多态、协议和鸭子类型的代码详解
May 05 Python
Windows10下 python3.7 安装 facenet的教程
Sep 10 Python
详解Python中字符串前“b”,“r”,“u”,“f”的作用
Dec 18 Python
python3实现在二叉树中找出和为某一值的所有路径(推荐)
Dec 26 Python
在Python中通过threshold创建mask方式
Feb 19 Python
pandas使用函数批量处理数据(map、apply、applymap)
Nov 27 Python
利用Python第三方库实现预测NBA比赛结果
Jun 21 Python
用PYTHON去计算88键钢琴的琴键频率和音高
Apr 10 Python
Python大数据之使用lxml库解析html网页文件示例
Nov 16 #Python
Python大数据之从网页上爬取数据的方法详解
Nov 16 #Python
简单了解Pandas缺失值处理方法
Nov 16 #Python
python selenium 执行完毕关闭chromedriver进程示例
Nov 15 #Python
浅谈Django2.0 加xadmin踩的坑
Nov 15 #Python
Django 实现xadmin后台菜单改为中文
Nov 15 #Python
django使用xadmin的全局配置详解
Nov 15 #Python
You might like
PHP 加密/解密函数 dencrypt(动态密文,带压缩功能,支持中文)
2009/01/30 PHP
PHP查询并删除数据库多列重复数据的方法(利用数组函数实现)
2016/02/23 PHP
PHP fopen中文文件名乱码问题解决方案
2020/10/28 PHP
javascript 写类方式之四
2009/07/05 Javascript
jQuery 的全选(全非选)即取得被选中的值使用介绍
2013/11/12 Javascript
js Date概念详细介绍
2013/11/22 Javascript
javascript 利用arguments实现可变长参数
2016/11/21 Javascript
深入理解vue.js双向绑定的实现原理
2016/12/05 Javascript
Vue.js简易安装和快速入门(第二课)
2017/10/17 Javascript
浅谈Vue.nextTick 的实现方法
2017/10/25 Javascript
Vue+jquery实现表格指定列的文字收缩的示例代码
2018/01/09 jQuery
微信小程序实现留言板(Storage)
2018/11/02 Javascript
详解mpvue中使用vant时需要注意的onChange事件的坑
2019/05/16 Javascript
在Echarts图中给坐标轴加一个标识线markLine
2020/07/20 Javascript
vue-cli4.0多环境配置变量与模式详解
2020/12/30 Vue.js
[01:08:48]LGD vs OG 2018国际邀请赛淘汰赛BO3 第三场 8.25
2018/08/29 DOTA
Python聊天室实例程序分享
2016/01/05 Python
Python 常用 PEP8 编码规范详解
2017/01/22 Python
python win32 简单操作方法
2017/05/25 Python
Python使用统计函数绘制简单图形实例代码
2019/05/15 Python
Python lxml模块的基本使用方法分析
2019/12/21 Python
利用Python实现最小二乘法与梯度下降算法
2021/02/21 Python
加拿大女包品牌:Matt & Nat
2017/05/12 全球购物
ghd澳大利亚官方网站:英国最受欢迎的美发工具品牌
2018/05/21 全球购物
Speedo速比涛德国官方网站:世界领先的泳装品牌
2019/08/26 全球购物
中学生评语大全
2014/04/18 职场文书
大二学生学年自我鉴定
2014/09/12 职场文书
上课说话检讨书500字
2014/11/01 职场文书
2014年消防工作总结
2014/11/21 职场文书
公司行政助理岗位职责
2015/04/11 职场文书
未婚证明范本
2015/06/15 职场文书
销售会议开幕词
2016/03/04 职场文书
餐饮行业关注的9大营销策略
2019/08/26 职场文书
Python图片检索之以图搜图
2021/05/31 Python
Java 在线考试云平台的实现
2021/11/23 Java/Android
Python 恐龙跑跑小游戏实现流程
2022/02/15 Python