【Rocket MQ】【MsgId】MsgId 谁生成的?什么时候生成的?怎么生成的?一定唯一么?

1  前言

这节我们来看看 Rocket MQ的一个小东西,就是我们平时发消息,消息里边有个 messageId,它是全局唯一的,就好奇是谁生成的?什么时候生成的?怎么生成的?我们跟进源码看下。

我这里看的是云消息队列里的开发包哈。

2  源码分析

2.1  消息发送过程

Rocket MQ作为消息中间件,三个角度生产者、MQ、消费者,生产者制造消息发给MQ,消费者消费MQ中的消息,那么我们来看下消息的发送过程:

经过中间一系列的 send 方法,我们看最后调用的方法:

我们跟进 sendKernelImpl 看下内部发送:

可以看到 setUniqID 就是设置消息id啦。

2.2  Uniq ID 生成过程

我们继续来看看消息 ID是怎么生成的:

我们进入创建方法看看:

可以看到它是由20位的固定长度+12位的随机组成的消息ID。那我们先来看下固定长度是怎么生成的:

可以看到是静态代码块,在类加载的时候就初始化上了,是由ip+进程ID+类加载器的Hash值组成20位的固定长度。我们可以看到两个关于时间的属性:startTime、nextStartTime:

还有一个属性计数器 counter ,从0开始计数:

那我们看看 createUniqIDBuffer 的组成:

可以看到就是时间戳差+计数值来得到消息ID剩下的12位。

这样就能保证消息ID唯一么?

首先对于每个producer实例来说ip都是唯一的,所以不同producer生成的msgId是不会重复的。对于producer单个实例来说的区分因子是时间戳差和计数值。首先应用不重启的情况下msgId是保证唯一性的;应用重启了只要系统的时钟不变msgId也是唯一的。所以只要系统的时钟不回拨我们就可以保证msgId的全局唯一。有人也许会说应用运行了一个月再进行重启msgId就会重复了。从生成算法上来说是的,但是MQ的message是有时效性的,有效期是72小时也就是3天。每天的凌晨4点rocketMQ会把过期的message清除掉。所以msgId也是保证全局唯一的。

还有随机字符是时间戳+short计数值 short也就是65535个,时间戳是毫秒级,1毫秒内发送超过65535个消息的话,其实消息ID是会重复的,但是基本上1毫秒是不会这么多的吧。哈哈哈。

消息ID是谁生成的?什么时候生成的?怎么生成的?

我们看完就有结论了,是由Producer生产者发送消息的时候生成的,由20位的固定字符(ip+进程id+类加载器Hash值)+12位的(时间戳差以及计数值)来组成的。

3  小细节

批量消息发送的时候,消息ID也是这样生成的么?

是的,也都是MessageClientIDSetter.setUniqID(message); 来循环逐个生成的。

 ByteBuffer是什么?可以用来干什么呢?

我们刚才可以看到 ByteBuffer.allocate,这是干什么呢?字面意思字节缓冲区,allocate()分配新的ByteBuffer。该方法需要一个参数,即缓冲区的容量。它返回分配的新的ByteBuffer。如果提供的容量为负,则抛出IllegalArgumentException。其实也就是申请一块字节为单位的固定长度的缓冲区。

byte 数组转十六进制字符串

// final static char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
public static String bytes2string(byte[] src) {
    char[] hexChars = new char[src.length * 2];
    for (int j = 0; j < src.length; j++) {
        // & 过之后,byte 转成 int
        int v = src[j] & 0xFF;
        // 无符号右移 4 位,高位补 0 ,即取字节的高 4 位
        hexChars[j * 2] = HEX_ARRAY[v >>> 4];
        // 取字节低 4 位
        hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
    }
    return new String(hexChars);
}

可以看到把一个字节拆成高4位低4位后,分别转换为字符后,装进字符数组。

那我们再想一下我们的消息ID,固定长度的生成过程 4个字节的ip + 2字节的进程ID + 4字节的hash值 = 10个字节 转换成了 20位的字符,随机字符分别是 4个字节的时间戳差 + short类型即2个字节的计数值 = 6个字节 转换成了 12位的字符。

4  小结

好啦,关于消息ID的我们就看到这里哈,有理解不对的地方欢迎指正哈。

posted @ 2023-07-21 07:20  酷酷-  阅读(457)  评论(0编辑  收藏  举报