分布式环境下的id生成方法
分布式环境下的id生成方法
前几天研究数据库分表分库的问题,其中有一个关键的地方就是生成唯一键的问题,假如数据表有1亿条数据,而且还在不断的增加,这里我们就需要考虑到分表分库,假设我们采用Hash或者是用户取模求余的方法将这个表拆分成10个表,每个表的结构相同,其中有一个主键id,那么10个表中的id需要唯一不同,在单表的时候,使用数据表自增长是没有问题的。当分成10个表后,就无法用到数据库自增长了。
当到这里的时候突然发现oracle数据库的序列真是好东西,在刚刚接触的时候还很郁闷这种设计真是没有mysql获sqlserver中的方便
目前做唯一id的做法基本有三种
1.使用uuid来实现,快速不重复,只是生成的id没有规则
2.使用外部的id分发中心来实现,生存的id简短有规则,缺点是依赖于单点
3.在数据库中做一个计数表来做,有点类是于oracle中的序列
以下内容大部分来自于网络:
UUID
UUID的目的,是让分散式系统中的所有元素,都能有唯一的辨识信息,而不需要通过中央控制端来做辨识信息的指定。如此一来,每个人都可以创建不与其它人冲突的UUID。在这样的情况下,就不需考虑数据库创建时的名称重复问题。
一组UUID,是由一串16位组(亦称128位)的16进位数字所构成,是故UUID理论上的总数为216 x 8=2128,约等于3.4 x 1038。也就是说若每纳秒产生1兆个UUID,要花100亿年才会将所有UUID用完。
UUID的标准型式包含32个16进位数字,以连字号分为五段,形式为8-4-4-4-12的36个字符。示例:
- 550e8400-e29b-41d4-a716-446655440000
twitter的Snowflake(id分发中心)
Snowflake是twitter开源的一款独立的适用于分布式环境的ID生成服务器。生成的ID是64Bits,同时满足高性能(>10K ids/s),低延迟(<2ms)和高可用。与MongoDB ObjectID类似这里生成的ID也是时间上有序的。编码方式也和ObjectID类似,如下:
0 41 51 64
+-----------+------+------+
|time |pc |inc |
+-----------+------+------+
- 前41bits是以微秒为单位的timestamp。
- 接着10bits是事先配置好的机器ID。
- 最后12bits是累加计数器。
MongoDB ObjectID(类似UUID的方式)
MongoDB中每一条记录都有一个’id’字段用来唯一标示本记录。如果用户插入数据时没有显示提供’id’字段,那么系统会自动生成一个。ObjectID一共12Bytes,设计的时候充分考虑了分布式环境下使用的情况,所以能保证在一个分布式MongoDB集群中唯一。ObjectID格式如下:
0 4 7 9 12
+--------+------+----+------+
|time |pc |pid |inc |
+--------+------+----+------+
- 前四个字节是Unix Timestamp。
- 接着三个字节是当前机器“hostname/mac地址/虚拟编号”其中之一的MD5结果的前3个字节。
- 接着两个字节是当前进程的PID。
- 最后三个字节是累加计数器或是一个随机数(只有当不支持累加计数器时才用随机数)。
最后生成的仍然是一个用16进制表示的串,如47cc67093475061e3d95369d。这里MongoDB的ObjectID相对UUID有个很大的优点就是ObjectID是时间上有序的。另外还有ObjectID本身也包含了很多其它有用的信息,通过直接解码ObjectID即可直接获得这些信息。
Ticket Server(数据库生存方式)
这个是Flickr在遇到生成全局ID问题时采用的办法。利用了数据库中auto_increment的特性和MySQL特有的REPLACE INFO命令,专门一个数据库实例用来产生ID。大致的过程是这样的:
- 首先建立一个表,比如用来产生64bitsID的,叫做’Ticket64′
CREATE TABLE `Tickets64` (
`id` bigint(20) unsigned NOT NULL auto_increment,
`stub` char(1) NOT NULL default '',
PRIMARY KEY (`id`),
UNIQUE KEY `stub` (`stub`)
) ENGINE=MyISAM
- 向里边插入一条记录后大致是这样:
+-------------------+------+
| id | stub |
+-------------------+------+
| 72157623227190423 | a |
+-------------------+------+
- 当需要一个64Bits ID的时候,执行如下SQL 语句:
REPLACE INTO Tickets64 (stub) VALUES ('a');
SELECT LAST_INSERT_ID();
另外为了防止这个Ticket Server单点故障,可以设置两个Ticket Server实例。其中一个产生奇数ID,另一个产生偶数ID。
TicketServer1:
auto-increment-increment = 2
auto-increment-offset = 1
TicketServer2:
auto-increment-increment = 2
auto-increment-offset = 2
应用交替请求两个Server,这样不仅压力减小一半,故障风险也降低一半。不过这里也有个问题,就是当一台机器故障时,另一台正常机器产生的ID将会领先故障机器一截,可能会造成不再是时间上有序的ID。按照Flickr的说法,这并不影响他们的应用。
Instagram采用的方式(UUID方式)
Instagram要将其中存储的图片分片到多个PostgreSQL中,其中生成ID的方案和MongoDB ObjectID类似。整个ID的长度为64Bits,设定为这个长度是为了优化在redis中的存储。ID的编码格式如下:
- 41bits以微秒为单位的timestamp,时间起点从2011-01-01开始。
- 13bits表示进行逻辑分片的Shard ID。
- 10bits表示一个累加计数器。
ID的生成逻辑用PL/PGSQL语言写到PostgreSQL数据库中,当每次插入数据时由数据库自动计算生成。
分布式环境下的id生成方法的更多相关文章
- 分布式环境下Unique ID生成方法
ID即标示符,在某个搜索域内能唯一标示其中某个对象.在关系型数据库中每个表都需要定义一个主键来唯一标示一条记录.为了方便一般都会使用一个auto_increment属性的整形数做为ID.因为数据库本身 ...
- 关于分布式环境下的id生成
public class IdWorker { //基准时间 public const long Twepoch = 1288834974657L; //机器标识位数 ; //数据标志位数 ; //序 ...
- 【融云分析】如何实现分布式场景下唯一 ID 生成?
◀背景▶ 对于一套分布式部署的 IM 系统,要求每条消息的 ID 要保证在集群中全局唯一且按生成时间有序排列.如何快速高效的生成消息数据的唯一 ID ,是影响系统吞吐量的关键因素.那么,融云是如何做到 ...
- MySQL分库分表环境下全局ID生成方案 转
在大型互联网应用中,随着用户数的增加,为了提高应用的性能,我们经常需要对数据库进行分库分表操作.在单表时代,我们可以完全依赖于数据库的自增ID来唯一标识一个用户或数据对象.但是当我们对数据库进行了分库 ...
- MySQL分库分表环境下全局ID生成方案
在大型互联网应用中,随着用户数的增加,为了提高应用的性能,我们经常需要对数据库进行分库分表操作.在单表时代,我们可以完全依赖于数据库的自增ID来唯一标识一个用户或数据对象.但是当我们对数据库进行了分库 ...
- 【转】MySQL分库分表环境下全局ID生成方案
转载一篇博客,里面有很多的知识和思想值得我们去思考. —————————————————————————————————————————————————————————————————————— 在大 ...
- 高并发环境下全局id生成策略
解决方案: 基于Redis的全局id生成策略:(推荐此方法) 基于雪花算法的全局id生成: https://www.cnblogs.com/kobe-qi/p/8761690.html 基于zooke ...
- 分布式id生成方法
系统唯一ID是我们在设计一个系统的时候常常会遇见的问题,也常常为这个问题而纠结.生成ID的方法有很多,适应不同的场景.需求以及性能要求.所以有些比较复杂的系统会有多个ID生成的策略.下面就介绍一些常见 ...
- 细聊分布式ID生成方法
细聊分布式ID生成方法 https://mp.weixin.qq.com/s?__biz=MjM5ODYxMDA5OQ==&mid=403837240&idx=1&sn=ae9 ...
随机推荐
- bzoj 1005 HNOI2008 明明的烦恼
这题做的我欲哭无泪啊…… 我已经没心情多说啥了…… 高精度T啊!我太弱啊!改了一天啊!还不如滚粗啊! 想好式子在写啊! 能用高精度乘单精度就不要用高精度乘高精度啊! 能用高精度除单精度就不要用 ...
- zabbix短信网关调用问题总结
在写调用短信网关的shell脚本的时候,发现了一个百思不得其解的问题,用浏览器访问短信接口地址是可以成功接收到短信的.但在shell 里面调用就报错了!!!在反复测试当中发现,在shell 中对特殊字 ...
- 在.NET连接MySQL以及封装好的MySQLHelper.cs
1.首先上MySQL网站下驱动:http://www.mysql.com/products/connector/ 2.安装下载的安装包 3.我们在Visual Studio里创建一个Web Appli ...
- ASP.NET Web API标准的“管道式”设计
详见:http://www.cnblogs.com/artech/p/asp-net-web-api-pipeline.html http://www.codeproject.com/Articles ...
- Python时间和日期学习
#coding=utf-8 __author__ = 'Administrator' #日期和时间模块学习 """ Python程序能用很多方式处理日期和时间,转换日期格 ...
- 【转】perl特殊符号及默认的内部变量
perl特殊符号及默认的内部变量,有需要的朋友不妨参考下 Perl的特殊符号 @ 数组 $x{} x名字前面是美元符号($),后面是花 ...
- IE10用video标签播放本地mp4文件失败的解决办法
1. 首先用“格式工厂”将要播放的视频文件按照“AVC高质量与大小”转换为要求格式的mp4文件: 2. 设置IIS7.5,添加mp4的MIME类型,步骤如下: 1.打开IIS管理器(运行inetmgr ...
- iframe 刷新
iframe刷新父页面 parent.location.reload(); iframe 一个子页面操作过后,刷新指定子页面 parent.frames('ifrmname').location.re ...
- iPhone手机屏幕的尺寸
以下是 iPhone的型号和对应的屏幕宽高 英寸 宽 高 厚度 3.5 320 480 4s ipad 系列 4 320 568 5 5s 4.7 375 66 ...
- Xcode 向6.0以后版本添加iOS开发空白模板
打开finder,找到应用程序,找到xcode 右键显示包内容.按照如下目录进行查找:Contents ▸ Developer ▸ Platforms ▸ iPhoneOS.platform ▸ De ...