
GitHub:https://github.com/qichengzx/seqsvr 欢迎 star。
本项目使用下列优秀的项目作为必要组件。
注意:需要在启动之前创建数据库并修改配置文件中数据库的配置。
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。
REPLACE INTO `generator_table` (uuid) VALUES ("54f5a3e2-e04c-4664-81db-d7f6a1259d01"); 欢迎 star。
1 puritania 2018-07-02 10:59:52 +08:00 via iPhone 这个同样要单独部署吧,引入单点 mysql 和线程锁增加了复杂性,悲观情况下可能会有很多问题,我觉得这方案跟 snowflake 比还是不行 |
2 wych 2018-07-02 11:39:20 +08:00 发出来的 ID 是单调递增的么? |
3 qichengzx OP @puritania 感谢回复。 1.可以单独部署成一个服务,也可以整理成一个包放到已有项目中。项目目前只是以独立服务作为实现。 2.MySQL 的问题,如果请求量不是特别大应该还好。业务量大也可以通过修改步长或 MySQL 增加机器解决。 3.根据携程的介绍是 Java 版使用情况还不错,而且个人认为 Go 的协程开销应该比 Java 低很多。 这个方案与 snowflake 相比,个人觉得原理和实现都比较简单,适合比较初期的项目。 有说的不对的还请指正。 |
5 glacer 2018-07-02 14:17:37 +08:00 @qichengzx 通常只有分布式系统(如分布式数据库)才需要用到全局唯一 id,如果是初期的项目,往往根本不需要用分布式系统,根本不存在你这个系统的使用场景啊。 |
6 pathbox 2018-07-02 14:53:02 +08:00 via iPhone 用 redis 的 inc 可以更快 |
8 qichengzx OP @glacer 感谢回复。 没有接触过分布式的系统,至少没有参与过。 写这个的初衷是看到携程的那篇文章,觉得这种方案还挺有意思的,就找时间做了实现,至于实际的使用场景,目前我确实不清楚。 根据文章的介绍,携程是用在了账号系统中。 个人觉得比如 MongoDB,没有数字 ID 的系统中,如果要用到数字 ID,这种方案也是适合的。 |
9 qichengzx OP @pathbox 感谢回复。 关于 Redis 的 incr,原文中也有提到。优缺点引用如下: 优点: 不依赖于数据库,灵活方便,且性能优于数据库。 数字 ID 天然排序,对分页或者需要排序的结果很有帮助。 使用 Redis 集群也可以防止单点故障的问题。 缺点: 如果系统中没有 Redis,还需要引入新的组件,增加系统复杂度。 需要编码和配置的工作量比较大,多环境运维很麻烦, 在开始时,程序实例负载到哪个 redis 实例一旦确定好,未来很难做修改。 |
10 zhouquan03 2018-07-02 19:20:19 +08:00 这样做是有很大风险的。内存进行自增的话,高可用怎么保证?服务挂掉重启怎么保证生成的 id 不重复? 还不如搭建个高可用的 redis,进行 incr 操作,redis QPS 还远远高于 mysql。 |
11 NUT 2018-07-02 19:24:56 +08:00 要说单调递增的 ID 生成,还数 TiDB 的 TSO 牛逼, 设计很轻巧,性能又不差,实现还简单。 |
12 yanaraika 2018-07-02 19:24:57 +08:00 @zhouquan03 redis 也没法保证生成 id 不重复吧 |
13 yanaraika 2018-07-02 19:30:53 +08:00 @zhouquan03 除非用基于 Raft 的 floyd,否则 rust-cluster 默认都是最终一致性。但 Raft 引起的性能下降很严重 |
15 qichengzx OP @zhouquan03 服务挂掉重启后,会从数据库重新写一条记录拿到一个新的 ID 做起点。 |
16 rahuahua 2018-07-03 12:04:02 +08:00 如果是单台 mysql,肯定不能算高可用,如果要搭集群 mysql,对于项目初期过于复杂了。 |