开发者学堂课程【全面讲解开源数据库中间件 MyCat 使用及原理(四):MyCat - 日志模块 - 日志表的 ID 生成分析】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/758/detail/13322
MyCat - 日志模块 - 日志表的 ID 生成分析
内容介绍:
一、日志表的 ID 生成分析
二、分布式 ID 生成
一、日志表的 ID 生成分析
对于插入日志,需要向表结构中插入一条数据。
在插入数据前,先要分析 id 的内容,该 id 设置的不是组件自增
1.分析:
为什么 tb_operatelog 这种表设置的不是组件自增?
原因是这张表将来的数据量可能会很大,这张表存储的是操作日志,操作日志随时间的累计数据量会非常大(大到一个服务器的磁盘存储不下)。这时需要考虑到扩容,就要使用到 MyCat 对该块数据库表进行分片。也就是说这张表到最后需要进行水平拆分,可能会拆分为多张表。假如这张表被拆分为两张表,tb_operatelog 被拆分到两个数据库中,两个数据库中都有这张表,并且表结构相同,但是其中存储的数据不同。
如果将该表的组件设置为组件自增(都从 1 开始),则两个数据库都从 1 开始自增,发现组件冲突。不同的数据库中存储不同的数据,表结构相同,最终出现组件冲突。
所以不能使用组件自增。
二、分布式 ID 生成
既然不能使用组件自增,则要如何生产该组件,并且要保证不会出现重复的 id?
方式较多,可以使用 UUID,也可以借助于 Redis。
这里推荐一种分布式 ID 的生成算法
1. snowflake(雪花算法)
snowflake 是 Twitter 开源的分布式 ID 生成算法,结果是一个 long 型的 ID。(能够保证在分布式集群环境下,不会出现重复的 id )
2.核心思想∶
使用 41bit 作为毫秒数,10bit 作为机器的 ID ( 5 个 bit 是数据中心,5 个 bit 的机器 ID ),12bit 作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是 0 ;
3.如何实现
Twitter 提供的 snowflake 算法是由 64 位二进制组成的,64 位二进制分为 5 个部分组成。第一位是不用的,永远是 0。第二位是表的时间戳(是毫秒值,仅仅提供毫秒值是不行的,因为同一个毫秒中可能要生成多个 id ),为了解决在同一个毫秒内也可能会产生多个 id 的情况,引入了最后 12 位的序列号(在一个毫秒内要生成多个 id,前面的毫秒值不同,后面的序列号也不同,会自增生成序列号)。
这样可以解决同一个毫秒值内通过序列号进行区分。
但是在集群环境下多态机器,同一个毫秒值多态机器都从某一个值开始向上自增,则有可能其序列号和毫秒值都相同。
所以在雪花算法中又引入了工作机器 id,机器工作 id 实际上分为两个部分,第一个五位和第二个五位,第一个五位代表机器 id,第二个五位表示数据中心的 id。
通过机器 id 和数据中心的 id 来进行区分,再去生成 id 时需要指定机器 id 和数据中心 id ,从而区分不同的服务器。机器 id 和数据中心 id 的取值分别从 0 到 31、3到 31。(从 0-31 的原因:五个二进制位就是 2 的 5 次方,2 的 5 次方是 32,所以从0-31)
通过机器 id 和数据中心的 id 来区分或者生成不同的 id ,即使在集群环境下也不会出现重复的 id 。能够支持的集群容量是 1024(32*32)台服务器,能够保证在集群数量在 1024 台之内不出现重复的 id 。
4.使用方式:
//构造 Idworker
Idworker idworker=new Idworker (1,1);
//0-31 , 0-31,(1,1)表示数据中心的 id 和机器 id
for (int i=0 ; i<10000 ;i++){
long id = idworker . nextId();
System.out.println(id);
}
要在日志模块中使用,则需要引入 Idworker
这里已经引入:
要在 v_service_log 中使用,需要将 pom.xml 引入
最好让 Idworker 不用每次都创建(new),交给 Spring 容器管理,所以进行如下配置:
@Bean
public IdWorker idworker(){
return new IdWorker(workerId:0,datacenterId:0)
}
对于 Bean 注解,其含义为将当前方法的返回值作为 Spring 容器中的 Bean 存在。
在后续的插入日志中,直接注入该 IdWorker 即可。