tx-lcn icon indicating copy to clipboard operation
tx-lcn copied to clipboard

6.0 唯一主键生成策略

Open xlorne opened this issue 4 years ago • 10 comments

框架中有两个地方需要创建唯一主键。 分别是:事务组 GroupId值的创建 与 事务日志中id的主键策略。数据类型 groupId:string id:long

groupid格式未必一定是string,也可以修改成lang类型。但是要保证全局环境中的唯一性

xlorne avatar Jul 03 '20 01:07 xlorne

目前生成的策略是啥。 推荐默认使用雪花算法,还可提供接口,有使用者实现

yizhishang avatar Jul 14 '20 14:07 yizhishang

雪花算法可以,但是需要均衡各个节点上的数据

xlorne avatar Jul 23 '20 08:07 xlorne


/**
 * @author lorne
 * @date 2020/8/8
 * @description
 */
public class IdUtils {


    /**
     * 创建GroupId策略
     *
     * @return
     */
    public static String generateGroupId(){
       //todo 
        return UUID.randomUUID().toString();
    }


}

目前是直接使用的UUID.randomUUID().toString();

xlorne avatar Aug 08 '20 14:08 xlorne


/**
 * @author lorne
 * @date 2020/8/8
 * @description
 */
public class IdUtils {


    /**
     * 创建GroupId策略
     *
     * @return
     */
    public static String generateGroupId(){
       //todo 
        return UUID.randomUUID().toString();
    }


}

目前是直接使用的UUID.randomUUID().toString();

我在以下测试中发现使用雪花算法当 workId 相同时 , 会有 30% 可能生成重复的 id ,为了避免这种情况发生可能需要落库或是 使用 redis

 @Test
    public void theSameWorkId() throws InterruptedException {
        final CountDownLatch COUNT_DOWN_LATCH = new CountDownLatch(10);
        Set<Long> idSet = new HashSet<>();
        IntStream.range(0, 10).forEach(i -> {
            new Thread(() -> {
                try {
                    Snowflake snowflake = IdUtils.createSnowflake(1);
                    IntStream.range(0, 1000).forEach(j -> {
                        long id = snowflake.nextId();
                        idSet.add(id);
                    });
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    COUNT_DOWN_LATCH.countDown();
                }
            }).start();
        });
        COUNT_DOWN_LATCH.await();
        System.out.println(idSet.size());
        Assert.isTrue(10000 == idSet.size(), "size must the same");
    }

600849155 avatar Aug 12 '20 02:08 600849155

是要workId不重复就行是吗?

xlorne avatar Aug 12 '20 09:08 xlorne

ObjectId就行了,24位长度也可以接受,天然的分布式id,同时也是趋势增长的,mongo就用这个.

wangcc57 avatar Aug 12 '20 10:08 wangcc57

是要workId不重复就行是吗?

~~经试验,workId 不重复就行了, 假设有2个机子有 tc ,workId 相同的概率 也不过是 1/1024,id相同的概率也不会很大~~

600849155 avatar Aug 12 '20 14:08 600849155

ObjectId就行了,24位长度也可以接受,天然的分布式id,同时也是趋势增长的,mongo就用这个.

试了下,效果还可以,除非极端情况,会有些许误差

  @Test
    public void theSameObjectId() throws InterruptedException {
        final CountDownLatch COUNT_DOWN_LATCH = new CountDownLatch(2);
        Set<String> idSet = new HashSet<>();
        IntStream.range(0, 2).forEach(i -> {
            new Thread(() -> {
                try {
                    IntStream.range(0, 10000).forEach(j -> {
                        String id = ObjectId.next();
                        idSet.add(id);
                    });
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    COUNT_DOWN_LATCH.countDown();
                }
            }).start();
        });
        COUNT_DOWN_LATCH.await();
        System.out.println(idSet.size());//19969
        Assert.isTrue(20000 == idSet.size(), "size must the same");
    }

600849155 avatar Aug 12 '20 15:08 600849155

那可以这样来设计 当tc链接到tm以后,由tm来分给workid,workid的自增策略由tm来控制,为了实现全局数据统一可讲workid值记录在tm的redis下。

xlorne avatar Aug 13 '20 01:08 xlorne

那可以这样来设计 当tc链接到tm以后,由tm来分给workid,workid的自增策略由tm来控制,为了实现全局数据统一可讲workid值记录在tm的redis下。

正有此意,虽然做法稍微比 ObjectId 的方式复杂些

600849155 avatar Aug 13 '20 15:08 600849155