分布式ID的使用

1.背景

分布式id(Distributed ID)可以用来唯一标识分布式系统中的各个实体、任务或请求。它可以用于多种用途,包括以下几个方面:

1. 数据库主键:在分布式数据库中,每个数据记录需要一个唯一的主键标识。分布式id可以用作主键,确保数据记录的唯一性。

2. 分布式锁:在分布式系统中,多个节点之间需要共享锁来实现同步和互斥。分布式id可以作为锁的名称,确保每个节点使用的锁是唯一的。

3. 分布式消息队列:在消息队列系统中,分布式id可以用来标识消息的发送和接收状态,以便进行消息的可靠传输和处理。

4. 分布式事务:在分布式事务中,分布式id可以用来标识事务的唯一性,确保事务的一致性和隔离性。

5. 分布式任务调度:在分布式任务调度系统中,分布式id可以用来标识任务的唯一性,确保任务的正确执行和结果的正确处理。

总之,分布式id可以在分布式系统中实现唯一标识、数据一致性、任务调度等功能,提高系统的可靠性和性能。

这里我们采用美团的leaf算法来实现分布式的唯一ID

2.号段模式

官方很懒,到现在还没有上传maven仓库,需要手动git下来。

git clone git@github.com:Meituan-Dianping/Leaf.git
git checkout feature/spring-boot-starter
cd Leaf
mvn clean install -Dmaven.test.skip=true 

2.1依赖引入

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <artifactId>leaf-boot-starter</artifactId>
            <groupId>com.sankuai.inf.leaf</groupId>
            <version>1.0.1-RELEASE</version>
        </dependency>
    </dependencies>

2.2sql执行

CREATE DATABASE leaf
CREATE TABLE `leaf_alloc` (
  `biz_tag` varchar(128)  NOT NULL DEFAULT '',
  `max_id` bigint(20) NOT NULL DEFAULT '1',
  `step` int(11) NOT NULL,
  `description` varchar(256)  DEFAULT NULL,
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`biz_tag`)
) ENGINE=InnoDB;

insert into leaf_alloc(biz_tag, max_id, step, description) values('leaf-segment-test', 1, 2000, 'Test leaf Segment Mode Get Id')

2.3 使用

1.在resources文件下创建一个leaf.properties

leaf.name=com.sankuai.leaf.opensource.test
leaf.segment.enable=true
leaf.segment.url=jdbc:mysql://localhost:3306/leaf
leaf.segment.username=root
leaf.segment.password=123456

2.主函数引入@EnableLeafServer注解

package com.mikey.distributed;

import com.sankuai.inf.leaf.plugin.annotation.EnableLeafServer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author mikey
 * @create 2024-03-03 21:21
 */
@SpringBootApplication
@EnableLeafServer
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }
}

3.实际应用

@RestController
public class IdController {

    @Autowired
    private SegmentService segmentService;

    @GetMapping("/segment")
    public Result getId1() {
        return segmentService.getId("leaf-segment-test");
    }
    
}

2.4总结

Leaf 最早期需求是各个业务线的订单ID生成需求。在美团早期,有的业务直接通过DB自增的方式生成ID,有的业务通过redis缓存来生成ID,也有的业务直接用UUID这种方式来生成ID。以上的方式各自有各自的问题,因此我们决定实现一套分布式ID生成服务来满足需求。(来自官网)

我们会发现在获取id的时候,需要一个key,这个key实际就是数据库的biz_tag这个字段,代表着业务的标签。max_id就是这次请求拿到的id,step就是步长。

假设此时数据库是  max_id = 1 , step = 20。

那么这次请求拿到的id就是1,然后他会缓存这1-20的id,下一次请求而不会请求数据库,而是从缓存里面拿,这里就是他性能高的原因。你会发现当你请求多几次的时候,而id还没到20,数据库的max_id更新到了21,这是因为他会提前去申请id空间,防止id不够,而提前做了数据库更新。

3.雪花算法

雪花算法(Snowflake Algorithm)是一种用于生成分布式系统中唯一 ID 的算法。

  1. 64 位二进制格式:Snowflake 算法生成的唯一 ID 是一个 64 位的整数,其结构一般是:1位符号位(不使用)、41位的时间戳、10位的机器标识(或工作机器 ID)、12位的序列号。

  2. 时间戳部分:占据了整个 64 位中的高位 41 位,可以精确到毫秒级别的时间,可以保证在相同的时间戳内生成的 ID 唯一。

  3. 机器标识部分:占据了中间的 10 位,用于区分不同的机器。这部分的信息可以手动配置或者从机器的某些特征中提取,例如数据中心 ID 和机器 ID 的组合。

  4. 序列号部分:占据了低位的 12 位,用于解决在同一毫秒内产生大量请求时的并发冲突问题。在同一毫秒内,序列号会从 0 开始递增,最多可以生成 4096(2^12)个不同的 ID。

  5. 生成 ID 的规则:Snowflake 算法根据当前时间戳、机器标识和序列号生成唯一的 ID。当某个节点生成 ID 时,它会根据当前时间戳计算出时间戳部分,将机器标识和序列号部分组合成 ID。

实际上不同的公司都会根据自己的场景从而去改造雪花算法,可以从时间戳部分或者机器表示部分或者序列号部分去优化,可以参考一下百度UidGenerator。

3.1依赖引入

这里需要引入zk的相关依赖,可以理解成zk在这里做了数据库这样的角色,存储了机器的标识符(ip)。这里不展开zk的安装,自行查看相关资料。

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <artifactId>leaf-boot-starter</artifactId>
            <groupId>com.sankuai.inf.leaf</groupId>
            <version>1.0.1-RELEASE</version>
        </dependency>
        <!--zk-->
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>2.6.0</version>
            <exclusions>
                <exclusion>
                    <artifactId>log4j</artifactId>
                    <groupId>log4j</groupId>
                </exclusion>
            </exclusions>
        </dependency>

3.2使用

1.在resources文件下创建一个leaf.properties

leaf.name=com.sankuai.leaf.opensource.test

leaf.snowflake.enable=false
leaf.snowflake.address=ip
leaf.snowflake.port=port

2.使用

    @Autowired
    private SnowflakeService snowflakeService;


    @GetMapping("/snowflake")
    public Result getId2() {
        return snowflakeService.getId("111");
    }

我们可以发现雪花算法这里也要获取一个key,实际上这里的key是没有意义的。看看github上的解释。

  • 33
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mikey689

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值