分布式惟一id生成策略

最近发现公司用的公共jar包里生成惟一主键的方法居然用的是当前时间戳,这种方式有明显弊端,参考了网上各类生成惟一id的方式以后,作下总结。java

1、数据库自增IDmysql

使用mysql数据库的自增id,数据库的自增id的优势是很是明显的:第一是速度快,并且是按序自增,检索很是有利。第二是自增的id都是数字型,占用空间小,易于程序中排序。 第三是新增记录时能够不用指定id,不用担忧主键重复问题。
算法

固然,使用数据库自增ID也有缺点:第一是手动插入指定ID的记录时会比较麻烦。第二是当新老系统合并作数据迁移时,新旧系统都是数字型,会致使多个主键id冲突,或新旧系统主键不一样是数字型就会致使修改主键数据类型。第三若是ID是连续的,恶意用户的扒取工做就很是容易作了,直接按照顺序下载指定URL便可;若是是订单号就更危险了,竞对能够直接知道咱们一天的单量。因此在一些应用场景下,会须要ID无规则、不规则。sql

2、UUID数据库

UUID保证对在同一时空中的全部机器都是惟一的。UUID由如下几部分的组合:
(1)当前日期和时间,UUID的第一个部分与时间有关,若是你在生成一个UUID以后,过几秒又生成一个UUID,则第一个部分不一样,其他相同。
(2)时钟序列。
(3)全局惟一的IEEE机器识别号,若是有网卡,从网卡MAC地址得到,没有网卡以其余方式得到。
数组

java中提供了两个对应的方法:安全

randomUUID() ,适用于生成惟一订单号。  服务器

nameUUIDFromBytes(byte[] n)会根据n产生惟一的uuid。只要有用户的惟一性信息。就能保证此用户的uuid的惟一性。网络

优势:性能很是高:本地生成,没有网络消耗。app

缺点:第一是不易存储,UUID太长,16字节128位,一般以36长度的字符串表示,不少场景不适用。第二是信息不安全,基于MAC地址生成UUID的算法可能会形成MAC地址泄露,这个漏洞曾被用于寻找梅丽莎病毒的制做者位置。

下面是UUID及生成8位UUID的java实例:

public class UUIDTest {

    public static String[] chars = new String[]
            {
                    "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
                    "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
                    "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"
            };

    public static void main(String[] args) {
        System.out.println(UUID.randomUUID().toString().replace("-", ""));
        System.out.println(getShortUuid());
    }

    public static String getShortUuid() {
        StringBuffer stringBuffer = new StringBuffer();
        String uuid = UUID.randomUUID().toString().replace("-", "");
        for (int i = 0; i < 8; i++) {
            String str = uuid.substring(i * 4, i * 4 + 4);
            int strInteger = Integer.parseInt(str, 16);
            stringBuffer.append(chars[strInteger % 0x3E]);
        }

        return stringBuffer.toString();
    }
}复制代码

其中生成8位UUID的思路是:将32位UUID按每四位截取,将截取的每组字符串转换成10进制的数字,而后对0x3E(十进制为62)取余,根据取余获得的结果找到ASCII字符数组中(总共62个字符)的位置,将每组的结果拼接就获得一个8位的UUID字符串。

3、SnowFlake雪花算法

雪花ID生成的是一个64位的二进制正整数,而后转换成10进制的数。64位二进制数由以下部分组成:

0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000

1位标识部分,在java中因为long的最高位是符号位,正数是0,负数是1,通常生成的ID为正数,因此为0;
41位时间戳部分,这个是毫秒级的时间,通常实现上不会存储当前的时间戳,而是时间戳的差值(当前时间-固定的开始时间),这样可使产生的ID从更小值开始;41位的时间戳可使用69年,(1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69年;
10位节点部分,Twitter实现中使用前5位做为数据中心标识,后5位做为机器标识,能够部署1024个节点;
12位序列号部分,支持同一毫秒内同一个节点能够生成4096个ID;

优势

  • 简单高效,生成速度快。
  • 时间戳在高位,自增序列在低位,整个ID是趋势递增的,按照时间有序递增。
  • 灵活度高,能够根据业务需求,调整bit位的划分,知足不一样的需求。

缺点

  • 依赖机器的时钟,若是服务器时钟回拨,会致使重复ID生成。
  • 在分布式环境上,每一个服务器的时钟不可能彻底同步,有时会出现不是全局递增的状况。
相关文章
相关标签/搜索