美团Leaf源码——号段模式源码解析

前言

分布式ID生成策略基本要求就是全局不重复,最好还能递增,长度较短,性能高,可用性强。关于相关的实现方案有很多,本文着重使用美团开源的分布式ID生成解决方案——Leaf。

关于Leaf,美团官方的介绍文档主要如下,强烈建议阅读文章大致了解Leaf的工作流程与原理,这对本文后续的源码解析有很大的帮助。

  1. Leaf:美团分布式ID生成服务开源
  2. Leaf——美团点评分布式ID生成系统

本系列Leaf源码解析部分按照使用的方式也分为号段模式和snowflake模式两篇文章,本文就来着重研究号段模式的源码实现。

本文的Leaf源码注释地址:https://github.com/MrSorrow/Leaf

I. 导入项目

Leaf由Maven构建,源码地址:https://github.com/Meituan-Dianping/Leaf
首先先Fork官方仓库到自己的仓库,我的源码注释版:https://github.com/MrSorrow/Leaf
下载源码,导入IDEA,导入成功依赖下载完成后项目结构大致如下:
项目框架

II. 测试号段模式

「创建数据库表」
DROP TABLE IF EXISTS `leaf_alloc`;

CREATE TABLE `leaf_alloc` (
  `biz_tag` varchar(128)  NOT NULL DEFAULT '' COMMENT '业务key',
  `max_id` bigint(20) NOT NULL DEFAULT '1' COMMENT '当前已经分配了的最大id',
  `step` int(11) NOT NULL COMMENT '初始步长,也是动态调整的最小步长',
  `description` varchar(256)  DEFAULT NULL COMMENT '业务key的描述',
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '数据库维护的更新时间',
  PRIMARY KEY (`biz_tag`)
) ENGINE=InnoDB;
「开启号段模式」
leaf.name=com.sankuai.leaf.opensource.test
leaf.segment.enable=true
leaf.jdbc.url=jdbc:mysql://localhost:3306/leaf_test?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8
leaf.jdbc.username=root
leaf.jdbc.password=1234

leaf.snowflake.enable=false
#leaf.snowflake.zk.address=
#leaf.snowflake.port=
「测试号段模式」

开启号段模式并配置好数据库连接后,点击启动 leaf-server 模块的 LeafServerApplication,将服务跑起来。

浏览器输入http://localhost:8080/api/segment/get/leaf-segment-test来获取分布式递增id;
获取id
监控号段模式:http://localhost:8080/cache
监控页面
数据库表:
数据库

III. 号段模式源码解析

正式进入源码前,再强烈建议阅读官方的两篇博客,对Leaf的号段模式工作模式有个大致的理解。

我们从http://localhost:8080/api/segment/get/leaf-segment-test入口来分析。该请求会交由 com.sankuai.inf.leaf.server.LeafController 处理:

@Autowired
SegmentService segmentService;

/**
 * 号段模式获取id
 * @param key 对应数据库表的biz_tag
 * @return
 */
@RequestMapping(value = "/api/segment/get/{key}")
public String getSegmentID(@PathVariable("key") String key) {
   
    // 核心是segmentService的getId方法
    return get(key, segmentService.getId(key));
}

private String get(@PathVariable("key") String key, Result id) {
   
    Result result;
    if (key == null || key.isEmpty()) {
   
        throw new NoKeyException();
    }

    result = id;
    if (result.getStatus().equals(Status.EXCEPTION)) {
   
        throw new LeafServerException(result.toString());
    }
    return String.valueOf(result.getId());
}

可以看到主要是调用 SegmentServicegetId(key) 方法。key 参数其实就是路径上对应的 leaf-segment-test,也就是数据库对应的 biz_taggetId(key) 方法返回的是 com.sankuai.inf.leaf.common.Result 对象,封装了 id 和 状态 status

public class Result {
   
    private long id;
    private Status status;

    // getter and setter....
}

public enum  Status {
   
    SUCCESS,
    EXCEPTION
}

创建SegmentService

我们进入 SegmentService 类中,再调用 getId(key) 方法之前,我们先看一下 SegmentService 类的实例化构造函数逻辑。可以看到:

package com.sankuai.inf.leaf.server;

@Service("SegmentService")
public class SegmentService {
   
    private Logger logger = LoggerFactory.getLogger(SegmentService.class);
    IDGen idGen;
    DruidDataSource dataSource;

    /**
     * 构造函数,注入单例SegmentService时,完成以下几件事:
     * 1. 加载leaf.properties配置文件解析配置
     * 2. 创建Druid dataSource
     * 3. 创建IDAllocDao
     * 4. 创建ID生成器实例SegmentIDGenImpl并初始化
     * @throws SQLException
     * @throws InitException
     */
    public SegmentService() throws SQLException, InitException {
   
        // 1. 加载leaf.properties配置文件
        Properties properties = PropertyFactory.getProperties();
        // 是否开启号段模式
        boolean flag = Boolean.parseBoolean(properties.getProperty(Constants.LEAF_SEGMENT_ENABLE, "true"));
        if (flag) {
   
            // 2. 创建Druid dataSource
            dataSource = new DruidDataSource();
            dataSource.setUrl(properties.getProperty(Constants.LEAF_JDBC_URL));
            dataSource.setUsername(properties.getProperty(Constants.LEAF_JDBC_USERNAME));
            dataSource.setPassword(properties.getProperty(Constants.LEAF_JDBC_PASSWORD));
            dataSource.init();

            // 3. 创建Dao
            IDAllocDao dao = new IDAllocDaoImpl(dataSource);

            // 4. 创建ID生成器实例SegmentIDGenImpl
            idGen = new SegmentIDGenImpl();
            ((SegmentIDGenImpl) idGen).setDao(dao);
            // 初始化SegmentIDGenImpl(加载db的tags至内存cache中,并开启定时同步更新任务)
            if (idGen.init()) {
   
                logger.info("Segment Service Init Successfully");
            } else {
   
                throw new InitException("Segment Service Init Fail");
            }
        } else {
   
            // ZeroIDGen一直返回id=0
            idGen = new ZeroIDGen();
            logger.info("Zero ID Gen Service Init Successfully");
        }
    }

    /**
     * 根据key获取id
     * @param key
     * @return
     */
    public Result getId(String key) {
   
        return idGen.get(key);
    }

    /**
     * 获取号段模式id生成器SegmentIDGenImpl
     * @return
     */
    public SegmentIDGenImpl getIdGen() {
   
        if (idGen instanceof SegmentIDGenImpl) {
   
            return (SegmentIDGenImpl) idGen;
        }
        return null;
    }
}

SegmentService 类的构造函数,主要完成以下几件事:

  1. 加载 leaf.properties 配置文件,并解析配置
  2. 创建 Druid 数据源对象 dataSource
  3. 创建 IDAllocDao 接口实例 IDAllocDaoImpl
  4. 创建ID生成器实例 SegmentIDGenImpl 并初始化
① 解析leaf.properties配置文件

通过 PropertyFactory 读取了 leaf.properties 配置文件并进行解析。其中所以的key-value配置信息最终封装为 Properties 中。

/**
 * 加载leaf.properties配置文件中配置信息
 */
public class PropertyFactory {
   
    private static final Logger logger = LoggerFactory.getLogger(PropertyFactory.class);
    private static final Properties prop = new Properties();
    static {
   
        try {
   
            prop.load(PropertyFactory.class.getClassLoade
  • 3
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
司科仿美团O2O程序码最新版+wap+微信版亲测完整版是一款基于PHP语言设计的团购网站码。 司科出品,必属精品!司科公司多年网站建设经验,专业提供商城网站制作,团购网站建设,团购APP制作,商城客户端设计,微信营销系统等服务。 PC端功能介绍: 产品发布 发布以天为形式的商品项目(添加、删除、修改、编辑) 秒杀抢团项目 发布以秒为形式的商品项目 商户展示 一、商家有自己的简单的介绍页面,介绍信息和产品 二、商家可以自己的后台对商品券进行验证消费。 商家专卖店展示系统 一、合作商家可以通过后台发布自己的展示商品和商家新闻,帮助树立商家企业形象,加强与商家的合作。 二、商家可以自己的后台对商品券进行验证消费。 商家上传系统 商家可以自行上传产品,管理员审核,审核通过即可显示,审核不通过商家再修改。 商家结算系统 V1.0 超级商家结算系统,网站自动计算商家提成 超强团购商家店铺 团购商家有独立商家店铺展示,实用性强! 会员级别V1.2 根据会员消费情况等,可以自动升级级别 手机版微信支付 包括PC的扫描支付&微信公众号的微信支付 消费评价+评分功能 独家用户消费评价+评分功能,提升用户体验 城市代理商管理V1.0 每个城市产品可以由独立代理商后台管理 可修改商品时间 可对商品进行修改结束时间,让操作更加方便、人性化。 支持商品退款 提供客户申请商品模式,让商品更加自由,让客户在商品中无后顾之忧,可对商品项目设置两种模式:支持 不支持。 支持快递商品 发布项目的时候,可选择优惠券或快递。 好友邀请 用户通过人人网、开心网、MSN/QQ等社交网络邀请好友注册购买。 邮件订阅 用户用来订阅本站每天商品项目信息,方便对自己感兴趣的商品项目及时下单购买。 短信订阅 用户输入手机号码订阅商品信息,可以收到每日最新商品的短信息。 本单答疑 展示在网站右侧,用户可通过答疑,向网站客服咨询,网站管理员在后台回复后显示内容。 常见问题 展示网站内的文字信息,比如:新手指南,入门教程以及常见问题等。 短信发券 用户购买时输入手机号码,购买成功后,可收到由商品网站统一发出的优惠券帐号和密码。 团券认证 用户消费商品券时,可以在此注销或查询团券有效期。团券注销后不可二次使用。 商家地图展示 通过后台设置商家的具体位置,方便消费型商品的客户查找 项目分类首页展示 首页分类不同的产品,不同楼层展示 多城市切换 商品产品可以分配不同的城市显示 在线客服QQ 通过客服qq,方便与网站浏览者及时沟通。 强大的在线分享 用户通过MSN 人人 网易 开心 豆瓣 百度 腾讯 飞信 新浪微博 QQ空间、等,快速分享给好朋友心怡的商品 网项目。 管理员等级及授权 总管理分配下属管理员,各自管理各自的项目 后台控制分类 自可以后台控制推荐产品,分类展示商品。 邮箱发送邮件 用户可以自己设置邮箱,群发邮件给用户 图片延时加载 采用图片延时加载,极大减少服务器带宽 快递单号批量上传 商家可以建立一个TXT文档,输入订单编号,快递单交给网站运营者,网站运营者在后台上传这个TXT文档, 系统批量给这些订单生成快递单号 每个项目设置自己独立的SEO 每个项目可以在后台设置自己独立的SEO,更利于网站被搜索引擎收录,让您的网站排名靠前。 整站生成静态页面 自动生成伪静态,可以增加网页访问速度及搜索引擎排名,提高网站的质量。 首页及内页广告位 通过后台的操作来发布首页及内页通栏相关的广告图片及图片链接从而及时发布重要信息和促销活动。 公告发布 统一发布公告,也可以按地区来发布相关的促销信息以及网站公告。 手机参与商品 通过手机上网参与商品。 购物车功能 方便用户一次性挑选多个商品进行购买 用户购买选择快递 让用户在购买时自己选择城市和快递公司 到货评论功能 用户对已购买的商品发表评论。增加用户粘性,吸引其他浏览者 虚拟购买人数 项目可以设置虚拟购买人数,刺激用户消费 管理员操作日志 根据需求进行后台管理员的权限分配 数据库的备份 根据需求自行在后台进行数据备份 用户调查参与 发布小调查,直观了解用户产品需求 多件免邮功能 根据购买数量设置是否免去邮费 友情链接 通过后台设置文字链接及图片链接 网站统计 客户根据统计报表可以知道每天用户访问量IP、浏览量pv、地区、ip地址及来自那个网站等,可根据时间生成报表,从而为网络营销提供依据。 WAP端功能介绍: 城市切换 触屏版会根据打开的用户地区进行自动城市更新,弹出提示,是否回到当前城市。 登陆注册 用户可以用QQ或者手机号码登陆触屏版进行购物,减少繁琐的输入选项。 在线搜索 触屏版首页有搜索框,用户可以输入自己喜欢的产品关键字进行查找购
根据提供的引用内容,我无法找到关于MyBatis Plus使用美团Leaf的具体信息。但是,我可以为您提供一些关于MyBatis Plus和Leaf的基本介绍。 MyBatis Plus是一个基于MyBatis的增强工具,它简化了MyBatis的开发流程,提供了更多的便利功能,如自动生成代码、分页查询、逻辑删除等。它可以与各种数据库进行集成,并提供了丰富的API和注解,使得开发更加高效和便捷。 美团的Leaf是一个分布式ID生成系统,它可以生成全局唯一的ID。Leaf提供了两种ID生成算法:基于数据库的分段生成ID和雪花算法生成分布式ID。这些算法可以确保生成的ID在分布式环境下是唯一的。 如果您想在MyBatis Plus中使用美团Leaf,您可以按照以下步骤进行操作: 1. 首先,您需要将Leaf集成到您的项目中。您可以通过引用美团Leaf的Git仓库或者下载代码来获取Leaf。 2. 然后,您需要根据Leaf的文档和示例代码,配置Leaf的相关参数,如数据库连接信息、ID生成算法等。 3. 接下来,您可以在MyBatis Plus的Mapper接口中定义一个方法,用于生成ID。您可以使用Leaf提供的API来生成ID,并将其作为参数传递给您的SQL语句。 4. 最后,您可以在您的业务逻辑中调用该方法,以生成唯一的ID。 请注意,以上步骤仅为一种可能的集成方式,具体的实现方式可能因项目需求和配置而有所不同。建议您参考美团Leaf的官方文档和示例代码,以获得更详细的集成指南和使用方法。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值