简单的ID生成器设计

1. ID生成器

    在工作中,我们经常需要用到ID生成器。比如当当前系统与别的系统有一些数据需要同步时,为了实现幂等性,往往会为每一次同步请求设定一个全局统一的ID。可见ID生成器在许多项目中都有至关重要的多用。

    ID生成器有许多的实现方式。

     1. 比如用著名的UUID,这种方法可以简单的获取到全局唯一的ID。但是因为获得的ID是字符串,在一些需要纯数据的场合,处理起来效率没有这么高。

     2.使用数据库的自增ID,但是需要数据落库之后才能拿到。

    本篇文章分享一种简单的ID生成器,可以支持多台实例使用。另外也支持自定定义每日或者每月重置。

 

2.设计思路

   为了提高ID生成器的访问速度,可以将当前的ID值存在内存中。而为了防止多个实例出现相同的ID,我们需要分配不同的ID段到不同的实例上,这样保证每个实例用的ID数字段都是不同的,也就不会出现重复的情况。同时将最新分配的数据段记录到数据库中,实现持久化。并且使用唯一键和乐观锁防止并发。分配ID段的步长可以自定义,如果设定为1,则每次分配的ID段都是1,能保证生成的ID是连续的,但是也导致每次生成ID都要去更新数据库。

   总结上面的设计思路后,假设当前业务编号(type)为1,ID生成器的分配ID段的步长为100,每日自动重置为0,当前日期为20200815,可以得到:

1. 调用ID生成器生成函数时,首先到内存中寻找有没有已经分配的ID段,如果没有,则到数据库中搜索是否有type=1 and time=20200815的记录,如果没有,创建一条记录(idvalue=100, type = 1,time=20200815),并且把0-100的数据段存到内存中使用。如果存在则更新idvalue=idvalue+步长。(使用乐观锁防止并发)

2.如果内存中存在已经分配的ID,则取ID,并且更新内存中ID的最新值。如果ID值超出了分配的ID段。则到数据库中搜出type=1 and time=20200815 的Idvalue,并且把(idvalue - idvalue+步长)放入内存中,并且更新数据库idvalue=idvalue+步长。

3.如果需要月结,年节等,只需要控制time字段就能实现。

 

3.代码 

其中部分逻辑等待读者自己去实现。(临时写的,如果发现问题可以交流)

class id_creator(objects):
    id_value_dict = {}
    step = 100 # step可以写成一个外部的字典,这样可以简单的更新步长

    def create_id(time, idtype):
       key = _create_key(time, idtype)  # 生成key的逻辑自己实现即可
       segment = id_value_dict.get(key)
       # 这里segment是一个类
       if segment is None or segment.value > sement.max_v:
           segment = self._create_new_segment(time, idtype)
        

    
        id_value = segment.value
        segment.value = segment.value + 1
        
        return id_value


    def _create_new_segment(time, type):
        #从数据库中获取记录,自行实现
        database_record = get_data_from_sql(time, idtype)

        # 这里使用乐观锁,一直循环到更新或者创建成功
        while True:
            # 如果没有数据库记录,则直接创建记录
            if database_recode is None:
                try:
                    _create_database_record(time, idtype, step)
                    max_value = step
                except:
                    continue
            # 如果有,更新记录
            else:
                max_value = database_recode.id_value + step
                try:
                    _update_database_record(time, idtype, max_value)
                except:
                    continue
                
            

            if  max_value > 0:
                break
        # 创建新的segment
        segment = Segment(value=max_value - step + 1, max_v=max_value)
        key = _create_key(time, idtype)
        id_value_dict[key] = segment

        return segment
   

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值