Leaf(世界上没有两片完全相同的树叶)

There are no two identical leaves in the world.

世界上没有两片完全相同的树叶。

​                                                                                                 — 莱布尼茨

懈怠了一段日子,事业、爱情你终究要二选其一,对于我而言,只能一心一意,或许是脑子不够用吧?

世界上没有两片完全相同的叶子,也没有完美的结局?想知道我最终选择了什么嘛?留个悬念啊........

把最近要学习的资料整理一下,希望能够给我带来一些帮助,也希望只言片语能够帮助到大家就问心无愧了。

Introduction:

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

目前Leaf覆盖了美团点评公司内部金融、餐饮、外卖、酒店旅游、猫眼电影等众多业务线。在4C8G VM基础上,通过公司RPC方式调用,QPS压测结果近5w/s,TP999 1ms。

使用leaf-starter注解来启动leaf

git clone [email protected]:Meituan-Dianping/Leaf.git
git checkout feature/spring-boot-starter
cd leaf
mvn clean install -Dmaven.test.skip=true 

引入依赖

<dependency>
	<artifactId>leaf-boot-starter</artifactId>
    <groupId>com.sankuai.inf.leaf</groupId>
    <version>1.0.1-RELEASE</version>
</dependency>

配置leaf.properties到你的classpath下面

springboot配置:
sagement1:properties
leaf.name=com.sankuai.leaf.opensource.test
leaf.segment.enable=false
#leaf.segment.url=
#leaf.segment.username=
#leaf.segment.password=
sagement2:yaml
leaf:
  name: leaf-name
  segment:
    url: jdbc:mysql://**********.mysql.rds.aliyuncs.com:3306/test?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=false&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true
    username: ******
    password: ******
    enable: true
snowflake1:
leaf:
  snowflake:
    enable: false 
    address: ******
    port: *******

snowflake2:
leaf.snowflake.enable=false
#leaf.snowflake.address=
#leaf.snowflake.port=

利用注解启动leaf,并使用api

//EnableLeafServer 开启leafserver
@SpringBootApplication
@EnableLeafServer
public class LeafdemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(LeafdemoApplication.class, args);
	}
}
//直接使用 spring注入
public class T {
    @Autowired
    private SegmentService segmentService;
    @Autowired
    private SnowflakeService snowflakeService;
}
 

Leaf Server的配置都在leaf-server/src/main/resources/leaf.properties中

配置项 含义 默认值
leaf.name leaf 服务名  
leaf.segment.enable 是否开启号段模式 false
leaf.jdbc.url mysql 库地址  
leaf.jdbc.username mysql 用户名  
leaf.jdbc.password mysql 密码  
leaf.snowflake.enable 是否开启snowflake模式 false
leaf.snowflake.zk.address snowflake模式下的zk地址  
leaf.snowflake.port snowflake模式下的服务注册端口

号段模式

如果使用号段模式,需要建立DB表,并配置leaf.jdbc.url, leaf.jdbc.username, leaf.jdbc.password

如果不想使用该模式配置leaf.segment.enable=false即可

创建数据表

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')

配置相关数据项

在leaf.properties中配置leaf.jdbc.url, leaf.jdbc.username, leaf.jdbc.password参数

Snowflake模式

Leaf-snowflake基本上就是沿用了snowflake的设计,ID组成结构:正数位(占1比特)+ 时间戳(占41比特)+ 机器ID(占5比特)+ 机房ID(占5比特)+ 自增值(占12比特),总共64比特组成的一个Long类型

Leaf-snowflake不同于原始snowflake算法地方,主要是在workId的生成上,Leaf-snowflake依靠Zookeeper生成workId,也就是上边的机器ID(占5比特)+ 机房ID(占5比特)。Leaf中workId是基于ZooKeeper的顺序Id来生成的,每个应用在使用Leaf-snowflake时,启动时都会都在Zookeeper中生成一个顺序Id,相当于一台机器对应一个顺序节点,也就是一个workId。

算法取自twitter开源的snowflake算法。

如果不想使用该模式配置leaf.snowflake.enable=false即可。

配置zookeeper地址

在leaf.properties中配置leaf.snowflake.zk.address,配置leaf 服务监听的端口leaf.snowflake.port。

运行Leaf Server

打包服务

git clone [email protected]:Meituan-Dianping/Leaf.git
//按照上面的号段模式在工程里面配置好
cd leaf
mvn clean install -DskipTests
cd leaf-server

运行服务

Tips: 首先得先配置好数据库表或者zk地址

ForExample:

通常在用号段模式的时候,取号段的时机是在前一个号段消耗完的时候进行的,可刚刚才取了一个ID,数据库中却已经更新了max_id,也就是说leaf已经多获取了一个号段,这是什么操作?

Leaf为什么这么设计?

为了探究这个问题,带着好奇心,测试一下研究结果.......

然后观察数据库变化,max_id根据step(1000)变为了1001

答案:

是为了DB中取号段的过程中做到无阻塞!

当号段耗尽时再去DB中取下一个号段,如果此时网络发生抖动,或者DB发生慢查询,业务系统拿不到号段,就会导致整个系统的响应时间变慢,对流量巨大的业务,这是不可容忍的。

所以Leaf在当前号段消费到某个点时,就异步的把下一个号段加载到内存中。而不需要等到号段用尽的时候才去更新号段。这样做很大程度上的降低了系统的风险。

Leaf采用双buffer的方式,它的服务内部有两个号段缓存区segment。当前号段已消耗10%时,还没能拿到下一个号段,则会另启一个更新线程去更新下一个号段。

在这里插入图片描述

Segment优点:

  • Leaf服务可以很方便的线性扩展,性能完全能够支撑大多数业务场景。
  • 容灾性高:Leaf服务内部有号段缓存,即使DB宕机,短时间内Leaf仍能正常对外提供服务。

缺点:

  • ID号码不够随机,能够泄露发号数量的信息,不太安全。
  • DB宕机会造成整个系统不可用(用到数据库的都有可能)。

SnowFlake优点:

  • ID号码是趋势递增的8byte的64位数字,满足上述数据库存储的主键要求。

缺点:

  • 依赖ZooKeeper,存在服务不可用风险(实在不知道有啥缺点了)

猜你喜欢

转载自blog.csdn.net/chajinglong/article/details/112990386
今日推荐