分布式ID-入门了解
1. 概念:
在分布式系统中,经常需要对大量的数据、消息、http请求等进行唯一标识,就需要不能出现的ID。
互联网应用中,某个表可能要占用很大的物理存储空间,为了解决该问题,使用数据库分片技术。将一个数据库进行拆分,通过数据库中间件连接。
如果数据库中该表选用ID自增策略,则可能产生重复的ID,此时应该使用分布式ID生成策略来生成ID。
例如:比如下订单需求,因数据库订单表已经分片,若用主键自增,分片后的各个表会产生重复ID。所以这个系统需要满足以下需求:
全局唯一:不能出现重复ID。
高可用:ID生成系统是基础系统,被许多关键系统调用,一旦宕机,会造成严重影响。
2.解决方式:
1.UUID(本地生成32位的ID,不需要进行远程调用,时延低,性能高;ID过长,没有排序)
2.Flicker方案(采用了MySQL自增长ID的机制,可靠性高,有序;系统扩容困难,数据库压力大)
3.TDDL序列生成方式(阿里的分库分表中间件,有全局数据库ID的生成方式;强依赖数据库,数据库异常时整个系统不可用)
4.Redis(可产生自增序号;主键产生需强依赖Redis)
5.Oracle(可产生与表无关的序列;只有Oracle数据库才能使用)
6.Snowflake算法(有序,性能高,可调整bit位划分;
依赖机器时钟,如果机器时钟回拨,会导致重复ID生成。
在单机上是递增的,但是由于涉及到分布式环境,每台机器上的时钟不可能完全同步,有时候会出现不是全
局递增的情况。)
***推荐使用雪花算法,时钟问题可百度解决!!!
主要原因:
业务需求:业务要求生成的ID要有递增趋势,全局唯一,并且为数字。
系统考虑:第三种方案性能高,稳定性高,对外部资源依赖少。
依据实际业务需求和系统规划,对算法进行局部调整,可使用 发号器snowflake方案。
3.Snowflake算法:
开源的twitter( 非官方中文惯称:推特。是国外的一个网站,是一个社交网络及微博客服务)的snowflake算法。
* <p>名称:IdWorker.java</p>
* <p>描述:分布式自增长ID</p>
* <pre>
* Twitter的 Snowflake JAVA实现方案
* </pre>
* 核心代码为其IdWorker这个类实现,其原理结构如下,我分别用一个0表示一位,用—分割开部分的作用:
* 1||0---0000000000 0000000000 0000000000 0000000000 0 --- 00000 ---00000 ---000000000000
* 在上面的字符串中,第一位为未使用(实际上也可作为long的符号位),接下来的41位为毫秒级时间,
* 然后5位datacenter(数据中心)标识位,5位机器(也叫进程)ID(并不算标识符,实际是为线程标识),
* 然后12位该毫秒内的当前毫秒内的计数,加起来刚好64位,为一个Long型。
* 这样的好处是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由datacenter和机器ID作区分),
* 并且效率较高,经测试,snowflake每秒能够产生26万ID左右,完全满足需要。
* 64位二进制ID (42(毫秒)+5(机器ID)+5(业务编码)+12(重复累加序列号))-->生成后会转为十进制的long类型整数
【使用】:
(1)工具类IdWorker.java拷贝到common工具类工程;
(2)在service工程的spring配置文件中添加配置(每个节点的进程和数据数据不能一样,若一样ID可能会重复);
<bean id="idWorker" class="util.IdWorker">
<!-- 进程 ID 取值:0~31 -->
<constructor-arg index="0" value="0"></constructor-arg>
<!-- 数据中心 ID 取值:0~31 -->
<constructor-arg index="1" value="0"></constructor-arg>
</bean>
(3)生成。
@Autowired
private IdWorker idWorker;
long orderId = idWorker.nextId();
**直接用:
IdWorker idWorker = new IdWorker();
long orderId = idWorker.nextId();