最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

redis分布式ID解決方案示例詳解

 更新時(shí)間:2023年03月07日 15:02:55   作者:德哥很ok  
這篇文章主要為大家介紹了redis分布式ID解決方案示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

常用的分布式ID解決方案

在分布式系統(tǒng)中,生成全局唯一ID是非常重要的,因?yàn)樵诜植际较到y(tǒng)中,多個(gè)節(jié)點(diǎn)同時(shí)生成ID可能會(huì)導(dǎo)致ID沖突。

下面介紹幾種常用的分布式ID解決方案。

UUID

UUID(通用唯一標(biāo)識(shí)符)是由128位數(shù)字組成的標(biāo)識(shí)符,它可以保證在全球范圍內(nèi)的唯一性,因?yàn)槠渖伤惴ɑ跁r(shí)間戳、節(jié)點(diǎn)ID等因素。UUID可以使用Java自帶的UUID類來(lái)生成,如下所示:

javaCopy code
import java.util.UUID;
public class UuidGenerator {
    public static void main(String[] args) {
        UUID uuid = UUID.randomUUID();
        System.out.println(uuid.toString());
    }
}

UUID的優(yōu)點(diǎn)是簡(jiǎn)單易用,無(wú)需額外的配置和管理,可以直接使用Java自帶的UUID類生成。但是UUID長(zhǎng)度較長(zhǎng)(128位),不太適合作為數(shù)據(jù)庫(kù)表的主鍵,且不易于排序和索引。

Snowflake

Snowflake是Twitter開(kāi)源的一種分布式ID生成算法,它可以生成64位的唯一ID,其中包含了時(shí)間戳、數(shù)據(jù)中心ID和機(jī)器ID等信息。Snowflake算法的Java代碼如下所示:

Snowflake算法的Java代碼:

javaCopy code
public class SnowflakeGenerator {
    private final static long START_STMP = 1480166465631L;
    private final static long SEQUENCE_BIT = 12;
    private final static long MACHINE_BIT = 5;
    private final static long DATACENTER_BIT = 5;
    private final static long MAX_DATACENTER_NUM = -1L ^ (-1L << DATACENTER_BIT);
    private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT);
    private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);
    private final static long MACHINE_LEFT = SEQUENCE_BIT;
    private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;
    private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT;
    private long datacenterId;
    private long machineId;
    private long sequence = 0L;
    private long lastStmp = -1L;
    public SnowflakeGenerator(long datacenterId, long machineId) {
        if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) {
            throw new IllegalArgumentException("datacenterId can't be greater than MAX_DATACENTER_NUM or less than 0");
        }
        if (machineId > MAX_MACHINE_NUM || machineId < 0) {
            throw new IllegalArgumentException("machineId can't be greater than MAX_MACHINE_NUM or less than 0");
        }
        this.datacenterId = datacenterId;
        this.machineId = machineId;
    }
    public synchronized long nextId() {
        long currStmp = getNewstmp();
        if (currStmp < lastStmp) {
            throw new RuntimeException("Clock moved backwards.  Refusing to generate id");
        }
        if (currStmp == lastStmp) {
            sequence = (sequence + 1) & MAX_SEQUENCE;
            if (sequence == 0L) {
                currStmp = getNextMill();
            }
        } else {
            sequence = 0L;
        }
        lastStmp = currStmp;
        return (currStmp - START_STMP) << TIMESTMP_LEFT
                | datacenterId << DATACENTER_LEFT
                | machineId << MACHINE_LEFT
                | sequence;
    }
    private long getNextMill() {
        long mill = getNewstmp();
        while (mill <= lastStmp) {
            mill = getNewstmp();
        }
        return mill;
    }
    private long getNewstmp() {
        return System.currentTimeMillis();
    }
}

Snowflake算法的優(yōu)點(diǎn)是生成ID的性能高,且ID長(zhǎng)度較短(64位),可以作為數(shù)據(jù)庫(kù)表的主鍵,且便于排序和索引。但是需要注意,如果集群中的節(jié)點(diǎn)數(shù)超過(guò)了機(jī)器ID所占的位數(shù),或者集群規(guī)模很大,時(shí)間戳位數(shù)不夠用,那么就需要考慮其他的分布式ID生成算法。

Leaf

Leaf是美團(tuán)點(diǎn)評(píng)開(kāi)源的一種分布式ID生成算法,它可以生成全局唯一的64位ID。Leaf算法的Java代碼如下所示:

Leaf算法的Java代碼:

javaCopy code
public class LeafGenerator {
    private static final Logger logger = LoggerFactory.getLogger(LeafGenerator.class);
    private static final String WORKER_ID_KEY = "leaf.worker.id";
    private static final String PORT_KEY = "leaf.port";
    private static final int DEFAULT_PORT = 8080;
    private static final int DEFAULT_WORKER_ID = 0;
    private static final int WORKER_ID_BITS = 10;
    private static final int SEQUENCE_BITS = 12;
    private static final int MAX_WORKER_ID = (1 << WORKER_ID_BITS) - 1;
    private static final int MAX_SEQUENCE = (1 << SEQUENCE_BITS) - 1;
    private static final long EPOCH = 1514736000000L;
    private final SnowflakeIdWorker idWorker;
    public LeafGenerator() {
        int workerId = SystemPropertyUtil.getInt(WORKER_ID_KEY, DEFAULT_WORKER_ID);
        int port = SystemPropertyUtil.getInt(PORT_KEY, DEFAULT_PORT);
        this.idWorker = new SnowflakeIdWorker(workerId, port);
        logger.info("Initialized LeafGenerator with workerId={}, port={}", workerId, port);
    }
    public long nextId() {
        return idWorker.nextId();
    }
    private static class SnowflakeIdWorker {
        private final long workerId;
        private final long port;
        private long sequence = 0L;
        private long lastTimestamp = -1L;
        SnowflakeIdWorker(long workerId, long port) {
            if (workerId < 0 || workerId > MAX_WORKER_ID) {
                throw new IllegalArgumentException(String.format("workerId must be between %d and %d", 0, MAX_WORKER_ID));
            }
            this.workerId = workerId;
            this.port = port;
        }
        synchronized long nextId() {
            long timestamp = System.currentTimeMillis();
            if (timestamp < lastTimestamp) {
                throw new RuntimeException("Clock moved backwards. Refusing to generate id");
            }
            if (timestamp == lastTimestamp) {
                sequence = (sequence + 1) & MAX_SEQUENCE;
                if (sequence == 0L) {
                    timestamp = tilNextMillis(lastTimestamp);
                }
            } else {
                sequence = 0L;
            }
            lastTimestamp = timestamp;
            return ((timestamp - EPOCH) << (WORKER_ID_BITS + SEQUENCE_BITS))
                    | (workerId << SEQUENCE_BITS)
                    | sequence;
        }
        private long tilNextMillis(long lastTimestamp) {
            long timestamp = System.currentTimeMillis();
            while (timestamp <= lastTimestamp) {
                timestamp = System.currentTimeMillis();
            }
            return timestamp;
        }
    }
}

Leaf算法的特點(diǎn)是生成ID的速度比Snowflake算法略慢,但是可以支持更多的Worker節(jié)點(diǎn)。Leaf算法生成的ID由三部分組成,分別是時(shí)間戳、Worker ID和序列號(hào),其中時(shí)間戳占用42位、Worker ID占用10位、序列號(hào)占用12位,總共64位。

以上是常見(jiàn)的分布式ID生成算法,當(dāng)然還有其他的一些方案,如:MongoDB ID、UUID、Twitter Snowflake等。不同的方案適用于不同的業(yè)務(wù)場(chǎng)景,具體實(shí)現(xiàn)細(xì)節(jié)和性能表現(xiàn)也有所不同,需要根據(jù)實(shí)際情況選擇合適的方案。

除了上述介紹的分布式ID生成算法,還有一些新的分布式ID生成方案不斷涌現(xiàn),例如Flicker的分布式ID生成算法,它使用了類似于Snowflake的思想,但是采用了不同的位數(shù)分配方式,相比Snowflake更加靈活,并且可以根據(jù)需要?jiǎng)討B(tài)調(diào)整每個(gè)部分占用的位數(shù)。此外,F(xiàn)acebook還推出了ID Generation Service (IGS)方案,該方案將ID的生成和存儲(chǔ)分離,提供了更加靈活和可擴(kuò)展的方案,但是需要進(jìn)行更加復(fù)雜的架構(gòu)設(shè)計(jì)和實(shí)現(xiàn)。

針對(duì)不同的業(yè)務(wù)需求,可以設(shè)計(jì)多套分布式ID生成方案。下面是我個(gè)人的一些建議:

  • 基于數(shù)據(jù)庫(kù)自增ID生成:使用數(shù)據(jù)庫(kù)自增ID作為全局唯一ID,可以很好的保證ID的唯一性,并且實(shí)現(xiàn)簡(jiǎn)單,但是并發(fā)量較高時(shí)可能會(huì)導(dǎo)致性能瓶頸。因此,在高并發(fā)場(chǎng)景下不建議使用。
  • 基于UUID生成:使用UUID作為全局唯一ID,可以很好地保證ID的唯一性,但是ID長(zhǎng)度較長(zhǎng)(128位),不便于存儲(chǔ)和傳輸,并且存在重復(fù)ID的概率非常小但不為0。因此,建議在分布式系統(tǒng)中使用時(shí)要考慮ID的長(zhǎng)度和存儲(chǔ)傳輸?shù)某杀尽?/li>
  • 基于Redis生成:使用Redis的原子性操作,可以保證ID的唯一性,并且生成ID的速度非常快,可以適用于高并發(fā)場(chǎng)景。但是需要注意,如果Redis宕機(jī)或者性能不足,可能會(huì)影響ID的生成效率和可用性。
  • 基于ZooKeeper生成:使用ZooKeeper的序列號(hào)生成器,可以保證ID的唯一性,并且實(shí)現(xiàn)較為簡(jiǎn)單,但是需要引入額外的依賴和資源,并且可能會(huì)存在性能瓶頸。

選擇適合自己業(yè)務(wù)場(chǎng)景的分布式ID生成方案,需要綜合考慮ID的唯一性、生成速度、長(zhǎng)度、存儲(chǔ)成本、可擴(kuò)展性、可用性等多個(gè)因素。同時(shí)需要注意,不同方案的實(shí)現(xiàn)細(xì)節(jié)和性能表現(xiàn)也有所不同,需要根據(jù)實(shí)際情況進(jìn)行權(quán)衡和選擇。

下面給出每種方案的詳細(xì)代碼demo:

基于數(shù)據(jù)庫(kù)自增ID生成

javaCopy code
public class IdGenerator {
    private static final String JDBC_URL = "jdbc:mysql://localhost:3306/test";
    private static final String JDBC_USER = "root";
    private static final String JDBC_PASSWORD = "password";
    public long generateId() {
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            conn = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD);
            pstmt = conn.prepareStatement("INSERT INTO id_generator (stub) VALUES (null)", Statement.RETURN_GENERATED_KEYS);
            pstmt.executeUpdate();
            rs = pstmt.getGeneratedKeys();
            if (rs.next()) {
                return rs.getLong(1);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (rs != null) {
                    rs.close();
                }
                if (pstmt != null) {
                    pstmt.close();
                }
                if (conn != null) {
                    conn.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return 0L;
    }
}

基于UUID生成

javaCopy code
import java.util.UUID;
public class IdGenerator {
    public String generateId() {
        return UUID.randomUUID().toString().replace("-", "");
    }
}

基于Redis生成

javaCopy code
import redis.clients.jedis.Jedis;
public class IdGenerator {
    private static final String REDIS_HOST = "localhost";
    private static final int REDIS_PORT = 6379;
    private static final String REDIS_PASSWORD = "password";
    private static final int ID_GENERATOR_EXPIRE_SECONDS = 3600;
    private static final String ID_GENERATOR_KEY = "id_generator";
    public long generateId() {
        Jedis jedis = null;
        try {
            jedis = new Jedis(REDIS_HOST, REDIS_PORT);
            jedis.auth(REDIS_PASSWORD);
            long id = jedis.incr(ID_GENERATOR_KEY);
            jedis.expire(ID_GENERATOR_KEY, ID_GENERATOR_EXPIRE_SECONDS);
            return id;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return 0L;
    }
}

基于ZooKeeper生成

javaCopy code
import java.util.concurrent.CountDownLatch;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
public class IdGenerator implements Watcher {
    private static final String ZK_HOST = "localhost";
    private static final int ZK_PORT = 2181;
    private static final int SESSION_TIMEOUT = 5000;
    private static final String ID_GENERATOR_NODE = "/id_generator";
    private static final int ID_GENERATOR_EXPIRE_SECONDS = 3600;
    private long workerId = 0;
    public IdGenerator() {
        try {
            ZooKeeper zk = new ZooKeeper(ZK_HOST + ":" + ZK_PORT, SESSION_TIMEOUT, this);
            CountDownLatch latch = new CountDownLatch(1);
            latch.await();
            if (zk.exists(ID_GENERATOR_NODE, false) == null) {
                zk.create(ID_GENERATOR_NODE, null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            }
            workerId = zk.getChildren(ID_GENERATOR_NODE, false).size();
            zk.create(ID_GENERATOR_NODE + "/worker_" + workerId, null, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public long generateId() {
        ZooKeeper zk = null;
        try {
            zk = new ZooKeeper(ZK_HOST + ":" + ZK_PORT, SESSION_TIMEOUT, null);
            CountDownLatch latch = new CountDownLatch(1);
            latch.await();
            zk.create(ID_GENERATOR_NODE + "/id_", null, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL, (rc, path, ctx, name) -> {}, null);
            byte[] data = zk.getData(ID_GENERATOR_NODE + "/worker_" + workerId, false, null);
            long id = Long.parseLong(new String(data)) * 10000 + zk.getChildren(ID_GENERATOR_NODE, false).size();
            return id;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (zk != null) {
                try {
                    zk.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return 0L;
    }
    @Override
    public void process(WatchedEvent event) {
        if (event.getState() == Event.KeeperState.SyncConnected) {
            System.out.println("Connected to ZooKeeper");
            CountDownLatch latch = new CountDownLatch(1);
            latch.countDown();
        }
    }
}

注意,這里使用了ZooKeeper的臨時(shí)節(jié)點(diǎn)來(lái)協(xié)調(diào)各個(gè)工作節(jié)點(diǎn),如果一個(gè)工作節(jié)點(diǎn)掛掉了,它的臨時(shí)節(jié)點(diǎn)也會(huì)被刪除,這樣可以保證每個(gè)工作節(jié)點(diǎn)獲得的ID是唯一的。

以上就是各種分布式ID生成方案的詳細(xì)代碼demo,實(shí)際上,每種方案都有其優(yōu)缺點(diǎn),應(yīng)根據(jù)具體業(yè)務(wù)場(chǎng)景和系統(tǒng)架構(gòu)選擇合適的方案。

以上就是redis分布式ID解決方案示例詳解的詳細(xì)內(nèi)容,更多關(guān)于redis分布式ID的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Redis如何實(shí)現(xiàn)投票功能

    Redis如何實(shí)現(xiàn)投票功能

    這篇文章主要介紹了Redis如何實(shí)現(xiàn)投票功能,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • 詳解Redis開(kāi)啟遠(yuǎn)程登錄連接

    詳解Redis開(kāi)啟遠(yuǎn)程登錄連接

    本篇文章主要介紹了Redis開(kāi)啟遠(yuǎn)程登錄連接,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-05-05
  • Redis安全策略詳解

    Redis安全策略詳解

    緩存穿透是指當(dāng)用戶在查詢一條數(shù)據(jù)的時(shí)候,而此時(shí)數(shù)據(jù)庫(kù)和緩存卻沒(méi)有關(guān)于這條數(shù)據(jù)的任何記錄,而這條數(shù)據(jù)在緩存中沒(méi)找到就會(huì)向數(shù)據(jù)庫(kù)請(qǐng)求獲取數(shù)據(jù)。用戶拿不到數(shù)據(jù)時(shí),就會(huì)一直發(fā)請(qǐng)求,查詢數(shù)據(jù)庫(kù),這樣會(huì)對(duì)數(shù)據(jù)庫(kù)的訪問(wèn)造成很大的壓力
    2022-07-07
  • Redis特殊數(shù)據(jù)類型HyperLogLog基數(shù)統(tǒng)計(jì)算法講解

    Redis特殊數(shù)據(jù)類型HyperLogLog基數(shù)統(tǒng)計(jì)算法講解

    這篇文章主要為大家介紹了Redis特殊數(shù)據(jù)類型HyperLogLog基數(shù)統(tǒng)計(jì)算法講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05
  • Redis分布式鎖一定要避開(kāi)的兩個(gè)坑

    Redis分布式鎖一定要避開(kāi)的兩個(gè)坑

    這篇文章主要為大家詳細(xì)介紹了Redis中分布式鎖一定要避開(kāi)的兩個(gè)坑以及對(duì)應(yīng)的解決方法,文中的示例代碼講解詳細(xì),希望對(duì)大家有所幫助
    2023-04-04
  • 爬蟲(chóng)技術(shù)之分布式爬蟲(chóng)架構(gòu)的講解

    爬蟲(chóng)技術(shù)之分布式爬蟲(chóng)架構(gòu)的講解

    今天小編就為大家分享一篇關(guān)于爬蟲(chóng)技術(shù)之分布式爬蟲(chóng)架構(gòu)的講解,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-01-01
  • Redis常見(jiàn)限流算法原理及實(shí)現(xiàn)

    Redis常見(jiàn)限流算法原理及實(shí)現(xiàn)

    這篇文章主要介紹了Redis常見(jiàn)限流算法原理及實(shí)現(xiàn),限流簡(jiǎn)稱流量限速(Rate?Limit)是指只允許指定的事件進(jìn)入系統(tǒng),超過(guò)的部分將被拒絕服務(wù)、排隊(duì)或等待、降級(jí)等處理
    2022-08-08
  • Redis搜索日期范圍內(nèi)的查詢示例

    Redis搜索日期范圍內(nèi)的查詢示例

    Redis作為內(nèi)存數(shù)據(jù)結(jié)構(gòu)存儲(chǔ)系統(tǒng),雖未專為日期范圍查詢?cè)O(shè)計(jì),但可通過(guò)存儲(chǔ)日期數(shù)據(jù)、使用KEYS命令或有序集合(SortedSet)實(shí)現(xiàn)查詢功能,下面就來(lái)介紹一下
    2024-09-09
  • redis啟動(dòng)報(bào)錯(cuò)Can‘t?open?the?log?file:?No?such?file?or?directory

    redis啟動(dòng)報(bào)錯(cuò)Can‘t?open?the?log?file:?No?such?file?or?d

    這篇文章主要介紹了redis啟動(dòng)報(bào)錯(cuò)Can‘t?open?the?log?file:?No?such?file?or?directory問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • Redis實(shí)現(xiàn)排名功能的示例代碼

    Redis實(shí)現(xiàn)排名功能的示例代碼

    本文主要介紹了Redis實(shí)現(xiàn)排名功能的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02

最新評(píng)論

大安市| 隆尧县| 柏乡县| 井陉县| 彰武县| 崇礼县| 连州市| 会宁县| 安多县| 曲阳县| 昭觉县| 武汉市| 桂阳县| 焦作市| 绍兴县| 上饶县| 如东县| 苍梧县| 梁山县| 儋州市| 连南| 绥江县| 无极县| 仙游县| 梓潼县| 防城港市| 鸡东县| 孝昌县| 万州区| 类乌齐县| 阜南县| 郓城县| 普陀区| 寿光市| 庆云县| 舟山市| 阳曲县| 舟曲县| 汽车| 屏东县| 昭通市|