一个兼容 Redis 协议的 ID 生成器

2016-04-07 13:55:28 +08:00
 flikecn

idgo 简介

1. idgo 特点

idgo 是一个利用 MySQL 批量生成 ID 的 ID 生成器, 主要有以下特点:

业界已经有利于 MySQL 生成 ID 的方案,都是通过:

REPLACE INTO Tickets64 (stub) VALUES ('a');
SELECT LAST_INSERT_ID();

这种方式生成 ID 的弊端就是每生成一个 ID 都需要查询一下 MySQL,当 ID 生成过快时会对 MySQL 造成很大的压力。这正式我开发这个项目的原因。服务端兼容 Redis 协议是为了避免单独开发和 idgo 通信的 SDK 。

2. idgo 架构

idgo 和前端应用是才有 redis 协议通信的,然后每个id_key是存储在 MySQL 数据库中,每个 key 会在 MySQL 中生成一张表,表中只有一条记录。这样做的目的是保证当 idgo 由于意外崩溃后,id_key对应的值不会丢失,这样就避免产生了 id 回绕的风险。

idgo 目前只支持四个 redis 命令:

1 . SET key value,通过这个操作设置 id 生成器的初始值。
例如: SET abc 123
2. GET key,通过该命令获取 id 。
3. EXISTS key,查看一个 key 是否存在。
4. DEL key,删除一个 key 。

3. 安装和使用 idgo

  1. 安装 idgo
	1. 安装 Go 语言环境( Go 版本 1.3 以上),具体步骤请 Google 。
	2. 安装 godep 工具, go get github.com/tools/godep 。 
	2. git clone https://github.com/flike/idgo src/github.com/flike/idgo
	3. cd src/github.com/flike/idgo
	4. source ./dev.sh
	5. make
	6. 设置配置文件
	7. 运行 idgo 。./bin/idgo -config=etc/idgo.toml

设置配置文件(etc/idgo.toml):

#idgo 的 IP 和 port
addr="127.0.0.1:6389"
#log_path: /Users/flike/src 
#日志级别
log_level="debug"

[storage_db]
mysql_host="127.0.0.1"
mysql_port=3306
db_name="idgo_test"
user="root"
password=""
max_idle_conns=64

操作演示:

#启动 idgo
➜  idgo git:(master) ✗ ./bin/idgo -config=etc/idgo.toml
2016/04/07 11:51:20 - INFO - server.go:[62] - [server] "NewServer" "Server running" "netProto=tcp|address=127.0.0.1:6389" req_id=0
2016/04/07 11:51:20 - INFO - main.go:[80] - [main] "main" "Idgo start!" "" req_id=0

#启动一个客户端连接 idgo
➜  ~  redis-cli -p 6389
redis 127.0.0.1:6389> get abc
(integer) 0
redis 127.0.0.1:6389> set abc 100
OK
redis 127.0.0.1:6389> get abc
(integer) 101
redis 127.0.0.1:6389> get abc
(integer) 102
redis 127.0.0.1:6389> get abc
(integer) 103
redis 127.0.0.1:6389> get abc
(integer) 104
redis 127.0.0.1:6389>

4. 压力测试

压测环境

|类别|名称| |---|---| |OS |CentOS release 6.4| |CPU |Common KVM CPU @ 2.13GHz| |RAM |2GB| |DISK |50GB| |Mysql |5.1.73|

本地 mac 连接远程该 MySQL 实例压测 ID 生成服务。 每秒中可以生成 20 多万个 ID 。性能方面完全不会有瓶颈。

5.ID 生成服务宕机后的恢复方案

当 idgo 服务意外宕机后,可以切从库,然后将 idgo 对应的 key 加上适当的偏移量。

License

MIT

开源地址: https://github.com/flike/idgo

2278 次点击
所在节点    Go 编程语言
30 条回复
flikecn
2016-04-07 16:32:49 +08:00
@skydiver MySQL 起来后加一个固定的偏移(比如 1000 )后可以保证不会重现重复的 ID 。因为只可能丢失固定的一段 id 值。
moro
2016-04-07 17:41:37 +08:00
idgo.go 121 行 的 defer 是不是应该放在 err 条件前面一行

rows, err := tx.Query(selectForUpdate)
if err != nil {
tx.Rollback()
return 0, err
}
defer rows.Close() //line 121
noahzh
2016-04-07 21:29:06 +08:00
@flikecn 就是通过 etcd watch 实现配置自动重加载
detailyang
2016-04-07 23:35:14 +08:00
嘿嘿,搭车发下曾花了一个晚上改的,线上稳定跑了一年的、用 redis 改的发号器。。。原理跟你说的一样,开启 aof always ,高可用是靠 lvs 做的四层的负载均衡, 缺点嘛不是严格的单调递增。。。因为每个实例的增长序列不同, https://github.com/detailyang/id-generator
jsq2627
2016-04-08 02:15:45 +08:00
sqlserver 有 sequence 这个东西, mysql 还真没什么好替代品。赞楼主!
flikecn
2016-04-08 10:13:33 +08:00
@detailyang 赞赞,我看看。
flikecn
2016-04-08 10:13:53 +08:00
@jsq2627 谢谢
surfire91
2016-04-08 11:02:08 +08:00
@flikecn 了解了,之前项目做个类似的功能,只是 mc+mysql+少量代码实现了类似功能。
感觉你的这个项目得基于 mysql 有些麻烦,考虑过加入持久化吗?
flikecn
2016-04-08 13:41:11 +08:00
@surfire91 基于 mysql 是可以利用事务批量申请 ID 。
zeayes
2016-04-08 14:39:54 +08:00
@flikecn redis 也可以批量 incr ,把 redis 配置的 appendfsync 参数改为 always ,可以替代该方案中的 mysql 事务。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/269235

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX