高性能高可用的分布式唯一ID服务——mooon-uniq-id

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
云数据库 RDS MySQL Serverless,价值2615元额度,1个月
简介: 目录 目录 1 1. 前言 1 2. 名词 1 3. 功能 1 4. 唯一性原理 2 5. 系统结构 2 5.

目录

目录 1

1. 前言 1

2. 名词 1

3. 功能 1

4. 唯一性原理 2

5. 系统结构 2

5.1. mooon-uniq-agent 2

5.2. mooon-uniq-master 2

6. 限制 3

7. 核心思想 4

8. 编译&安装 4

9. 启动&运行 5

10. 编程使用 5


1. 前言

源码位置:https://github.com/eyjian/mooon/tree/master/application/uniq_id


mooon-uniq-id可单机运行,也可以由1~255台机器组成集群分布式运行。性能极高,单机批量取(每批限定最多100个),每秒可提供2000个唯一ID服务,单个取每秒可以提供20唯一ID服务。

mooon-uniq-id还具极高的可用性,只要有一台机器正常即可正常提供服务。

2. 名词

Lable 机器标签

3. 功能

mooon-uniq-id提供64位无符号整数唯一ID和类似于订单号、流水号的字符串唯一ID

4. 唯一性原理

mooon-uniq-id生成的唯一ID通过以下公式保证:

唯一ID = 机器唯一标签 本机递增序列号 系统时间


机器唯一标签自动生成,取值从1~255,故最多支持255台机器组成集群。时间粒度为小时,单台机器一小时内的递增序列号值为536870911个,只要一小时内提供的唯一ID数不超过536870911个即是安全的。如果需求超过536870911,则可以扩展到分钟的粒度,mooon-uniq-id保留了6位供用户自由支配,这保留的6位可以用于存储分钟值。

5. 系统结构

mooon-uniq-id的实现为单进程无线程UDP实现简单高效。采用弱主架构,这种架构下,master在一段时间内不可用,完全不影响正常服务。租期为多长,即可允许多长时间内master不可用,比如租期为7天,则7天内master不可用都不影响正常服务,agentmaster的依赖非常低,因此叫弱主架构。

mooon-uniq-idmooon-uniq-agentmooon-uniq-master组成弱主架构,为保证可用性mooon-uniq-agent至少1台以上,而且只要有一台可以用即整体可用。

mooon-uniq-master一般可部署2台形成主备,实际上部署一台也完全无问题,因为mooon-uniq-master只要在租期内恢复正常即可。

5.1. mooon-uniq-agent

对外提供获取唯一ID服务的是mooon-uniq-agent,至少应当部署2台,以提供必要的可用性,部署的越多可用性越高,同时每秒提供的唯一ID个数也越多,支撑的并发数也越大。

mooon-uniq-agent在能够对外服务之前,都必须先从mooon-uniq-master租约到机器标签,否则不能服务。

5.2. mooon-uniq-master

mooon-uniq-master负责租约的管理,包括租约的初始化、租约的分配和租约的过期管理和回收。

默认情况下,mooon-uniq-agent每隔1分钟以心跳的形式向mooon-uniq-master续租机器标签,可以通过命令行参数“--interval”修改续租间隔,参数值的单位为秒,默认值为6001分钟。

mooon-uniq-master将机器标签存储在MySQL表中,各机器标签的状态也存储在MySQL表中。mooon-uniq-masterMySQL有依赖,但也不是强依赖,因为只要在租期内可以成功续租或新租成功即可,而一旦集群上线后,99.999%的时间都只是续租。


在启动mooon-uniq-master之前,需要先创建好如下3MySQL库和表:

-- CREATE DATABASE IF NOT EXISTS uniq_id DEFAULT CHARSET utf8 COLLATE utf8_general_ci;

 

-- Label资源池表

-- mooon-uniq-master第一次启动时会初始化t_label_pool

DROP TABLE IF EXISTS t_label_pool;

CREATE TABLE t_label_pool (

    f_label TINYINT UNSIGNED NOT NULL,

    PRIMARY KEY (f_label)

);

 

-- Label在线表

-- f_label为主键,保证同一时间不可能有两个IP租赁同一个Label,

-- 但一个IP可能同时持有一个或多个过期的Label,和一个当前有效的Label

DROP TABLE IF EXISTS t_label_online;

CREATE TABLE t_label_online (

    f_label TINYINT UNSIGNED NOT NULL,

    f_ip CHAR(16) NOT NULL,

    f_time DATETIME NOT NULL,

    PRIMARY KEY (f_label),

    KEY idx_ip(f_ip),

    KEY idx_time(f_time)

);

 

-- Label日志表

-- 记录租约和续租情况

DROP TABLE IF EXISTS t_label_log;

CREATE TABLE t_label_log (

    f_id BIGINT NOT NULL AUTO_INCREMENT,

    f_label TINYINT UNSIGNED NOT NULL,

    f_ip CHAR(16) NOT NULL,

    f_event TINYINT NOT NULL,

    f_time DATETIME NOT NULL,

    PRIMARY KEY (f_id),

    KEY idx_label(f_label),

    KEY idx_ip(f_ip),

    KEY idx_event(f_event),

    KEY idx_time(f_time)

);

6. 限制

ID具备唯一性,但不具备递增性。

7. 核心思想

要保证ID的唯一性,最关键是要保证同一个机器标签不能同时出现在多台机器上。mooon-uniq-id的实现引入租约,每台mooon-uniq-agent在服务之前需要先成功租约到机器标签,在租约期内独占标签,并且可以在租期内续租。

在租期后,每个机器标签还有一段冻结期,处于冻结期的机器标签不会被租约。

通过这样的一种机制保证了机器标签的安全性,只要每台mooon-uniq-agent保证序列号在该机器上唯一,那么两者相结合即保证了整体上的唯一性。

序列号总是有限的,为保证永久的唯一性,在组成唯一ID时,加上了时间共同组成唯一性。

8. 编译&安装

mooon-uniq-id依赖mooon基础库,使用gitTortoiseGit下载mooon库源码:

https://github.com/eyjian/mooon/tree/master/mooon

同样,使用gitTortoiseGit下载mooon-uniq-id源码:

https://github.com/eyjian/mooon/tree/master/application/uniq_id


两者均采用CMake编译,且编译方法相同,先编译mooon基础库,编译和安装步骤:

1) 进入源代码目录,执行cmake生成Makefile文件,安装目录指定为/usr/local/mooon:

cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=/usr/local/mooon .

2) 执行make编译源代码:

make

3) 在make成功后,执行“make install”完成安装:

/usr/local/mooon

├── bin

├── CMake.common

├── include

│     └── mooon

│           ├── net

│           ├── sys

│           └── utils

└── lib

       └── libmooon.a


接着编译和安装mooon-uniq-id,方法相同,安装路径也请指定为/usr/local/mooon。

9. 启动&运行

简单点可以放到crontab中自动拉起,比如借助process_monitor.sh(下载:https://github.com/eyjian/mooon/blob/master/mooon/shell/process_monitor.sh)的监控和自动重启功能:

* * * * * /usr/local/bin/process_monitor.sh "/usr/local/uniq_id/bin/uniq_master" "/usr/local/uniq_id/bin/uniq_master --db_host=127.0.0.1 --db_port=3306 --db_user=zhangsan --db_pass='zS2018' --db_name=uniq_id"

* * * * * /usr/local/bin/process_monitor.sh "/usr/local/uniq_id/bin/uniq_agent" "/usr/local/uniq_id/bin/uniq_agent --master_nodes=192.168.31.33.225.168.251:16200,192.168.31.35:16200"

10. 编程使用

可以参考uniq_test.cppuniq_stress.cpp使用mooon-uniq-id,如:

bool polling = false; // 轮询还是随机选择mooon-uniq-agent

const uint32_t timeout_milliseconds = 200;

const uint8_t retry_times = 5;

 

// 注意:需要捕获CSyscallException和CException两种异常

try

{

    // agent_nodes为mooon-uniq-agent连接信息,多个间以逗号分隔,注意不要包含空格:

    // 如:192.168.1.31:6200,192.168.1.32:6200,192.168.1.33:6200

    mooon::CUniqId uniq_id(agent_nodes, timeout_milliseconds, retry_times, polling);

 

    // 取交易流水号

    //

    // %L 为取mooon-uniq-agent的机器标签,每个mooon-uniq-agent不会有相同的标签

    // %Y 为YYYY格式的年,如2017

    // %M 为MM格式的月,如:04或12等

    // %D 为DD格式的日,如:01或31等

    // %m 为mm格式的分钟,如:09或59等

    // %H 为hh格式的小时,24小时制,如:03或23等

    // %5S 表示取5位的序列号,不足时前补0

    std::string transaction_id = uniq_id.get_transaction_id("%L%Y%M%D%m%5S");

    fprintf(stdout, "%s\n", transaction_id.c_str());

 

    // 取8字节无符号整数值

    const uint64_t uniq_id = uniq_id.get_uniq_id();

    union mooon::UniqID uid;

    uid.value = uniq_id;

    fprintf(stdout, "id: %" PRIu64" => %s\n", uniq_id, uid.id.str().c_str());

}

catch (mooon::sys::CSyscallException& ex)

{

    fprintf(stderr, "%s\n", ex.str().c_str());

}

catch (mooon::utils::CException& ex)

{

    fprintf(stderr, "%s\n", ex.str().c_str());

}



相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
24天前
|
监控 负载均衡 Cloud Native
ZooKeeper分布式协调服务详解:面试经验与必备知识点解析
【4月更文挑战第9天】本文深入剖析ZooKeeper分布式协调服务原理,涵盖核心概念如Server、Client、ZNode、ACL、Watcher,以及ZAB协议在一致性、会话管理、Leader选举中的作用。讨论ZooKeeper数据模型、操作、会话管理、集群部署与管理、性能调优和监控。同时,文章探讨了ZooKeeper在分布式锁、队列、服务注册与发现等场景的应用,并在面试方面分析了与其它服务的区别、实战挑战及解决方案。附带Java客户端实现分布式锁的代码示例,助力提升面试表现。
34 2
|
2月前
|
消息中间件 算法 Java
【亿级数据专题】「分布式服务框架」 盘点本年度我们探索服务的保障容量的三大关键方案实现
【亿级数据专题】「分布式服务框架」 盘点本年度我们探索服务的保障容量的三大关键方案实现
188 0
|
10天前
使用JWT的服务分布式部署之后报错:JWT Check Failure:
使用JWT的服务分布式部署之后报错:JWT Check Failure:
20 1
|
17天前
|
存储 SQL 算法
搞定了 6 种分布式ID,分库分表哪个适合做主键?
在《ShardingSphere5.x分库分表原理与实战》系列的第七篇文章中,作者探讨了分布式ID在分库分表中的重要性,以及如何利用`ShardingSphere-jdbc`的多种主键生成策略。文章介绍了`UUID`、`NanoID`、自定义雪花算法和`CosId`等策略的优缺点,并警告不要在SQL中手动拼接主键字段。此外,文章还展示了如何配置这些策略,并提醒读者`CosId`在5.2.0版本可能不可用。最后,文章讨论了如何自定义分布式主键生成算法,并强调选择策略时要考虑全局唯一性、性能和易用性。
|
2月前
|
缓存 算法 关系型数据库
深度思考:雪花算法snowflake分布式id生成原理详解
雪花算法snowflake是一种优秀的分布式ID生成方案,其优点突出:它能生成全局唯一且递增的ID,确保了数据的一致性和准确性;同时,该算法灵活性强,可自定义各部分bit位,满足不同业务场景的需求;此外,雪花算法生成ID的速度快,效率高,能有效应对高并发场景,是分布式系统中不可或缺的组件。
深度思考:雪花算法snowflake分布式id生成原理详解
|
2月前
|
缓存 前端开发 小程序
【分布式技术专题】「架构设计方案」盘点和总结RBAC服务体系的功能设计及注意事项技术体系
【分布式技术专题】「架构设计方案」盘点和总结RBAC服务体系的功能设计及注意事项技术体系
31 0
|
2月前
|
XML 安全 Java
【分布式技术专题】「单点登录技术架构」一文带领你好好对接对应的Okta单点登录实现接口服务的实现落地
【分布式技术专题】「单点登录技术架构」一文带领你好好对接对应的Okta单点登录实现接口服务的实现落地
62 0
|
2月前
|
消息中间件 SpringCloudAlibaba Java
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(八)Config服务配置+bus消息总线+stream消息驱动+Sleuth链路追踪
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(八)Config服务配置+bus消息总线+stream消息驱动+Sleuth链路追踪
786 0
|
8天前
|
NoSQL Java 关系型数据库
【Redis系列笔记】分布式锁
分布式锁:满足分布式系统或集群模式下多进程可见并且互斥的锁。 分布式锁的核心思想就是让大家都使用同一把锁,只要大家使用的是同一把锁,那么我们就能锁住线程,不让线程进行,让程序串行执行,这就是分布式锁的核心思路
30 2
|
3天前
|
监控 NoSQL 算法
探秘Redis分布式锁:实战与注意事项
本文介绍了Redis分区容错中的分布式锁概念,包括利用Watch实现乐观锁和使用setnx防止库存超卖。乐观锁通过Watch命令监控键值变化,在事务中执行修改,若键值被改变则事务失败。Java代码示例展示了具体实现。setnx命令用于库存操作,确保无超卖,通过设置锁并检查库存来更新。文章还讨论了分布式锁存在的问题,如客户端阻塞、时钟漂移和单点故障,并提出了RedLock算法来提高可靠性。Redisson作为生产环境的分布式锁实现,提供了可重入锁、读写锁等高级功能。最后,文章对比了Redis、Zookeeper和etcd的分布式锁特性。
36 16
探秘Redis分布式锁:实战与注意事项