日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

java redis 生成唯一id_Redis在集群环境中生成唯一ID

發布時間:2023/12/10 数据库 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java redis 生成唯一id_Redis在集群环境中生成唯一ID 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

概述

設計目標:每秒最大生成10萬個ID,ID單調遞增且唯一。Reidis可以不需要持久化ID。

要求:集群時鐘不能倒退。

總體思路:集群中每個節點預生成生成ID;然后與redis的已經存在的ID做比較。如果大于,則取節點生成的ID;小于的話,取Redis中最大ID自增。

Java代碼

import org.apache.commons.lang3.RandomStringUtils;

import org.apache.commons.lang3.StringUtils;

import org.apache.commons.lang3.time.FastDateFormat;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import java.io.IOException;

import java.nio.file.Files;

import java.nio.file.Path;

import java.nio.file.Paths;

import static com.google.common.base.Preconditions.checkArgument;

/**

* 生成遞增的唯一序列號, 可以用來生成訂單號,例如216081817202494579

*

* 生成規則:

* 業務類型 + redis中最大的序列號

*

* 約定:

* redis中最大的序列號長度為17,包括{6位日期 + 6位時間 + 3位毫秒數 + 2位隨機}

*

* 建議:

* 為了容錯和服務降級, SeqGenerator生成失敗時最好采用UUID替換

*

* Created by juemingzi on 16/8/19.

*/

public class SeqGenerator {

private static final Logger logger = LoggerFactory.getLogger(SeqGenerator.class);

private static final Path filePath = Paths.get(Thread.currentThread().getContextClassLoader().getResource("lua/get_next_seq.lua").getPath());

//線程安全

private static final FastDateFormat seqDateFormat = FastDateFormat.getInstance("yyMMddHHmmssSSS");

private static final RedisExtraService redisExtraService = SpringContext.getBean(RedisExtraService.class);

private final byte[] keyName;

private final byte[] incrby;

private byte[] sha1;

public SeqGenerator(String keyName) throws IOException {

this(keyName, 1);

}

/**

* @param keyName

* @param incrby

*/

public SeqGenerator(String keyName, int incrby) throws IOException {

checkArgument(keyName != null && incrby > 0);

this.keyName = keyName.getBytes();

this.incrby = Integer.toString(incrby).getBytes();

init();

}

private void init() throws IOException {

byte[] script;

try {

script = Files.readAllBytes(filePath);

} catch (IOException e) {

logger.error("讀取文件出錯, path: {}", filePath);

throw e;

}

sha1 = redisExtraService.scriptLoad(script);

}

public String getNextSeq(String bizType) {

checkArgument(StringUtils.isNotBlank(bizType));

return bizType + getMaxSeq();

}

private String generateSeq() {

String seqDate = seqDateFormat.format(System.currentTimeMillis());

String candidateSeq = new StringBuilder(17).append(seqDate).append(RandomStringUtils.randomNumeric(2)).toString();

return candidateSeq;

}

/**

* 通過redis生成17位的序列號,lua腳本保證序列號的唯一性

*

* @return

*/

public String getMaxSeq() {

String maxSeq = new String((byte[]) redisExtraService.evalsha(sha1, 3, keyName, incrby, generateSeq().getBytes()));

return maxSeq;

}

}1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

lua腳本

--

-- 獲取最大的序列號,樣例為16081817202494579

--

-- Created by IntelliJ IDEA.

-- User: juemingzi

-- Date: 16/8/18

-- Time: 17:22

local function get_max_seq()

local key = tostring(KEYS[1])

local incr_amoutt = tonumber(KEYS[2])

local seq = tostring(KEYS[3])

local month_in_seconds = 24 * 60 * 60 * 30

if (1 == redis.call(\'setnx\', key, seq))

then

redis.call(\'expire\', key, month_in_seconds)

return seq

else

local prev_seq = redis.call(\'get\', key)

if (prev_seq < seq)

then

redis.call(\'set\', key, seq)

return seq

else

--[[

不能直接返回redis.call(\'incr\', key),因為返回的是number浮點數類型,會出現不精確情況。

注意: 類似"16081817202494579"數字大小已經快超時lua和reids最大數值,請謹慎的增加seq的位數

--]]

redis.call(\'incrby\', key, incr_amoutt)

return redis.call(\'get\', key)

end

end

end

return get_max_seq()1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

測試代碼

public class SeqGeneratorTest extends BaseTest {

@Test

public void testGetNextSeq() throws Exception {

final SeqGenerator seqGenerater = new SeqGenerator("orderId");

String orderId = seqGenerater.getNextSeq(Integer.toString(WaitingOrder.KIND_TAKE_OUT));

assertNotNull(orderId);

System.out.println("orderId is: " + orderId);

}

@Test

public void testGetNextSeqWithMultiThread() throws Exception {

int cpus = Runtime.getRuntime().availableProcessors();

CountDownLatch begin = new CountDownLatch(1);

CountDownLatch end = new CountDownLatch(cpus);

final Set seqSet = new ConcurrentSkipListSet<>();

ExecutorService executorService = Executors.newFixedThreadPool(cpus);

final SeqGenerator seqGenerater = new SeqGenerator("orderId");

for (int i = 0; i < cpus; i++) {

executorService.execute(new Worker(seqGenerater, seqSet, begin, end));

}

begin.countDown();

end.await();

assertEquals(seqSet.size(), cpus * 10000);

System.out.println("finish!");

}

private static class Worker implements Runnable {

private final CountDownLatch begin;

private final CountDownLatch end;

private final Set seqSet;

private final SeqGenerator seqGenerator;

public Worker(SeqGenerator seqGenerator, Set seqSet, CountDownLatch begin, CountDownLatch end) {

this.seqGenerator = seqGenerator;

this.seqSet = seqSet;

this.begin = begin;

this.end = end;

}

@Override

public void run() {

try {

begin.await();

for (int i = 0; i < 10000; i++) {

String seq = seqGenerator.getNextSeq("2");

if (!seqSet.add(seq)) {

System.out.println(seq);

fail();

}

}

System.out.println("end");

} catch (Exception e) {

e.printStackTrace();

} finally {

end.countDown();

}

}

}

}1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

總結

以上是生活随笔為你收集整理的java redis 生成唯一id_Redis在集群环境中生成唯一ID的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。