分布式系统唯一ID生成方案

系统唯一ID是我们在设计一个系统的时候常常会遇见的问题,也常常为这个问题而纠结 。生成ID的方法有很多,适应不同的场景、需求以及性能要求 。所以有些比较复杂的系统会有多个ID生成的策略 。下面就介绍一些常见的ID生成策略 。
1、数据库自增长序列或字段最常见的方式 。利用数据库,全数据库唯一 。
优点:
1)简单,代码方便,性能可以接受 。
2)数字ID天然排序,对分页或者需要排序的结果很有帮助 。
缺点:
1)不同数据库语法和实现不同,数据库迁移的时候或多数据库版本支持的时候需要处理 。
2)在单个数据库或读写分离或一主多从的情况下,只有一个主库可以生成 。有单点故障的风险 。
3)在性能达不到要求的情况下,比较难于扩展 。
【分布式系统唯一ID生成方案】4)如果遇见多个系统需要合并或者涉及到数据迁移会相当痛苦 。
5)分表分库的时候会有麻烦 。
优化方案:
1)针对主库单点,如果有多个Master库,则每个Master库设置的起始数字不一样,步长一样,可以是Master的个数 。比如:Master1 生成的是 1,4,7,10,Master2生成的是2,5,8,11 Master3生成的是 3,6,9,12 。这样就可以有效生成集群中的唯一ID,也可以大大降低ID生成数据库操作的负载 。
2、UUID常见的方式 。可以利用数据库也可以利用程序生成,一般来说全球唯一 。
优点:
1)简单,代码方便 。
2)生成ID性能非常好,基本不会有性能问题 。
3)全球唯一,在遇见数据迁移,系统数据合并,或者数据库变更等情况下,可以从容应对 。
缺点:
1)没有排序,无法保证趋势递增 。
2)UUID往往是使用字符串存储,查询的效率比较低 。
3)存储空间比较大,如果是海量数据库,就需要考虑存储量的问题 。
4)传输数据量大
5)不可读 。
3、UUID的变种1)为了解决UUID不可读,可以使用UUID to Int64的方法 。及
/// <summary>/// 根据GUID获取唯一数字序列/// </summary>public static long GuidToInt64(){    byte[] bytes = Guid.NewGuid().ToByteArray();    return BitConverter.ToInt64(bytes, 0);}2)为了解决UUID无序的问题,NHibernate在其主键生成方式中提供了Comb算法(combined guid/timestamp) 。保留GUID的10个字节,用另6个字节表示GUID生成的时间(DateTime) 。
/// <summary> /// Generate a new <see cref="Guid"/> using the comb algorithm. /// </summary> private Guid GenerateComb(){    byte[] guidArray = Guid.NewGuid().ToByteArray();     DateTime baseDate = new DateTime(1900, 1, 1);    DateTime now = DateTime.Now;     // Get the days and milliseconds which will be used to build        //the byte string        TimeSpan days = new TimeSpan(now.Ticks - baseDate.Ticks);    TimeSpan msecs = now.TimeOfDay;     // Convert to a byte array            // Note that SQL Server is accurate to 1/300th of a        // millisecond so we divide by 3.333333        byte[] daysArray = BitConverter.GetBytes(days.Days);    byte[] msecsArray = BitConverter.GetBytes((long)      (msecs.TotalMilliseconds / 3.333333));     // Reverse the bytes to match SQL Servers ordering        Array.Reverse(daysArray);    Array.Reverse(msecsArray);     // Copy the bytes into the guid        Array.Copy(daysArray, daysArray.Length - 2, guidArray,      guidArray.Length - 6, 2);    Array.Copy(msecsArray, msecsArray.Length - 4, guidArray,      guidArray.Length - 4, 4);     return new Guid(guidArray);}


推荐阅读