国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
Redis在集群環(huán)境中生成唯一ID

概述

設計目標:每秒最大生成10萬個ID,ID單調(diào)遞增且唯一。Reidis可以不需要持久化ID。
要求:集群時鐘不能倒退。
總體思路:集群中每個節(jié)點預生成生成ID;然后與redis的已經(jīng)存在的ID做比較。如果大于,則取節(jié)點生成的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 * <p/> * 生成規(guī)則: * 業(yè)務類型 + redis中最大的序列號 * <p/> * 約定: * redis中最大的序列號長度為17,包括{6位日期 + 6位時間 + 3位毫秒數(shù) + 2位隨機} * <p/> * 建議: * 為了容錯和服務降級, SeqGenerator生成失敗時最好采用UUID替換 * <p/> * 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:22local 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浮點數(shù)類型,會出現(xiàn)不精確情況。            注意: 類似"16081817202494579"數(shù)字大小已經(jīng)快超時lua和reids最大數(shù)值,請謹慎的增加seq的位數(shù)        --]]            redis.call(\'incrby\', key, incr_amoutt)            return redis.call(\'get\', key)        end    endendreturn 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<String> 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<String> seqSet;        private final SeqGenerator seqGenerator;        public Worker(SeqGenerator seqGenerator, Set<String> 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
本站僅提供存儲服務,所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
redis隊列及多線程應用
秒殺系統(tǒng)設計架構(gòu)與實現(xiàn)
Spring Boot 使用 AOP 防止重復提交
利用redis + lua解決搶紅包高并發(fā)的問題
Redis學習筆記1--入門篇 (轉(zhuǎn))
項目實戰(zhàn)
更多類似文章 >>
生活服務
分享 收藏 導長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服