本文将主要介绍一些常见的全局主键生成策略,然后重点介绍flickr使用的一种非常优秀的全局主键生成方案。关于分库分表(sharding)的拆分策略和实施细则,请参考该系列的前一篇文章:数据库分库分表(sharding)系列(一) 拆分实施策略和示例演示 本文原文连接: http://blog.csdn.net/bluishglc/article/details/7710738 ,转载请注明出处!

第一部分:一些常见的主键生成策略

一旦数据库被切分到多个物理结点上,我们将不能再依赖数据库自身的主键生成机制。一方面,某个分区数据库自生成的ID无法保证在全局上是唯一的;另一方面,应用程序在插入数据之前需要先获得ID,以便进行SQL路由。目前几种可行的主键生成策略有:
1. UUID:使用UUID作主键是最简单的方案,但是缺点也是非常明显的。由于UUID非常的长,除占用大量存储空间外,最主要的问题是在索引上,在建立索引和基于索引进行查询时都存在性能问题。
2. 结合数据库维护一个Sequence表:此方案的思路也很简单,在数据库中建立一个Sequence表,表的结构类似于:

  1. CREATE TABLE `SEQUENCE` (
  2. `tablename` varchar(30) NOT NULL,
  3. `nextid` bigint(20) NOT NULL,
  4. PRIMARY KEY (`tablename`)
  5. ) ENGINE=InnoDB

每当需要为某个表的新纪录生成ID时就从Sequence表中取出对应表的nextid,并将nextid的值加1后更新到数据库中以备下次使用。此方案也较简单,但缺点同样明显:由于所有插入任何都需要访问该表,该表很容易成为系统性能瓶颈,同时它也存在单点问题,一旦该表数据库失效,整个应用程序将无法工作。有人提出使用Master-Slave进行主从同步,但这也只能解决单点问题,并不能解决读写比为1:1的访问压力问题。

除此之外,还有一些方案,像对每个数据库结点分区段划分ID,以及网上的一些ID生成算法,因为缺少可操作性和实践检验,本文并不推荐。实际上,接下来,我们要介绍的是Fickr使用的一种主键生成方案,这个方案是目前我所知道的最优秀的一个方案,并且经受了实践的检验,可以为大多数应用系统所借鉴。

第二部分:一种极为优秀的主键生成策略

flickr开发团队在2010年撰文介绍了flickr使用的一种主键生成测策略,同时表示该方案在flickr上的实际运行效果也非常令人满意,原文连接:Ticket Servers: Distributed Unique Primary Keys on the Cheap这个方案是我目前知道的最好的方案,它与一般Sequence表方案有些类似,但却很好地解决了性能瓶颈和单点问题,是一种非常可靠而高效的全局主键生成方案。

图1. flickr采用的sharding主键生成方案示意图(点击查看大图)

flickr这一方案的整体思想是:建立两台以上的数据库ID生成服务器,每个服务器都有一张记录各表当前ID的Sequence表,但是Sequence中ID增长的步长是服务器的数量,起始值依次错开,这样相当于把ID的生成散列到了每个服务器节点上。例如:如果我们设置两台数据库ID生成服务器,那么就让一台的Sequence表的ID起始值为1,每次增长步长为2,另一台的Sequence表的ID起始值为2,每次增长步长也为2,那么结果就是奇数的ID都将从第一台服务器上生成,偶数的ID都从第二台服务器上生成,这样就将生成ID的压力均匀分散到两台服务器上,同时配合应用程序的控制,当一个服务器失效后,系统能自动切换到另一个服务器上获取ID,从而保证了系统的容错。

关于这个方案,有几点细节这里再说明一下:

1. flickr的数据库ID生成服务器是专用服务器,服务器上只有一个数据库,数据库中表都是用于生成Sequence的,这也是因为auto-increment-offset和auto-increment-increment这两个数据库变量是数据库实例级别的变量。
2. flickr的方案中表格中的stub字段只是一个char(1) NOT NULL存根字段,并非表名,因此,一般来说,一个Sequence表只有一条纪录,可以同时为多张表生成ID,如果需要表的ID是有连续的,需要为该表单独建立Sequence表

3. 方案使用了mysql的LAST_INSERT_ID()函数,这也决定了Sequence表只能有一条记录。
4. 使用REPLACE INTO插入数据,这是很讨巧的作法,主要是希望利用mysql自身的机制生成ID,不仅是因为这样简单,更是因为我们需要ID按照我们设定的方式(初值和步长)来生成。

5. SELECT LAST_INSERT_ID()必须要于REPLACE INTO语句在同一个数据库连接下才能得到刚刚插入的新ID,否则返回的值总是0
6. 该方案中Sequence表使用的是MyISAM引擎,以获取更高的性能,注意:MyISAM引擎使用的是表级别的锁,MyISAM对表的读写是串行的,因此不必担心在并发时两次读取会得到同一个ID(另外,应该程序也不需要同步,每个请求的线程都会得到一个新的connection,不存在需要同步的共享资源)。经过实际对比测试,使用一样的Sequence表进行ID生成,MyISAM引擎要比InnoDB表现高出很多!

7. 可使用纯JDBC实现对Sequence表的操作,以便获得更高的效率,实验表明,即使只使用Spring JDBC性能也不及纯JDBC来得快!

实现该方案,应用程序同样需要做一些处理,主要是两方面的工作:

1. 自动均衡数据库ID生成服务器的访问
2. 确保在某个数据库ID生成服务器失效的情况下,能将请求转发到其他服务器上执行。

转数据库分库分表(sharding)系列(二) 全局主键生成策略的更多相关文章

  1. 数据库分库分表(sharding)系列(二) 全局主键生成策略

    本文将主要介绍一些常见的全局主键生成策略,然后重点介绍flickr使用的一种非常优秀的全局主键生成方案.关于分库分表(sharding)的拆分策略和实施细则,请参考该系列的前一篇文章:数据库分库分表( ...

  2. 数据库分库分表(sharding)系列【转】

    原文地址:http://www.uml.org.cn/sjjm/201211212.asp数据库分库分表(sharding)系列 目录; (一) 拆分实施策略和示例演示 (二) 全局主键生成策略 (三 ...

  3. 数据库分库分表(sharding)系列

    数据库分库分表(sharding)系列     目录; (一) 拆分实施策略和示例演示 (二) 全局主键生成策略 (三) 关于使用框架还是自主开发以及sharding实现层面的考量 (四) 多数据源的 ...

  4. 数据库分库分表(sharding)系列(一) 拆分规则

    第一部分:实施策略 数据库分库分表(sharding)实施策略图解 1. 垂直切分垂直切分的依据原则是:将业务紧密,表间关联密切的表划分在一起,例如同一模块的表.结合已经准备好的数据库ER图或领域模型 ...

  5. 转数据库分库分表(sharding)系列(一) 拆分实施策略和示例演示

    本文原文连接: http://blog.csdn.net/bluishglc/article/details/7696085 ,转载请注明出处!本文着重介绍sharding切分策略,如果你对数据库sh ...

  6. 数据库分库分表(sharding)系列(一)拆分实施策略和示例演示

    本文原文连接: http://blog.csdn.net/bluishglc/article/details/7696085 ,转载请注明出处!本文着重介绍sharding切分策略,如果你对数据库sh ...

  7. 数据库分库分表(sharding)系列(五) 一种支持自由规划无须数据迁移和修改路由代码的Sharding扩容方案

    作为一种数据存储层面上的水平伸缩解决方案,数据库Sharding技术由来已久,很多海量数据系统在其发展演进的历程中都曾经历过分库分表的Sharding改造阶段.简单地说,Sharding就是将原来单一 ...

  8. 数据库分库分表(sharding)系列(三) 关于使用框架还是自主开发以及sharding实现层面的考量

    当团队对系统业务和数据库进行了细致的梳理,确定了切分方案后,接下来的问题就是如何去实现切分方案了,目前在sharding方面有不少的开源框架和产品可供参考,同时很多团队也会选择自主开发实现,而不管是选 ...

  9. 数据库分库分表(sharding)系列(四) 多数据源的事务处理

    系统经sharding改造之后,原来单一的数据库会演变成多个数据库,如何确保多数据源同时操作的原子性和一致性是不得不考虑的一个问题.总体上看,目前对于一个分布式系统的事务处理有三种方式:分布式事务.基 ...

随机推荐

  1. CSS布局自适应高度解决方法

    这是一个比较典型的三行二列布局,每列高度(事先并不能确定哪列的高度)的相同,是每个设计师追求的目标,按一般的做法,大多采用背景图填充.加JS脚本的方法使列的高度相同,本文要介绍的是采用容器溢出部分隐藏 ...

  2. USACO 3.2 kimbits DP

    自己YY了个DP:设f[n][l]为n位数中包含不超过l个1的总个数 f[n][l]=f[n-1][l]+f[n-1][l-1] 然后用_search()从高位向低位扫描即可,tmp记录当前已记下多少 ...

  3. Prim和Kruskal求最小生成树

    Prim: 算法步骤: 1.任意结点开始(不妨设为v1)构造最小生成树: 2.首先把这个结点(出发点)包括进生成树里, 3.然后在那些其一个端点已在生成树里.另一端点还未在生成树里的所有边中找出权最小 ...

  4. [NOIP2011] 提高组 洛谷P1311 选择客栈

    题目描述 丽江河边有n 家很有特色的客栈,客栈按照其位置顺序从 1 到n 编号.每家客栈都按照某一种色调进行装饰(总共 k 种,用整数 0 ~ k-1 表示),且每家客栈都设有一家咖啡店,每家咖啡店均 ...

  5. ISO 基础之 (十二) 文件管理

    一 文件管理 沙盒:让每个APP应用在手机上有一个独立的文件夹,相互之间不能访问. 沙盒目录:NSHomeDirectory() library: 库文件 tmp: 临时文件 1.NSData 也是一 ...

  6. Eclipse开发Android程序如何在手机上运行

    android开发不论是在真机上调试还是最终发布到真机上都非常简单,过程如下: 1.安装usb驱动 手机要能与电脑相连,当然要安驱动了.效果就是你插入手机,电脑显示驱动已识别.驱动安装的官方教程:ht ...

  7. 解决Surface Pro外接移动硬盘经常睡眠的问题

    1. 打开注册表,找到下面的键 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Power\PowerSettings\0012ee47-904 ...

  8. 织梦DedeCms网站更换域名后文章图片路径批量修改

    因为织梦上传图片用的是绝对地址,如果域名更换后,之前发布的文章的图片URL是不会跟着改变的,所以我们需要把旧域名替换成新的域名,方法很简单,有一段SQL语句更新一下文章正文内容就行. 复制下面SQL语 ...

  9. Unity-Tween

    1.GoKit 免费开源 AssetStore:https://www.assetstore.unity3d.com/en/#!/content/3663 下载地址:https://github.co ...

  10. git工作量统计

    #!/bin/bash function count() { local insert=0 local delete=0 while read line ;do current=`echo $line ...