行业资讯 2025年08月6日
0 收藏 0 点赞 242 浏览 2210 个字
摘要 :

文章目录 生成有序id 生成无序id 本文主要讲解关于号段模式生成分布式ID 相关内容,让我们来一起学习下吧! 采用数据库号段模式来生成分布式id,包括生成有序id和无序i……




本文主要讲解关于号段模式生成分布式ID 相关内容,让我们来一起学习下吧!

采用数据库号段模式来生成分布式id,包括生成有序id和无序id。

生成有序id

  1. 数据库中定义相关id生成策略的表,其中每一条记录代表一种id生成策略,包括id段的起始值、结束值、步长、版本号(乐观锁实现)。
  2. id生成服务启动时,先去数据库中获取指定id对应的id生成策略,抢占号段(更新数据库对应记录的起始值、结束值、版本号)。如果更新失败,则进行有限次数的重试(重新从数据库中获取指定id对应的id生成策略,重新尝试更新)。如果更新成功,则将对应号段加载到本地。为每一种生成策略绑定一个信号量,new Semaphore(1)。
  3. 本地采用ConcurrentHashMap来保存号段,形式为<id, 号段对象>。其中本地保存的当前id值为原子类,保证线程安全。
private static Map<Integer, LocalUnSeqIdBO> localSeqIdBOMap = new ConcurrentHashMap<>();

// 号段对象的属性
/**
 * id生成策略,对应数据库中记录的主键
 */
private int id;
/**
 * 在内存中记录的当前有序id的值
 */
private AtomicLong currentNum;

/**
 * 当前id段的开始值
 */
private Long currentStart;
/**
 * 当前id段的结束值
 */
private Long nextThreshold;
  1. 当调用获取id的方法时,传入对应的生成策略的id,根据id去本地内存中获取对应的号段对象,如果获取对象成功并且生成的id在号段范围内,则通过原子类的incrementAndGet方法获取生成的id。同时启动异步任务,检查更新本地的id号段。
  2. 在异步检查更新本地的id号段中,如果已经使用的id超过阈值,另起一个线程去抢占数据库中的号段,并加载到本地内存中。为了保证线程安全,使用信号量来控制进入同步更新本地号段的线程数为1。
private void refreshLocalSeqId(LocalSeqIdBO localSeqIdBO) {
    long step = localSeqIdBO.getNextThreshold() - localSeqIdBO.getCurrentStart();
    if (localSeqIdBO.getCurrentNum().get() - localSeqIdBO.getCurrentStart() > step * UPDATE_RATE) {
        Semaphore semaphore = semaphoreMap.get(localSeqIdBO.getId());
        if (semaphore == null) {
            LOGGER.error(\"semaphore is null,id is {}\", localSeqIdBO.getId());
            return;
        }
        boolean acquireStatus = semaphore.tryAcquire();
        if (acquireStatus) {
            LOGGER.info(\"开始尝试进行本地id段的同步操作\");
            // 异步进行同步id段操作
            threadPoolExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        IdGeneratePO idGeneratePO = idGenerateMapper.selectById(localSeqIdBO.getId());
                        tryUpdateMySQLRecord(idGeneratePO);
                    } catch (Exception e) {
                        LOGGER.error(\"[refreshLocalSeqId] error is \", e);
                    } finally {
                        semaphoreMap.get(localSeqIdBO.getId()).release();
                        LOGGER.info(\"本地有序id段同步完成,id is {}\", localSeqIdBO.getId());
                    }
                }
            });
        }
    }
}

生成无序id

  1. 本地存放无序id。 Map<Integer, LocalUnSeqIdBO> localUnSeqIdBOMap = new ConcurrentHashMap<>();
  2. 无序id对象属性,使用ConcurrentLinkedQueue提前存放无序id。
private int id;
/**
 * 提前将无序的id存放在这条队列中
 */
private ConcurrentLinkedQueue<Long> idQueue;
/**
 * 当前id段的开始值
 */
private Long currentStart;
/**
 * 当前id段的结束值
 */
private Long nextThreshold;
  1. 获取本地的无序id,Long returnId = localUnSeqIdBO.getIdQueue().poll();
  2. 在获取本地无序id时,如果已经使用的id达到阈值,尝试异步更新同步本地的id号段。
  3. 更新本地id号段的操作中,同样使用信号量控制进入的线程数为1。尝试去抢占数据库中的id段,获取到对应的id段后,将段内的id提前生成并打乱顺序放入队列中。

号段模式生成分布式ID

以上就是关于号段模式生成分布式ID 相关的全部内容,希望对你有帮助。欢迎持续关注潘子夜个人博客(www.panziye.com),学习愉快哦!

微信扫一扫

支付宝扫一扫

版权: 转载请注明出处:https://www.zuozi.net/10060.html

管理员

相关推荐
2025-08-06

文章目录 一、Reader 接口概述 1.1 什么是 Reader 接口? 1.2 Reader 与 InputStream 的区别 1.3 …

986
2025-08-06

文章目录 一、事件溯源 (一)核心概念 (二)Kafka与Golang的优势 (三)完整代码实现 二、命令…

463
2025-08-06

文章目录 一、证明GC期间执行native函数的线程仍在运行 二、native线程操作Java对象的影响及处理方…

347
2025-08-06

文章目录 一、事务基础概念 二、MyBatis事务管理机制 (一)JDBC原生事务管理(JdbcTransaction)…

455
2025-08-06

文章目录 一、SnowFlake算法核心原理 二、SnowFlake算法工作流程详解 三、SnowFlake算法的Java代码…

516
2025-08-06

文章目录 一、本地Jar包的加载操作 二、本地Class的加载方法 三、远程Jar包的加载方式 你知道Groo…

831
发表评论
暂无评论

还没有评论呢,快来抢沙发~

助力内容变现

将您的收入提升到一个新的水平

点击联系客服

在线时间:08:00-23:00

客服QQ

122325244

客服电话

400-888-8888

客服邮箱

122325244@qq.com

扫描二维码

关注微信客服号