Golang Go语言中 SEQSVR:Go + MySQL 实现的高性能 ID 生成服务

发布于 1周前 作者 h691938207 来自 Go语言

SEQSVR

Go + MySQL 实现的 ID 生成服务

GitHub:https://github.com/qichengzx/seqsvr 欢迎 star。

特性

  • 分布式:可任意横向扩展
  • 高性能:分配 ID 只访问内存(到达上限会请求数据库一次)
  • 易用性:对外提供 HTTP 服务
  • 唯一性:MySQL 自增 ID,永不重复
  • 高可靠:MySQL 持久化

依赖项

本项目使用下列优秀的项目作为必要组件。

安装

注意:需要在启动之前创建数据库并修改配置文件中数据库的配置。

go get 方式:

需保证 $GOPATH/bin 在系统 PATH 中。

go get github.com/qichengzx/seqsvr
seqsvr

单独编译:

git clone [email protected]:qichengzx/seqsvr.git
cd seqsvr
go build .
./seqsvr

Docker 方式:

Dockerfile 使用了 Docker 多阶段构建功能,需保证 Docker 版本在 17.05 及以上。详见:Use multi-stage builds

git clone [email protected]:qichengzx/seqsvr.git
cd seqsvr
docker build seqsvr:latest .
docker run -p 8000:8000 seqsvr:latest

初始化数据库

数据库名称可以自定义,修改 config.yml 即可。

然后导入以下 SQL 生成数据表。

CREATE TABLE `generator_table` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `uuid` char(36) NOT NULL COMMENT '机器识别码',
  PRIMARY KEY (`id`),
  UNIQUE KEY `id_UNIQUE` (`id`),
  UNIQUE KEY `stub_UNIQUE` (`uuid`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

修改配置

配置文件使用 YAML 格式。

#app
port: ':8000'

#service step: 100

#db mysql: user: ‘root’ password: ‘’ host: ‘tcp(localhost:3306)’ database: ‘sequence’

可修改端口号及 MySQL 的配置。

使用

curl http://localhost:8000/new

{“code”:0,“msg”:“ok”,“data”:{“id”:101}}

原理

本项目设计原理来自 携程技术中心 的干货 | 分布式架构系统生成全局唯一序列号的一个思路

服务初始化后第一次请求会在 MySQL 数据库中插入一条数据,以生成初始 ID。

后续的请求,都会在内存中进行自增返回,并且保证返回的 ID 不会超过设置的上限,到达上限后会再次从 MySQL 中更新数据,返回新的初始 ID。

核心 SQL
REPLACE INTO `generator_table` (uuid) VALUES ("54f5a3e2-e04c-4664-81db-d7f6a1259d01");

欢迎 star。


Golang Go语言中 SEQSVR:Go + MySQL 实现的高性能 ID 生成服务

更多关于Golang Go语言中 SEQSVR:Go + MySQL 实现的高性能 ID 生成服务的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

17 回复

这个同样要单独部署吧,引入单点 mysql 和线程锁增加了复杂性,悲观情况下可能会有很多问题,我觉得这方案跟 snowflake 比还是不行

更多关于Golang Go语言中 SEQSVR:Go + MySQL 实现的高性能 ID 生成服务的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


发出来的 ID 是单调递增的么?


感谢回复。
1.可以单独部署成一个服务,也可以整理成一个包放到已有项目中。项目目前只是以独立服务作为实现。
2.MySQL 的问题,如果请求量不是特别大应该还好。业务量大也可以通过修改步长或 MySQL 增加机器解决。
3.根据携程的介绍是 Java 版使用情况还不错,而且个人认为 Go 的协程开销应该比 Java 低很多。

这个方案与 snowflake 相比,个人觉得原理和实现都比较简单,适合比较初期的项目。

有说的不对的还请指正。


感谢回复。
是单调递增的。

通常只有分布式系统(如分布式数据库)才需要用到全局唯一 id,如果是初期的项目,往往根本不需要用分布式系统,根本不存在你这个系统的使用场景啊。

用 redis 的 inc 可以更快

snowflake 解决不了时间偏移的问题吧


感谢回复。
没有接触过分布式的系统,至少没有参与过。
写这个的初衷是看到携程的那篇文章,觉得这种方案还挺有意思的,就找时间做了实现,至于实际的使用场景,目前我确实不清楚。
根据文章的介绍,携程是用在了账号系统中。
个人觉得比如 MongoDB,没有数字 ID 的系统中,如果要用到数字 ID,这种方案也是适合的。


感谢回复。

关于 Redis 的 incr,原文中也有提到。优缺点引用如下:
优点:
不依赖于数据库,灵活方便,且性能优于数据库。
数字 ID 天然排序,对分页或者需要排序的结果很有帮助。
使用 Redis 集群也可以防止单点故障的问题。

缺点:

如果系统中没有 Redis,还需要引入新的组件,增加系统复杂度。
需要编码和配置的工作量比较大,多环境运维很麻烦,
在开始时,程序实例负载到哪个 redis 实例一旦确定好,未来很难做修改。

这样做是有很大风险的。内存进行自增的话,高可用怎么保证?服务挂掉重启怎么保证生成的 id 不重复?

还不如搭建个高可用的 redis,进行 incr 操作,redis QPS 还远远高于 mysql。

要说单调递增的 ID 生成,还数 TiDB 的 TSO 牛逼, 设计很轻巧,性能又不差,实现还简单。

redis 也没法保证生成 id 不重复吧

除非用基于 Raft 的 floyd,否则 rust-cluster 默认都是最终一致性。但 Raft 引起的性能下降很严重

#7 系统时间问题我觉得相比引入其他依赖增加调用链路来说出错几率更小。

服务挂掉重启后,会从数据库重新写一条记录拿到一个新的 ID 做起点。

如果是单台 mysql,肯定不能算高可用,如果要搭集群 mysql,对于项目初期过于复杂了。

针对您提到的Golang(Go语言)中的SEQSVR——一个基于Go和MySQL实现的高性能ID生成服务,以下是我的专业回复:

SEQSVR作为一个高性能的ID生成服务,巧妙结合了Go语言的并发处理能力和MySQL的持久化存储特性。在分布式系统中,生成全局唯一且递增的ID是一个常见需求,SEQSVR正是为了解决这一问题而设计的。

Go语言以其高效的并发模型(goroutines和channels)而著称,这使得SEQSVR能够高效地处理大量的ID生成请求。同时,通过MySQL进行数据存储,确保了ID生成的持久化和可靠性。这种设计既满足了性能需求,又兼顾了数据的安全性。

在实现上,SEQSVR可能会采用一些策略来优化ID生成的效率和准确性,比如使用预分配ID块、缓存机制以及高效的数据库访问策略等。这些策略能够减少数据库访问次数,降低延迟,提高吞吐量。

此外,SEQSVR还可能具备一些高级功能,如ID的自定义前缀、批量生成ID等,以满足不同场景下的需求。同时,通过监控和日志功能,可以方便地跟踪ID生成服务的运行状态,及时发现并解决问题。

总的来说,SEQSVR是一个基于Go和MySQL实现的、高性能且可靠的ID生成服务,适用于各种需要全局唯一ID的分布式系统。如果您正在寻找一个这样的服务,SEQSVR无疑是一个值得考虑的选择。

回到顶部