非常感谢程序员小灰

————— 第二天 —————

方法一:UUID

UUID是通用唯一识别码 (Universally Unique Identifier),在其他语言中也叫GUID,可以生成一个长度32位的全局唯一识别码。

String uuid = UUID.randomUUID().toString()

结果示例:

046b6c7f-0b8a-43b9-b35d-6489e6daee91

为什么无序的UUID会导致入库性能变差呢?

这就涉及到 B+树索引的分裂:

众所周知,关系型数据库的索引大都是B+树的结构,拿ID字段来举例,索引树的每一个节点都存储着若干个ID。

如果我们的ID按递增的顺序来插入,比如陆续插入8,9,10,新的ID都只会插入到最后一个节点当中。当最后一个节点满了,会裂变出新的节点。这样的插入是性能比较高的插入,因为这样节点的分裂次数最少,而且充分利用了每一个节点的空间。

但是,如果我们的插入完全无序,不但会导致一些中间节点产生分裂,也会白白创造出很多不饱和的节点,这样大大降低了数据库插入的性能。

方法二:数据库自增主键

假设名为table的表有如下结构:

id feild

35 a

每一次生成ID的时候,访问数据库,执行下面的语句:

begin;

REPLACE INTO table ( feild ) VALUES ( ‘a’ );

SELECT LAST_INSERT_ID();

commit;

REPLACE INTO 的含义是插入一条记录,如果表中唯一索引的值遇到冲突,则替换老数据。

这样一来,每次都可以得到一个递增的ID。

为了提高性能,在分布式系统中可以用DB proxy请求不同的分库,每个分库设置不同的初始值,步长和分库数量相等.

这样一来,DB1生成的ID是1,4,7,10,13…,DB2生成的ID是2,5,8,11,14…

初识SnowFlake

snowflake算法所生成的ID结构是什么样子呢?我们来看看下图:

SnowFlake所生成的ID一共分成四部分:

1.第一位

占用1bit,其值始终是0,没有实际作用。

2.时间戳

占用41bit,精确到毫秒,总共可以容纳约69 年的时间。

3.工作机器id

占用10bit,其中高位5bit是数据中心ID(datacenterId),低位5bit是工作节点ID(workerId),做多可以容纳1024个节点。

4.序列号

占用12bit,这个值在同一毫秒同一节点上从0开始不断累加,最多可以累加到4095。

SnowFlake算法在同一毫秒内最多可以生成多少个全局唯一ID呢?只需要做一个简单的乘法:

同一毫秒的ID数量 = 1024 X 4096 = 4194304

这个数字在绝大多数并发场景下都是够用的。

SnowFlake的代码实现


public class SnowFlake {/*** 起始的时间戳*/private final static long START_TIMESTAMP = 1480166465631L;/*** 每一部分占用的位数*/private final static long SEQUENCE_BIT = 12;   //序列号占用的位数private final static long MACHINE_BIT = 5;     //机器标识占用的位数private final static long DATA_CENTER_BIT = 5; //数据中心占用的位数/*** 每一部分的最大值*/private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT);private final static long MAX_DATA_CENTER_NUM = -1L ^ (-1L << DATA_CENTER_BIT);/*** 每一部分向左的位移*/private final static long MACHINE_LEFT = SEQUENCE_BIT;private final static long DATA_CENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;private final static long TIMESTAMP_LEFT = DATA_CENTER_LEFT + DATA_CENTER_BIT;private long dataCenterId;  //数据中心private long machineId;     //机器标识private long sequence = 0L; //序列号private long lastTimeStamp = -1L;  //上一次时间戳/*** 根据指定的数据中心ID和机器标志ID生成指定的序列号** @param dataCenterId 数据中心ID* @param machineId    机器标志ID*/public SnowFlake(long dataCenterId, long machineId) {if (dataCenterId > MAX_DATA_CENTER_NUM || dataCenterId < 0) {throw new IllegalArgumentException("DtaCenterId can't be greater than MAX_DATA_CENTER_NUM or less than 0!");}if (machineId > MAX_MACHINE_NUM || machineId < 0) {throw new IllegalArgumentException("MachineId can't be greater than MAX_MACHINE_NUM or less than 0!");}this.dataCenterId = dataCenterId;this.machineId = machineId;}/*** 产生下一个ID** @return*/public synchronized long nextId() {long currTimeStamp = getNewTimeStamp();if (currTimeStamp < lastTimeStamp) {throw new RuntimeException("Clock moved backwards.  Refusing to generate id");}if (currTimeStamp == lastTimeStamp) {//相同毫秒内,序列号自增sequence = (sequence + 1) & MAX_SEQUENCE;//同一毫秒的序列数已经达到最大if (sequence == 0L) {currTimeStamp = getNextMill();}} else {//不同毫秒内,序列号置为0sequence = 0L;}lastTimeStamp = currTimeStamp;return (currTimeStamp - START_TIMESTAMP) << TIMESTAMP_LEFT //时间戳部分| dataCenterId << DATA_CENTER_LEFT       //数据中心部分| machineId << MACHINE_LEFT             //机器标识部分| sequence;                             //序列号部分}private long getNextMill() {long mill = getNewTimeStamp();while (mill <= lastTimeStamp) {mill = getNewTimeStamp();}return mill;}private long getNewTimeStamp() {return System.currentTimeMillis();}public static void main(String[] args) {SnowFlake snowFlake = new SnowFlake(1, 1);for (int i = 0; i < 1000000; i++) {//10进制System.out.println(snowFlake.nextId());}}}

SnowFlake的优势和劣势

SnowFlake算法的优点:

1.生成ID时不依赖于DB,完全在内存生成,高性能高可用。

2.ID呈趋势递增,后续插入索引树的时候性能较好。

SnowFlake算法的缺点:

依赖于系统时钟的一致性。如果某台机器的系统时钟回拨,有可能造成ID冲突,或者ID乱序。

漫画解读SnowFlake算法相关推荐

  1. 漫画:什么是SnowFlake算法

    转载自 漫画:什么是SnowFlake算法 方法一:UUID UUID是通用唯一识别码 (Universally Unique Identifier),在其他语言中也叫GUID,可以生成一个长度32位 ...

  2. Cell封面:王二涛组在丛枝菌根共生“自我调节”研究中取得重大进展(视频+漫画解读)...

    科 研 进 展 2021年10月12日,分子植物卓越中心王二涛研究团队在国际顶尖学术期刊<细胞>(Cell)上发表题为"A phosphate starvation respon ...

  3. 分布式唯一id:snowflake算法思考

    匠心零度 转载请注明原创出处,谢谢! 缘起 为什么会突然谈到分布式唯一id呢?原因是最近在准备使用RocketMQ,看看官网介绍: 一句话,消息可能会重复,所以消费端需要做幂等.为什么消息会重复后续R ...

  4. java 唯一id生成算法_分布式全局唯一ID生成方案之snowflake算法

    已有的方案: 可大致分为: 完全依赖关系/非关系型数据库递增的方案 完全不依赖数据源作为生成因子的UUID 半依赖数据源作为生成因子的snowflake 为什么推荐snowflake? 这个问题,可以 ...

  5. snowflake算法 php,Snowflake —— 分布式全局唯一 id 生成算法

    简介 Snowflake 是 Twitter 提出一种的分布式唯一序列号生成算法,理论上单节点 1 毫秒可以生成 4096 个(每秒四百万个)唯一序列,这个序列是个 long 类型的数字,在数据库中的 ...

  6. mysql snowflake_一篇文章彻底搞懂snowflake算法及百度美团的最佳实践

    写在前面的话 一提到分布式ID自动生成方案,大家肯定都非常熟悉,并且立即能说出自家拿手的几种方案,确实,ID作为系统数据的重要标识,重要性不言而喻,而各种方案也是历经多代优化,请允许我用这个视角对分布 ...

  7. 根据twitter的snowflake算法生成唯一ID

    C#版本 /// <summary>/// 根据twitter的snowflake算法生成唯一ID/// snowflake算法 64 位/// 0---0000000000 000000 ...

  8. 【转】漫画:Bitmap算法

    漫画:Bitmap算法 转载于:https://www.cnblogs.com/apeway/p/10786283.html

  9. java生成唯一有序序列号_分布式唯一 ID 之 Snowflake 算法

    SegmentFault 社区专栏:全栈修仙之路作者:semlinker No.1 Snowflake 简介 1.1 什么是 Snowflake Snowflake is a service used ...

最新文章

  1. cs-HtmlHelpers
  2. iftop是一个很好用的实时流量监测程序,跟使用iftop查看linux连接进程占用的实时流量...
  3. C++ TR1、TR2与boost的关系
  4. 微信小程序点击按钮实现手机振动功能
  5. ordersta在php中是什么意思,[求助]ststa中的几个问题
  6. 和不安全的Android说再见,Google为它添加新铠甲
  7. 【转】应用架构之道:分离业务逻辑和技术细节
  8. 获取 NodeJS 程序退出码
  9. Install-Package Ninject -Project SportsStore.WebUI
  10. 推荐几个顶级的IT技术公众号
  11. java返回xls格式_java后台获得url返回的excel文件
  12. windows mysql 和linux mysql解决乱码问题
  13. HCIE-Security心得
  14. 遥感影像数据下载网址
  15. 阿里巴巴达摩院发布2019十大科技趋势:语音AI在特定领域通过图灵测试...
  16. 【整活】修改U盘的图标,让你的U盘与众不同
  17. 光明区支持总部企业高质量发展实施办法(征求意见稿)
  18. word文档粘贴到html,将Word 文档复制到Dreamweaver的方法
  19. Eviews7.2模型建模与预测时间序列分析(ARIMA 模型的建立与预测)
  20. 第一章 python筑基

热门文章

  1. Python 之 使用Tkinter 做GUI 研究机器人走迷宫
  2. MySQL面试通关秘籍:这次你也可以在简历写上精通MySQL!
  3. 原创超简单代码(1.29)||我的世界(大更)
  4. java常用英文翻译
  5. windows启动和停止mysql_WIN下启动和停止MYSQL命令
  6. 用计算机做路由器,电脑当无线路由器怎么用 电脑当无线路由器详细教程【图文】...
  7. mac视频剪辑软件Final Cut Pro X for Mac
  8. 修正Lilypond生成简谱工具
  9. 密码编码学与网络安全期末考试笔记
  10. 研究PS过的图片信息残留问题