当前位置: 刻度器 >> 刻度器前景 >> Golang分布式系统
本文梳理了golang分布式系统的知识点。
一、分布式id生成器在高并发场景中,通常需要类似MySQL自增id一样不断增长且不会重复的id。
比如某电商双11时,在0:00开始,会有千万到亿级的订单涌入,每秒要处理10w+的订单。在将订单插入数据库前,我们需要给订单一个唯一的id再插入数据库内。也正因为订单量大,一个无意义的纯数字id在对数据库进行增删改查时不能起到优化作用。此id内应该包含一些时间信息,这样即使后端的系统对消息进行了分库分表,也能够以时间顺序对这些消息进行排序。
Twitter的snowflake算法是这种场景下的一个典型解法,原理如图:
首先确定的是,id数值长度是64位,int64类型,被分为四个部分(不含开头的符号/unused):
41位来表示收到请求时的时间戳,单位为毫秒5位表示数据中心的id5位表求机器的实例id12位为循环自增id到达,,后归0这样的机制可以支持一台机器在一毫秒内能够产生条消息。一秒共.6w条消息。从值域上来讲完全够用。
数据中心id加上实例id共有10位,每个数据中心可以部署32台实例,搭建32个数据中心,所以可以一共部署台实例。
41位的时间戳(毫秒为单位)能够使用69年。
1worker_id分配timestamp,datacenter_id,worker_id和sequence_id这四个字段中,timestamp和sequence_id是由程序在运行期生成的。但datacenter_id和worker_id需要在部署阶段就能够获取得到,并且一旦程序启动之后,就是不可更改的了。如果可以随意更改,可能被不慎修改,造成最终生成的id有冲突。
一般不同数据中心的机器,会提供对应的获取数据中心id的API,所以datacenter_id我们可以在部署阶段轻松地获取到。而worker_id是我们逻辑上给机器分配的一个id,这个要怎么办呢?比较简单的想法是由能够提供这种自增id功能的工具来支持,比如MySQL:
mysqlinsertintoa(ip)values("10.1.2.");QueryOK,1rowaffected(0.00sec)mysqlselectlast_insert_id();+------------------+
last_insert_id()
+------------------+
2
+------------------+1rowinset(0.00sec)
从MySQL中获取到worker_id之后,就把这个worker_id直接持久化到本地,以避免每次上线时都需要获取新的worker_id。让单实例的worker_id可以始终保持不变。
当然,使用MySQL相当于给我们简单的id生成服务增加了一个外部依赖。依赖越多,我们的服务的可运维性就越差。
考虑到集群中即使有单个id生成服务的实例挂了,也就是损失一段时间的一部分id,所以我们也可以更简单暴力一些,把worker_id直接写在worker的配置中,上线时,由部署脚本完成worker_id字段替换。
2开源实例2.1标准snowflakegithub.
转载请注明:http://www.aideyishus.com/lkcf/279.html