一种消息id生成策略

总体设计思路为每5个bit进行一次编码,编码规则为将数字和大写英文的结合,数字中去掉同意混淆的0和1,英文字母中去掉容易混淆的I和O。这样就不会出现类似于1I0O这种的字符串。

我们一共采用60个bit,每20个bit组成一组,每组之间用-来表示。(例如:T4VS-CSA3-2223)。

f59a300f531143088599cad9ee44c67f.png

详细说明

41bit值即为获取当前时间戳(java  中 System.currentTimeMillis(),js:new Date().getTime()),将其转换为二进制位41位,(例如2024年8月20日17点37分大约为11001000101101111001001011011010010100101)其为精确到毫秒。 考虑到在大型的IM系统中可能存在统一毫秒可能生成多条消息id的情况,故低位采用的为14bit的自旋id,共16383个。

最后5bit为消息类型,包括单聊、群聊等。

 

具体代码试下逻辑如下:

import java.util.concurrent.atomic.AtomicInteger;

public class FingerprintV2 {
    private static final char[] Bits = {
            '2', '3', '4', '5', '6', '7', '8','9', 'A', 'B', 'C', 'D', 'E',
            'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S',
            'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
    };


    private static final int SPIN_ID_LIMIT = 0x3FFF;

    private final static AtomicInteger INCR = new AtomicInteger(0); // 递增值


    public static String createFinger(int talkType) {
        String s = getHighChar() + getSpinStr() + getTypeStr(talkType);
        return encodeBitsToChars(s);
    }

     //自旋id

    private static int createSpinId() {
        int ret = INCR.getAndIncrement();
        if(INCR.get() >= SPIN_ID_LIMIT) {
            INCR.set(0);
        }
        return ret;
    }

    /**
     * 获取高位字符
     * @return
     */
    public static String getHighChar() {
        long currentTimeMillis = System.currentTimeMillis();
        System.out.println(Long.toBinaryString(currentTimeMillis));
        return Long.toBinaryString(currentTimeMillis);
    }

    /**
     * 获取自旋字符
     * @return
     */
    public static String getSpinStr() {
        int spinId = createSpinId();
        String s = Integer.toBinaryString(spinId);
         return String.format("%14s", s.replaceAll(" ", "")).replace(' ', '0');

    }

  /**
     * 获取会话类型
     * @param type
     * @return
     */
    public static String getTypeStr(int type) {
        String s = Integer.toBinaryString(type);
        return String.format("%5s", s.replaceAll(" ", "")).replace(' ', '0');
    }




    //将二进制字符编码
    public static String encodeBitsToChars(String bitString) {
        int length = bitString.length();
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < bitString.length(); i+=5) {
            int end = Math.min(i + 5, length);
            String substring = bitString.substring(i, end);
            int decimalValue = Integer.parseInt(substring, 2);
            char bit = Bits[decimalValue];
            stringBuilder.append(bit);
      }
        String string = stringBuilder.toString();

        return splitAndJoin(string, 4, '-');
    }

    //字符串拼接

    public static String splitAndJoin(String input, int chunkSize, char separator) {
        StringBuilder output = new StringBuilder();
        int length = input.length();
        if (length == 0) {
            return "";
        }
        for (int i = 0; i < length; i += chunkSize) {
            int end = Math.min(i + chunkSize, length);
            String substring = input.substring(i, end);
            if (output.length() > 0) {
                output.append(separator);
       }
            output.append(substring);
        }
        return output.toString();
    }





循环执行1万此:

    public static void main(String[] args) {
        Set<String> set = new HashSet<>();
        for (int i = 0; i < 10000; i++) {
            String finger = createFinger(1);
            System.out.println(finger);
            set.add(finger);
 }
        System.out.println(set.size());

    }

c71fcb490a234d148f956258936867ff.png

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值