美团分布式Id生成器-Leaf

327 阅读2分钟

一.介绍

 There are no two identical leaves in the world.<br />     世界上没有两片完全相同的树叶。<br />								                               — 莱布尼茨<br />Leaf 最早期需求是各个业务线的订单ID生成需求。在美团早期,有的业务直接通过DB自增的方式生成ID,有的业务通过redis缓存来生成ID,也有的业务直接用UUID这种方式来生成ID。以上的方式各自有各自的问题,因此我们决定实现一套分布式ID生成服务来满足需求。具体Leaf 设计文档见:[leaf 美团分布式ID生成服务](https://tech.meituan.com/MT_Leaf.html)

二.分布式id生成策略

  • uuid: 性能非常高:本地生成,没有网络消耗。问题缺点:id太长且随机,对于依赖b树提高性能的优化来说严重影响性能,安全性会暴露mac地址

  • redis:当redis不存在时,获取数据库中最大的id+1。问题缺点利用redis绝大多数情况高效易用,但是数据丢失时候虚啊哟去数据库中获取最大的id,且对锁的掌握求比较高(比较复杂)

  • 类snowflake: 循序可以保证递增,性能ok,问题缺点:依赖机器时钟,如果机器时钟回拨可能导致id重复。

  • 数据库生成:id依靠数据来做id自增 问题缺点:但是需要每次都访问数据库,性能不好。

  • leaf:有两种模式 segment | snowflake

          segment 依靠数据库来预生成id号段缓存到leaf服务器中,且leaf利于扩展<br />            snowflake 十分适用于订单,解决简单自增可以推导出订单量的情况,且解决了类snowflake:中时钟的问题(利用zk来持久化时钟数据,如果发现时钟不正确则报错启动运行失败)
    

三.使用 Leaf两种模式 segment | snowflake

3.1 segment

  • 1.创建数据库/表/数据
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.修改配置文件 /Leaf/leaf-server/src/main/resources/leaf.properties
leaf.name=com.sankuai.leaf.opensource.test
leaf.segment.enable=true
leaf.jdbc.url=jdbc:mysql://xxxxxx/leaf?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
leaf.driver.class.name=com.mysql.cj.jdbc.Driver //原先没有这段是作者加的
leaf.jdbc.username=xxxx
leaf.jdbc.password=xxxx
  • 3.打包
mvn clean install -DskipTests
  • 4.启动
mvn spring-boot:run  或  sh deploy/run.sh
  • 5.测试
curl http://localhost:8080/api/segment/get/leaf-segment-test

3.2 snowflake

  • 1.修改配置文件 /Leaf/leaf-server/src/main/resources/leaf.properties
leaf.snowflake.enable=ture //原先是false 如果需要使用snowflake模式我们需要将它开启
leaf.snowflake.zk.address=xxx:2181,xxx:2181,xxx:2181
leaf.snowflake.port=1900
  • 2.测试
curl http://localhost:8080/api/snowflake/get/test

四.监控页面

号段模式:http://localhost:8080/cache

五.遇到的问题

描述: 我的rds mysql版本是8.0以上,当我最先修改了jdbc版本后出现以下异常
截屏2023-03-15 11.56.13.png
解决办法:

  • 1.父级pom文件

mysql-connector-java.version 5.x.x -> 8.x.x

  • 2.代码 com.sankuai.inf.leaf.server.Constants

添加 public static final String LEAF_DRIVER_CLASS_NAME = "leaf.driver.lass.name";

  • 3.server/src/main/resources/leaf.properties

添加 leaf.driver.class.name=com.mysql.cj.jdbc.Driver

  • 4.com.sankuai.inf.leaf.server.service.SegmentService

dataSource.setDriverClassName(properties.getProperty(Constants.LEAF_DRIVER_CLASS_NAME));