多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
[TOC] > [参考](https://chai2010.cn/advanced-go-programming-book/ch6-cloud/ch6-01-dist-id.html) ## 概述 在插入数据库之前,我们需要给这些消息、订单先打上一个ID,然后再插入到我们的数据库。对这个id的要求是希望其中能带有一些时间信息,这样即使我们后端的系统对消息进行了分库分表,也能够以时间顺序对这些消息进行排序 ## Twitter的snowflake算法 ![](../../images/screenshot_1654350944627.png) id 大小为 int64位,被划分为四部分,不含开头的第一个bi,用41位来表示收到请求时的时间戳,单位为毫秒,然后五位来表示数据中心的id,然后再五位来表示机器的实例id,最后是12位的循环自增id(到达1111,1111,1111后会归0) 表示`timestamp`的41位,可以支持我们使用69年,所以这里的`timestamp`只是相对于某个时间的增量,比如我们的系统上线是2018-08-01,那么我们可以把这个timestamp当作是从`2018-08-01 00:00:00.000`的偏移量 ### worker_id分配 `timestamp`,`datacenter_id`,`worker_id`和`sequence_id`这四个字段中,`timestamp`和`sequence_id`是由程序在运行期生成的。但`datacenter_id`和`worker_id`需要我们在部署阶段就能够获取得到 一般不同数据中心的机器,会提供对应的获取数据中心id的API,所以`datacenter_id`我们可以在部署阶段轻松地获取到 worker_id是我们逻辑上给机器分配的一个id,有两种方式生成 1. 使用mysql的自增id,但是引入 mysql 增加对外部的依赖 ``` mysql> insert into a (ip) values("10.1.2.101"); Query OK, 1 row affected (0.00 sec) mysql> select last_insert_id(); +------------------+ | last_insert_id() | +------------------+ | 2 | +------------------+ 1 row in set (0.00 sec) ``` 2. `worker_id`直接写在worker的配置中,上线时,由部署脚本完成`worker_id`字段替换 ### go 实现 ``` package main import ( "fmt" "os" "github.com/bwmarrin/snowflake" ) func main() { n, err := snowflake.NewNode(1) if err != nil { println(err) os.Exit(1) } for i := 0; i < 3; i++ { id := n.Generate() fmt.Println("id", id) fmt.Println( "node: ", id.Node(), "step: ", id.Step(), "time: ", id.Time(), "\n", ) } } ``` ## sonyflake 算法 ![](blob:https://www.kancloud.cn/c923063a-76c6-4961-9c26-8c69ebd9febd)