id分配是社区类产品的提交环节中必不可少的一步。任何UGC类内容产生时每每须要分配一个对应的id。php
id分配的几种方式 mysql
方式一:单点自增分配。全局由一个模块来负责生成id,可保证id从0开始连续递增,数据通常放在本地文件。简洁,但致命的问题是单点故障会致使服务总体不可用。算法
方式一改进:为该模块提供主从复制的能力,或者干脆将数据放在mysql里,利用mysql的主从复制,都必定程度上加强了可用性,减轻了单点故障的影响。sql
方式二:随机/散列分配。经过一些hash算法,好比以时间+随机串为key的md5生成一个惟一的id,关键点在于算法和key的选择要避免冲突。网络
最典型的就是UUID,UUID的标准型式包含32个16进位数字,以连字号分为五段,形式为8-4-4-4-12的32个字符,如550e8400-e29b-41d4-a716-446655440000。libuuid提供了以时间或者随机数为基的UUID。UUID的最大缺点是位数太长,128位,在绝大多数应用和语言里对128位整数的支持都很差。分布式
方式二改进:有条件的进行压缩。twitter的snowflake使用 time – 41 bits + configured machine id – 10 bits + sequence number – 12 bits的形式分配id,共63位,最高部分使用毫秒级的时间戳,保证了必定程度的有序性,机器标示使用10位,最多可容纳1024个分配器,最后的12位序列号能够支持在1ms内产生4096个不重复的id。从工程角度,这些都足够用了。但对系统时间的依赖性很是强,须要关闭ntp的时间同步功能,或者当检测到ntp时间调整后,拒绝分配id。ide
咱们的需求和多IDC的挑战ui
咱们的实际状况是:blog
· 一些老模块依赖于从0开始自增的id,数据在内存或者文件中以id为偏移来存储的。排序
· 一些系统依赖于id的增加作数据分片,例如按取除后分表,所以要求id在总体上是比较均衡的增加。
· 在多IDC环境,高延迟加不稳定的网络环境,要求各个分配器彼此之间无需协做,或者能够容忍短时间内不可协做。
· 对于一些古董级的老系统来讲,还在使用32位的id,63位id仍是太大了。
所以,咱们须要一种分布式高可用、从0开始自增、基本均衡、可以兼容老系统的id分配方案。
取模或分段的分布式分配
基于方案一再改进一步,将整个id空间按取模或分段等分为若干个独立的id子空间,每一个id子空间由一个独立的分配器负责。
优势:简单,各个id分配器无需协做,即便发生网络划分时,也可保证可用性和id的不冲突。
若是在国际化环境的多IDC里进行部署,须要预先将id空间划分为N份,每一个国家里部署若干份。每一个IDC内应用只连本IDC的id分配服务。
在均衡性上的不足:在同一个IDC内,均衡性能够在接入层均衡算法保证,可是在多个IDC里,ID分配器个数的比例和id增加的服务每每是不吻合的,所以在多个IDC内,id是没法保证均衡增加的。
均衡性上的改进
将id分配分为两层:
· 上层的“id分配器”对应用暴露,提供一次申请一个id的接口,通常本IDC的应用只连本IDC的id分配器。
·下层的“段分配器”对“id分配器”提供服务。id分配器“知晓”全部IDC的全部段分配器的存在,使用均衡策略向段分配器申请一个id段,当所持有的id段快耗尽时,再请求下一个段。
惟一性:全局中,根据分片规则,每一个段分配器会持有不一样的id段。例以下表中,每一个段的大小是100,段分配器A持有分片0和分片1。对于每一个分片而言,是一个个跳跃的id段。特殊的,当段大小为1时,段分配器就是改进前的id分配器。
均衡策略:均衡策略在id分配器来实现,简单的讲,是一个轮询策略。每一个id分配器会轮询下游段分配器的状态,并选中id段的最小的那个,而后发起id段申请。因为不会加锁,当多个id分配器同时竞争时,可能会出现获取的id段不是全局最小的,能够附加一些策略来调优,好比再多获取一次,并本地排序。从总体上而言,id仍是比较均衡的,可知足需求。
可用性:当发生网络划分时,本IDC的id分配器能够只链接本IDC的段分配器,成功的申请到id段。整个系统可容忍必定时间内不可协做,长时间不可协做的惟一危害是id增加不均衡,此时,就退化为改进前的方案。
多IDC环境的适应性:id分配器须要和全部IDC的段分配器交互,可是交互频率很低,同时和提供id分配服务是两个独立的阶段,不会受到多IDC网络环境的干扰。
效果
改进后的id分配方案成功的知足了图片系统重构过程当中的兼容需求,而且部署在全球多个IDC内为图片系统提供全局惟一的id分配服务。
by Lizhe