首页 > MySQL, MySQL Innodb, php > 分库分表(sharding)后主键全局唯一性的解决方案

分库分表(sharding)后主键全局唯一性的解决方案

随着数据量的增大,在数据库的扩展上通常遇到切分时保证键值的唯一性问题,遇到这种情况,通常有如下几种相对简单的解决方案:

1  UUID 这种方案的优点是实现和管理简单,缺点是占用空间大,查询效率低下。

2  Sequence Number 优点是实现和管理简单,确定是有性能瓶颈和单点问题。

3  不同的集群采用的起始点或者增长间隔不同 这种方案实现简单,但是后期管理麻烦。

除了上述解决方案之外其实还有很多简单可行的办法,但是通用性不太好,在各种解决方案的接触上,本人总结出一个实现和性能上都很好的解决方案,那就是采用时间戳加毫秒数再加随机数来解决,存储字段采用bigint。
下面给出php代码实现:
function ivan_fetch_unique_bigint_id()
{
    $start_timestamp = 1238119411;
    $ivan_len = 3;
    $time = explode( ‘ ‘, microtime());
    $id = ($time[1]$start_timestamp) . sprintf(‘%06u’, substr($time[0], 2, 6));
    if ($ivan_len > 0) {
        $id .= substr(sprintf(‘%010u’, mt_rand()), 0, $ivan_len);
    }
    return $id;
}
取模测试均分性很好。
转载请注明出处,谢谢。

Related posts:

  1. MySQL分区表没有全局索引,只有分区索引
  2. MySQL vs NoSQL 效率与成本之争
分类: MySQL, MySQL Innodb, php 标签: , ,
  1. 2009年3月27日13:35 | #1

    高并发下还靠谱不

  2. 2009年3月27日13:47 | #2

    @神仙
    直接插入,如果id重复会抛出exception(因为会模到同一库表中),然后重新生成ID,再插入。不过我想就算高并发,这种碰撞的概率接近于0

  3. 膜拜
    2009年12月7日22:31 | #3

    其中用了unix的时间戳是32位的,貌似在2037年左右就会失效?到时候,如升级64位时间戳能否保证不发生重复id呢?

  4. 2009年12月8日17:04 | #4

    @膜拜
    我想现在的发展速度,等到2038年的时候,肯定有解决方法的,不用担心。

  5. Jack Liang
    2010年4月14日15:36 | #5

    膜拜讲得不对,这个数生成是这样的
    33109660 407978 070
    9~10位秒数 6位微妙 3位随机数

    UNIX时间戳是(2^32/2)2,147,483,648 ,足够68年的秒数用
    而bigint 范围是
    -2^63 (-9,223,372,036,854,775,808) 到 2^63-1 (9,223,372,036,854,775,807)
    这个 9,223,372,036 足够292年用
    非常充足了

  6. liangrn
    2010年9月20日10:06 | #6

    这种方案虽然性能好,但是对于多核的机器以及服务器之间,获取Id的操作会在同一时间戳中进行,这时候就需要3位随机数来区分了。一台服务器的CPU核数越多,服务器越多,那么3位随机数重复的概率就越高。已经在一台多核机器上验证,产生将近90万的ID,有400多Id是同一微秒时间戳的Id,靠3位随机数区分,所以还是有一定风险的。

    • 2010年9月20日10:45 | #7

      碰撞的概率是非常低的,随机数位数还可以调整。另外如果1微妙有400多的话,那么这个记录量是非常恐怖的,我想世界上还没有哪个系统能有这么大的量,何况还需要在插入的时候做异常处理,这些可以避免和解决的。

  7. liangrn
    2010年9月20日12:31 | #8

    谭俊青 :碰撞的概率是非常低的,随机数位数还可以调整。另外如果1微妙有400多的话,那么这个记录量是非常恐怖的,我想世界上还没有哪个系统能有这么大的量,何况还需要在插入的时候做异常处理,这些可以避免和解决的。

    可能我表述不清楚,我的意思是在一台机器上并发20,压了1分钟不到,产生了90万的Id,有400条会出现时间戳重复(是分别有重复,不是一个时间戳重复400)。

  8. liangrn
    2010年9月20日12:33 | #9

    如果调整随机数位数,比如调整成4位,是可以减低重复概率,但是估计id只能用30多年就会超出19位,也就大于BigInt的范围了。

  9. 2010年9月20日12:40 | #10

    liangrn :

    谭俊青 :碰撞的概率是非常低的,随机数位数还可以调整。另外如果1微妙有400多的话,那么这个记录量是非常恐怖的,我想世界上还没有哪个系统能有这么大的量,何况还需要在插入的时候做异常处理,这些可以避免和解决的。

    可能我表述不清楚,我的意思是在一台机器上并发20,压了1分钟不到,产生了90万的Id,有400条会出现时间戳重复(是分别有重复,不是一个时间戳重复400)。

    400条重复数据应该是 同一毫秒的数据是2条记录,然后利用随机数碰撞的概率还是很低的,另外可以做一场处理。以3位随机数为例按照你测试的碰撞概率计算,大概是200万一次的碰撞可能,然后做一次异常处理,再次碰撞的概率就非常低了。随机数位数增加到4这个概率还会更低。

  10. 2010年9月20日12:42 | #11

    liangrn :

    如果调整随机数位数,比如调整成4位,是可以减低重复概率,但是估计id只能用30多年就会超出19位,也就大于BigInt的范围了。

    嗯,上面有人提到过,可以使用约70年,其实已经足够了,过度设计并不是好事儿。

  11. liangrn
    2010年9月20日12:52 | #12

    @谭俊青
    如果是4位随机数,是30多年。不可能70多年。70多年和290多年的是基于3位随机数的。

    我验证了在一台机器上,5个并发,跑了几个小时的插入业务,偶尔还是有ID冲突,当然是可以通过异常捕捉重新取Id来尝试。估计服务器越多,这个概率越高,还是要看业务的来取舍,以及加强冲突的尝试才行。

  12. 2010年9月20日12:58 | #13

    @liangrn
    另外要提的是,例中采用的是微妙,是百万分子一秒,不确定碰撞该概率有这么高。还有就是机器多跟这个没有直接关系,最终还是跟同一微妙下的并发多少有关。

  13. liangrn
    2010年9月20日13:00 | #14

    还是非常感谢楼主提出的这个思路!:), 如果真的取3位随机数,如果一台机器是8核或16核,然后100台甚至更多这样的服务器,对于频繁写数据的业务,估计重复的几率还是有些高的。

  14. liangrn
    2010年9月20日13:02 | #15

    谭俊青 :@liangrn 另外要提的是,例中采用的是微妙,是百万分子一秒,不确定碰撞该概率有这么高。还有就是机器多跟这个没有直接关系,最终还是跟同一微妙下的并发多少有关。

    机器多跟这个绝对有关系的,微秒也是时间,多台服务器也是按这个算法去生成Id,重复概率绝对就高了。

  15. 2010年9月20日13:07 | #16

    liangrn :

    谭俊青 :@liangrn 另外要提的是,例中采用的是微妙,是百万分子一秒,不确定碰撞该概率有这么高。还有就是机器多跟这个没有直接关系,最终还是跟同一微妙下的并发多少有关。

    机器多跟这个绝对有关系的,微秒也是时间,多台服务器也是按这个算法去生成Id,重复概率绝对就高了。

    我们考虑的角度可能有些偏差,焦点在碰撞的概率上。
    如果按照你之前提到的按照毫秒取的话,后面随机数可以取6位。
    另外,机器多少没有直接关系指的是,在机器多的时候同一毫秒甚至微妙,在实际业务中碰撞的概率并不是线性的,而且增长缓慢。
    建议你采用毫秒+6位随机数或者微妙+3位随机数做下测试,看碰撞概率究竟有多大。

  16. liangrn
    2010年9月20日13:12 | #17

    谭俊青 :

    liangrn :

    谭俊青 :@liangrn 另外要提的是,例中采用的是微妙,是百万分子一秒,不确定碰撞该概率有这么高。还有就是机器多跟这个没有直接关系,最终还是跟同一微妙下的并发多少有关。

    机器多跟这个绝对有关系的,微秒也是时间,多台服务器也是按这个算法去生成Id,重复概率绝对就高了。

    我们考虑的角度可能有些偏差,焦点在碰撞的概率上。如果按照你之前提到的按照毫秒取的话,后面随机数可以取6位。另外,机器多少没有直接关系指的是,在机器多的时候同一毫秒甚至微妙,在实际业务中碰撞的概率并不是线性的,而且增长缓慢。建议你采用微妙+6位随机数或者毫秒+3位随机数做下测试,看碰撞概率究竟有多大。

    我采用的就是楼主的算法试验的,也是精确度到微秒,不是毫秒。8位毫秒(年月日,减了39年1238119411秒所以8位) + 6位微秒 + 3位随机数。

  17. liangrn
    2010年9月20日13:19 | #18

    另外有些业务是会在众多服务器下不断并发插入数据的,所以服务器之间的碰撞概率也需要考虑的。所以我说还是跟业务有关系,如果那些业务并发量少,微秒级已经很少发生重复概率的按问题不大,否则就需要加强冲突重试处理了。

  18. sigma
    • 2010年11月30日03:09 | #20

      这个就是中心化的思想,容易出问题,第二点说的就是这个。

  19. yangzhen
    2012年8月31日14:28 | #21

    我看不懂你这个方法是什么意思。能讲讲吗

  1. 本文目前尚无任何 trackbacks 和 pingbacks.