vlambda博客
学习文章列表

雪花算法-保证数据库分库分表后id的全局唯一性

        数据库分库分表后可以带来很多好处,如解决数据库的水平扩展能力,提升读写能力。但是也带来了很多的限制,

        第一,查询时候,需要带上分区键,否则你找不到你要查询的数据在哪个库哪个表。

        第二,一些聚合类的查询count性能较差,

        第三,由于数据跨机器存储,避免跨机器查询数据,join语句很难实现。

        上面是一些问题,但是最典型的问题,就是如何保证在不同机器,不同数据表中的数据有唯一不同的主键标识呢?

对于以前的单库单表,我们喜欢用主键自增,步长为1,来保证插入的数据主键唯


一,对于自增id,有两个地方需要考虑

         1  id的自增是有顺序的,可以被人循环请求

        2  对于同一个业务表,分不到不同的机器上后,只能保证在这台机器上的唯一性,很难保证全局的唯一性。


二,要保证全局唯一性,我们需要考虑其他的办法。

1 使用特殊的业务字段作为主键,

        特殊的业务字段,如手机号,身份证号等。每个人不仅仅是有一个手机号,后期手机号更换,业务关联表外键也需要更新,很麻烦,使用身份证是能保证一人一个。但是身份证比较隐私,很多人抵触上传,而且不是所有的系统都需要用户上传个人信息,也不是太靠谱


2 自己生成业务主键。

        2.1 使用uuid 通用唯一标识码

        这个不依赖第三方系统,性能和可用性方面很好,是能作为一个唯一的标识,但是作为数据库主键,存在以下不足之处。

            2.2.1 不具有顺序性:

          UUID(),生成的数据不是递增的,可以创建测试表两个字段uuid和created_time,然后写脚本,每秒执行一次SQL :insert into 表名 select UUID(),now(); 插入大量数据后,按照uuid和created_time 排序,如果结果一样,说明uuid是有序的(ps:网上很多例子);

            为什么要保证生成 的id是有序的?

            1 因为主键id涉及到排序的问题,最简单的业务场景,评论数据,取出数据在页面展示的时候,有需要按照时间排序,如果id不是在时间上有序的,我们就不能直接通过id做排序,大家也知道id是主键索引,通过id排序可以很高效。

            2 可以插入更高效。刚刚也说了,主键也是一种索引,索引在b+树上是有序的,插入的id有序,只需要在后面持续的追加就可以了。如果不能保证id有序,你需要先找到这条id对应要插入的位置。然后在移动该位置后面的数据,这一系列的操作造成了额外的开销。


         2.2 雪花算法(snowflake)

         Twitter公司提出的snowflake算法,弥补了上面UUID的不足之处。

雪花算法的核心思想就是将64bit的数字分成若干份。每一部分都存有特殊含义的数据如时间戳,机器号等。

         41位时间戳,可以支撑(2^41)/(1000*60*60*24*365) 大约69年

            10位机器id,可以继续划分为机房id和机器id,2-3位表示机房id(可以支撑4-8个IDC机房),7-8位机器id(可以支撑128-256台机器),

            12位序列号,表示每个机器节点,每毫秒可以生成4096个id。而且可以根据各自公司的特点对具体位数做调整。如增加机房id,减少序列号等,


三,雪花算法的部署方案

        3.1 内嵌到业务代码里,也就是分布式在业务服务器中

        这种方案不需要跨网络调用,性能会好点,但是需要更多位的机器id,去支撑大量的业务服务器,因为每一台机器都要有独立的机器id,

        3.2  独立部署为服务,作为发号器服务。

        这种部署,业务在使用发号器的时候,就需要多一次网络调用,如果内网中调用,性能损耗几乎很小。而且发号器部署实例有限,机器id位数完全可以省略,写入到配置中,省下机器id位数,给序列号或者其他业务含义。


雪花算法代码网上很多,代码量不多可以写一下,