分布式服务下唯一序号的生成

数据库完全自增:所有服务器连同个db,在一张表中定义auto_increment自增的方法获得序号,这样保证不重复,这种方法每次获取id都需要连一次db,效率比较低,可以应用在低频交易系统,如应用管理平台的交易

PS:其中数据库含关系型数据库、内存数据库等(如redis)

数据库不完全自增:所有服务器连同个db,db中用自增的方法获取一个序号,并设置步长,每台服务器每次从db中获取到一次序号后,保留在内存中,每次需要生产序号则从内存中序号递增直到步长使用完毕再从db中获取,这样以减少与db的交互。(对于自增也可以不设置步长,而由应用程序来维护步长,如步长为1000,则n*1000到(n+1)*1000-1)但服务器每次重启会丢弃部分序号。该方案不适合序号必须连续的场景。

时间+应用+数据库不完全自增:如果对于交易记录这样交易id可能在实际应用中数据量比较大,建议增加时间的控制,而对于分布式多DB的应用程序还可以将应用服务器在流水中记录,即给每台服务器分配一个id。最后该id的组成为:年月日+机器id +数据库不完全自增id。在此之上还可以再延伸修改数据库不完全自增值。在每日交易发生的第一笔都更新数据库id为1,然后以1为基础增加。该方案的id记录长度较大,适合高频大数据量的业务,且不会发生数据库id到上限的风险。

时间+随机数:如果不使用db,且容许出现小概率的重复id可以使用时间+随机数,多机情况可以使用机器id+时间+随机数。如2位机器id+System.currentTimeMillis()+5位随机数。这种id适合唯一性不强的系统使用,有的系统会对此数据做DES加密转为Base64编码输出以避免直接被看到系统时间,当然这样就会牺牲系统性能

Twittersnowflake:snowflake是twitterr开源的一个id生产方法。该id用64位表示。

固定0 | 41位时间 | 10位机器id |12位自增id

41位时间是精确到系统的毫秒,41位的毫秒时间最大支持70年,10位机器id最大支持1023台服务器。12位自增id支持1毫秒内单台服务器最大并发为4095.当达到4095后则等待下一毫秒并继续生成新的id。最后将64位转为16进制存储,这样应用程序不依赖db,且能保证唯一,而且只保存16位字符,占用空间也不大。该方法从效率及并发上看都能达到较大预期。

参考:http://massivetechinterview.blogspot.com/2015/06/twitteridsnowflake-iteye.html

mangoDBObjectId:mangoDB ObectId的生成类似于snowflake算法,存储的位数增大。在数据组成上增加了线程id,objectid由12个字节组成

4位时间 | 3位机器id | 2位线程id | 3位自增id

参考:http://www.cnblogs.com/xjk15082/archive/2011/09/18/2180792.html

参考:https://github.com/mongodb/mongo-java-driver/blob/master/bson/src/main/org/bson/types/ObjectId.java

Uuid:对于java应用使用uuid可以保证不重复,这种方法开发极为简单,唯一存在的问题是存储的字节较长,有32位字符。也有人对uuid取前一半16位+4位随机数,但这种方法就可能产生重复值。

有限id:对于有的应用对id数量及id值有限制,既要随机又要唯一,比如银行卡号的分配。这里简单介绍下银联卡号的分配:6位银行卡bin + 12位银行卡序号+校验位。而对于很多银行会对第7、8位做特殊处理,比如区分银行卡类型,那么序号则剩下10位。为了不让客户开卡时了解银行开卡的大致数据量还需要随机产生卡号。且不能产生特殊号(如连续8个8)。对于这样的id产生流程大致可以这样实现:1.先将所有特殊号提取到单独的表中;2.对于10位序号切分100张表,每张表有1000万数据(除去特殊号实际没有1000万,而在银行中可以先放开1000万给用户使用,1000万张银行卡应该已经是个中型规模的银行了)。对1000万数据初始化,并随机打散,每次客户请求则pop第一条数据,或者再把表改为更小1000张100万的表,然后每张表随机打散,开卡时随机取1000中的一张表并pop第一条数据。


分布式服务下唯一序号的生成_第1张图片

你可能感兴趣的:(分布式服务下唯一序号的生成)