ROCKETMQ消息ID生成逻辑

摘要

消息发送之前,会在客户端创建一个msgId,发送到broker,broker也会创建一个msgId,

  1. 客户端的msgId 包含 本地IP:本地PORT,本地classloader的hashCode
  2. broker返回的msgId 包含 brokerIP:brokerPort,brokerOffset

源码阅读

SendResult [sendStatus=SEND_OK, msgId=0A0158434F3473D16E938F000AEE0000 (本地msgId), offsetMsgId=0A01584300002A9F0000000000125CA7(brokerMsgId), messageQueue=MessageQueue [topic=TOPIC_TEST, brokerName=broker-b, queueId=3], queueOffset=479]

客户端消息创建源码

MessageClientIDSetter.setUniqID(msg);

 public static String createUniqID() {
        StringBuilder sb = new StringBuilder(LEN * 2);//32位
        sb.append(FIX_STRING);// 静态方法,在启动的时候初始化,内容包含 IP:PORT,classloader的hashCode
        sb.append(UtilAll.bytes2string(createUniqIDBuffer()));// 追加了一个时间差值 和子增值
        return sb.toString();
    }

    static {
        LEN = 4 + 2 + 4 + 4 + 2;
        ByteBuffer tempBuffer = ByteBuffer.allocate(10);
        tempBuffer.position(2);
        tempBuffer.putInt(UtilAll.getPid());
        tempBuffer.position(0);
        try {
            tempBuffer.put(UtilAll.getIP());// 获取当前IP:port,转换成16个字符串,之后创建msgId时可以用这个16位作为固定前缀
        } catch (Exception e) {
            tempBuffer.put(createFakeIP());
        }
        tempBuffer.position(6);
        tempBuffer.putInt(MessageClientIDSetter.class.getClassLoader().hashCode());
        FIX_STRING = UtilAll.bytes2string(tempBuffer.array());
        setStartTime(System.currentTimeMillis());
        COUNTER = new AtomicInteger(0);
    }
	
   // 6位,前4位表示时间差值,后面2位表示一个自增值
    private static byte[] createUniqIDBuffer() {
        ByteBuffer buffer = ByteBuffer.allocate(4 + 2);
        long current = System.currentTimeMillis();
        if (current >= nextStartTime) {
            setStartTime(current);
        }
        buffer.position(0);
        buffer.putInt((int) (System.currentTimeMillis() - startTime));
        buffer.putShort((short) COUNTER.getAndIncrement());
        return buffer.array();
    }
	

broker 消息ID创建源码

 // 根据这个创建commitlog的消息id    前面8位是  brokerIP:PORT,后面8位是commitlog的offset,转码成32位
    public static String createMessageId(final ByteBuffer input, final ByteBuffer addr, final long offset) {
        input.flip();
        input.limit(MessageDecoder.MSG_ID_LENGTH);

        input.put(addr);
        input.putLong(offset);

        return UtilAll.bytes2string(input.array());
    }

消息offsetMsgId解码源码

这个port一般是10911

代码入口:

org.apache.rocketmq.common.message.MessageDecoder.decodeMessageId(String)
	/**
	 * 根据消息id反转码得到MessageId对象,MessageId对象包含 SocketAddress(ip:port),消息在索引文件的位置 offset
	 * 0A01584A483873D16E936A9D8D930000
	 * 前8位是 ip,接下来8位是port,最后16位是commitLogOffset
	 */
    public static MessageId decodeMessageId(final String msgId) throws UnknownHostException {
        SocketAddress address;
        long offset;
        //前8位是ip地址
        byte[] ip = UtilAll.string2bytes(msgId.substring(0, 8));
        //接下来8位是端口
        byte[] port = UtilAll.string2bytes(msgId.substring(8, 16));
        ByteBuffer bb = ByteBuffer.wrap(port);
        int portInt = bb.getInt(0);
        address = new InetSocketAddress(InetAddress.getByAddress(ip), portInt);

        // offset 接下来16位是offset
        byte[] data = UtilAll.string2bytes(msgId.substring(16, 32));
        bb = ByteBuffer.wrap(data);
        offset = bb.getLong(0);

        return new MessageId(address, offset);
    }
	
	/**
     * 将8位的字符串转换成4个字节
     * 转换方法:高字节左移,跟 字节 做| 运算
     * 高字节能左移,是因为字节都是16以下的,字节的低4位能表示,字节的高4位是0
     * @param hexString
     * @return
     */
    public static byte[] string2bytes(String hexString) {
        if (hexString == null || hexString.equals("")) {
            return null;
        }
        hexString = hexString.toUpperCase();
        int length = hexString.length() / 2;
        char[] hexChars = hexString.toCharArray();
        byte[] d = new byte[length];
        for (int i = 0; i < length; i++) {
            int pos = i * 2;
            /**
             *  这些字符的必定是 0123456789ABCDEF 这16个数字里面的,最大也就是16位,只需要低4位表示
             *  第i个字符的低四位左移4位,拼接 i+1个字符的低四位,构成一个完整的8位byte,这样就是一个256范围的数字,或 操作就是拼接
             */
            d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
        }
        return d;
    }
	

转载于:https://my.oschina.net/liangxiao/blog/2991232

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值