美团Leaf源码——snowflake模式源码解析

前言

上一篇文章介绍了如何使用Leaf的号段模式生成分布式全局唯一id,参照下图我们简单总结一下。当我们部署Leaf集群时(图中是3个),每个节点起初都包含一个双 buffer,也就是双号段。当有请求过来时,每个节点都会去数据库查询按照初始的DB中的step去更新最大id,从而获取到一个号段,然后每个节点当第一个号段用到超过10%的时候再异步准备第二个号段。所以按照图中的理解可以认为左中右三个节点依次被调用请求test_tag业务对应的id,从而每个节点都获得到自己的号段,三个节点都按照step=1000去更新maxId,最后maxId表示已经分配最大的id为3000,接下来三个节点谁先用到超过10%就会再去异步准备另一个号段。等到请求量都达到10%之后,都会准备好双buffer,然后不断切换异步准备。
号段模式
这次我们主要讨论snowflake模式的使用以及源码解析。本文的Leaf源码注释地址:https://github.com/MrSorrow/Leaf

I. 测试snowflake模式

「安装ZooKeeper」

这里选择Docker的方式快速搭建一个单机版的ZooKeeper,用于整合Leaf框架。

docker pull zookeeper:3.4firewall-cmd --zone=public --add-port=2181/tcp --permanent
firewall-cmd --zone=public --add-port=2888/tcp --permanent
firewall-cmd --zone=public --add-port=3888/tcp --permanent
firewall-cmd --reloaddocker run --name leaf-zookeeper --restart always -p 2181:2181 -e TZ=Asia/Shanghai -d zookeeper:3.4

可能会遇到 WARNING IPv4 forwarding is disabled. Networking will not work 错误,解决方法如下:

vi /usr/lib/sysctl.d/00-system.conf
# 添加上一行
net.ipv4.ip_forward=1
# 重启network服务
systemctl restart network
# 查看
sysctl net.ipv4.ip_forward
# 如果返回为“net.ipv4.ip_forward = 1”则表示成功了

「开启snowflake模式」

主要配置好最后的三项,开启snowflake模式,配置好zookeeper的地址和端口号。

leaf.name=com.sankuai.leaf.opensource.test
# 关闭号段模式
leaf.segment.enable=false
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=true
leaf.snowflake.zk.address=192.168.2.113
leaf.snowflake.port=2181

「启动测试」

仍然和号段模式启动一样,点击启动 leaf-server 模块的 LeafServerApplication,将服务跑起来。
snowflake模式启动成功
浏览器输入http://localhost:8080/api/snowflake/get/key来获取分布式递增id。或者通过命令行中 curl 方式进行测试。

wangguopingdeMacBook-Air:~ guoping$ curl http://localhost:8080/api/snowflake/get/key1
1128852519460536335
wangguopingdeMacBook-Air:~ guoping$ curl http://localhost:8080/api/snowflake/get/key1
1128852531322028054wangguopingdeMacBook-Air:~ guoping$ curl http://localhost:8080/api/snowflake/get/key2
1128852655284682815
wangguopingdeMacBook-Air:~ guoping$ curl http://localhost:8080/api/snowflake/get/key2
1128852694715334657

我们将返回的id转换为十六进制数,可以确定 workerId 是 0,时间戳也确实在递增,自增序列却不是递增的,这在后面我们研究源码可以知道当时间戳一致才会自增,时间戳增大后,自增序列要“清零”重新开始自增。

1128852519460536335=0-00011111010101001111101011000101011001001-0000000000-000000001111
1128852531322028054=0-00011111010101001111101011001010111010101-0000000000-0000000101101128852655284682815=0-00011111010101001111101100000100101001000-0000000000-000000111111
1128852694715334657=0-00011111010101001111101100010111000000001-0000000000-000000000001

按照snowflake算法的比特分配,我们将上述的id值转换成对应的形式。图中有些错误,最后自增序列是12位。
snowflake比特分配

III. snowflake模式源码分析

有了号段模式源码的分析基础,我们对于整个项目的结构有了更加清晰的认识。调用snowflake模式下的Leaf服务,依然调用的是 LeafController 下的接口,然后Service层的实现则换成了 SnowflakeService,Service层依赖的ID生成器 IDGen 的实现类则是 SnowflakeIDGenImpl
snowflake模式
下面我们就来从LeafController 下的接口出发。

@Autowired
SnowflakeService snowflakeService;/*** snowflake模式获取id* @param key 随便定义* @return*/
@RequestMapping(value = "/api/snowflake/get/{key}")
public String getSnowflakeID(@PathVariable("key") String key) {return get(key, snowflakeService.getId(key));}

可以看出核心方法调用的是 SnowflakeServicegetId(key) 方法。

SnowflakeService

/*** snowflake模式的service层*/
@Service("SnowflakeService")
public class SnowflakeService {private Logger logger = LoggerFactory.getLogger(SnowflakeService.class);/*** ID生成器*/IDGen idGen;/*** 构造函数,注入单例SnowflakeService时,完成以下几件事:* 1. 加载leaf.properties配置文件解析配置* 2. 创建snowflake模式ID生成器* 3. 初始化ID生成器* @throws InitException*/public SnowflakeService() throws InitException {// 1. 加载leaf.properties配置文件解析配置Properties properties = PropertyFactory.getProperties();// 是否开启snowflake模式boolean flag = Boolean.parseBoolean(properties.getProperty(Constants.LEAF_SNOWFLAKE_ENABLE, "true"));if (flag) {// 2. 创建snowflake模式ID生成器String zkAddress = properties.getProperty(Constants.LEAF_SNOWFLAKE_ZK_ADDRESS);int port = Integer.parseInt(properties.getProperty(Constants.LEAF_SNOWFLAKE_PORT));idGen = 


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部