検索
ホームページデータベースRedisRedis 分散 ID のソリューションは何ですか?

    一般的に使用される分散 ID ソリューション

    分散システムでは、グローバルに一意の ID を生成することが非常に重要です。分散システムでは複数のノードが存在するためです。同時に ID を生成すると、ID の競合が発生する可能性があります。

    次に、一般的に使用される分散 ID ソリューションをいくつか紹介します。

    UUID

    UUID (Universally Unique Identifier) は 128 桁で構成される識別子で、その生成アルゴリズムはタイムスタンプ、ノード ID などの要素に基づいているため、グローバルな一意性を保証できます。 UUID は、以下に示すように、Java 独自の UUID クラスを使用して生成できます:

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

    Java 独自の UUID クラスによって生成された UUID は非常にシンプルで使いやすく、追加の構成や管理を必要としません。 。 UUID はその長さ (128 ビット) のため、データベース テーブルの主キーとしては適しておらず、並べ替えやインデックス付けが困難です。

    Snowflake

    Snowflake は、Twitter がオープンソース化した分散 ID 生成アルゴリズムで、タイムスタンプ、データセンター ID、マシン ID などの情報を含む 64 ビットの一意の 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&#39;t be greater than MAX_DATACENTER_NUM or less than 0");
            }
            if (machineId > MAX_MACHINE_NUM || machineId < 0) {
                throw new IllegalArgumentException("machineId can&#39;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 アルゴリズムの利点は、ID 生成のパフォーマンスが高く、ID の長さが短いことです (64 bits) をデータベース テーブルの主キーとして使用すると、並べ替えとインデックス付けが容易になります。ただし、クラスター内のノードの数がマシン ID が占める桁数を超える場合、またはクラスターが非常に大きくタイムスタンプの桁数が十分でない場合は、他の分散 ID 生成アルゴリズムを使用する必要があることに注意してください。考慮されます。

    Leaf

    Leaf は、Meituan Dianping によってオープンソース化された分散 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 アルゴリズムは、Snowflake アルゴリズムよりも ID の生成がわずかに遅くなりますが、より多くのワーカーをサポートできます。ノード 。 Leaf アルゴリズムで生成される ID は、タイムスタンプ、ワーカー ID、シーケンス番号の 3 つの部分で構成され、タイムスタンプが 42 ビット、ワーカー ID が 10 ビット、シーケンス番号が 12 ビットの合計 64 ビットを占めます。

    上記は一般的な分散 ID 生成アルゴリズムですが、もちろん、MongoDB ID、UUID、Twitter Snowflake など、他のソリューションもあります。ビジネスシーンに応じて適したソリューションが異なり、具体的な実装内容やパフォーマンスも異なるため、実際の状況に応じて適切なソリューションを選択する必要があります。

    上記で紹介した分散 ID 生成アルゴリズムに加えて、Flicker の分散 ID 生成アルゴリズムなど、新しい分散 ID 生成ソリューションもいくつか登場しています。これは、Snowflake と同様のアイデアを使用しますが、異なるビット割り当て方法を採用しています。 Snowflake よりも柔軟性があり、各部分が占めるビット数は必要に応じて動的に調整できます。さらに、Facebook は ID 生成サービス (IGS) ソリューションも開始しました。これは ID の生成と保存を分離し、より柔軟でスケーラブルなソリューションを提供しますが、より複雑なアーキテクチャの設計と実装が必要になります。

    さまざまなビジネス ニーズに応じて、複数セットの分散 ID 生成ソリューションを設計できます。私の個人的な提案をいくつか紹介します。

    • データベース自動インクリメント ID に基づいて生成する: データベース自動インクリメント ID をグローバルに一意な ID として使用すると、ID の一意性が確保され、簡単になります。ただし、同時実行性が高いとパフォーマンスのボトルネックが発生する可能性があります。したがって、同時実行性の高いシナリオで使用することはお勧めできません。

    • UUID に基づいて生成: グローバルに一意な ID として UUID を使用すると、ID の一意性を確保できますが、ID の長さが長く (128 ビット)、保管や保存に不便です。 ID が重複する可能性は非常に低いですが、0 ではありません。分散システムを使用する場合は、ID の長さと、保存および送信のコストを考慮する必要があることが推奨されます。

    • Redis に基づく生成: Redis のアトミック操作を使用すると、ID の一意性が保証され、ID 生成速度が非常に高速になるため、同時実行性の高いシナリオに適用できます。 Redis がクラッシュしたり、パフォーマンスが低下したりすると、ID 生成の効率と可用性に影響が出る可能性があることに注意してください。

    • ZooKeeper に基づく生成: ZooKeeper のシリアル番号ジェネレーターを使用すると、ID の一意性を確保でき、実装は比較的簡単ですが、追加の依存関係とリソースの導入が必要です。パフォーマンスの問題がボトルネックになっている可能性があります。

    ビジネス シナリオに合った分散 ID 生成ソリューションを選択するには、ID の一意性、生成速度、長さ、ストレージ コスト、拡張性、可用性などの複数の要素を総合的に考慮する必要があります。異なるソリューションを実装するには、実装の詳細やパフォーマンスも異なるため、実際の状況でのトレードオフと選択を考慮する必要があります。

    各ソリューションの詳細なコード デモを以下に示します。

    データベース自動インクリメント 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("-", "");
        }
    }

    Generate 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 の一時ノードは、各作業ノードを調整するためにここで使用されることに注意してください。作業ノードがハングアップすると、その一時ノードも削除されます。各ワーカー ノードによって取得される ID が固有であることを確認します。

    以上がRedis 分散 ID のソリューションは何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    声明
    この記事は亿速云で複製されています。侵害がある場合は、admin@php.cn までご連絡ください。
    Redis vsデータベース:パフォーマンスの比較Redis vsデータベース:パフォーマンスの比較May 14, 2025 am 12:11 AM

    PerformStraditionaldatabasesinspeedforread/writeoperationsduetoitsinmemorynature、whieldatitionaldatabasesesexcelincomplearsanddataintegrity.1)Redisidealforreal-timeanalyticsandcaching、offeringphenomenalporfance.2)伝統的なダタベース

    従来のデータベースの代わりにRedisをいつ使用する必要がありますか?従来のデータベースの代わりにRedisをいつ使用する必要がありますか?May 13, 2025 pm 04:01 PM

    useredisinsteadofatraditationaldatabase whenyourapplicationreassandreal-timedataprocessing、suteasforcaching、sessionmanagement、orreal-timeanalytics.redisexcelsin:1)キャッシング、削減loadonprimarydatabases;

    Redis:SQLを超えて-NOSQLの視点Redis:SQLを超えて-NOSQLの視点May 08, 2025 am 12:25 AM

    Redisは、高性能と柔軟性のためにSQLデータベースを超えています。 1)Redisは、メモリストレージを介して非常に速い読み取りおよび書き込み速度を実現します。 2)複雑なデータ処理に適したリストやコレクションなど、さまざまなデータ構造をサポートしています。 3)シングルスレッドモデルは開発を簡素化しますが、高い並行性はボトルネックになる可能性があります。

    Redis:従来のデータベースサーバーとの比較Redis:従来のデータベースサーバーとの比較May 07, 2025 am 12:09 AM

    Redisは、並行性が高く、遅延の低いシナリオの従来のデータベースよりも優れていますが、複雑なクエリやトランザクション処理には適していません。 1.Redisは、メモリストレージ、高速読み取り速度、および高い並行性と低遅延の要件に適しています。 2.従来のデータベースは、ディスクに基づいており、複雑なクエリとトランザクション処理をサポートし、データの一貫性と永続性が強い。 3. Redisは、従来のデータベースのサプリメントまたは代替品として適していますが、特定のビジネスニーズに応じて選択する必要があります。

    Redis:強力なメモリデータストアの紹介Redis:強力なメモリデータストアの紹介May 06, 2025 am 12:08 AM

    redisisahigh-performancein-memorydatastructurturturestorettorethatedcelsinsinsinsversility.1)itsupportsvariousdatastructureslikestrings、lists、andsets.2)redisisaninmorydatabasewithpersistenceoptions、daturing datasafety.3)

    Redisは主にデータベースですか?Redisは主にデータベースですか?May 05, 2025 am 12:07 AM

    Redisは主にデータベースですが、単なるデータベース以上のものです。 1.データベースとして、Redisは持続性をサポートし、高性能のニーズに適しています。 2。キャッシュとして、Redisはアプリケーションの応答速度を改善します。 3。メッセージブローカーとして、Redisはリアルタイム通信に適したPublish-Subscribeモードをサポートしています。

    Redis:データベース、サーバー、または他の何か?Redis:データベース、サーバー、または他の何か?May 04, 2025 am 12:08 AM

    redisisamultifaCetedTooltoToolvesSasadatabase、server、andmore。

    Redis:その目的と主要なアプリケーションを発表しますRedis:その目的と主要なアプリケーションを発表しますMay 03, 2025 am 12:11 AM

    Redisisanopen-Source、In-MemoryDatastructurestoreStoreSadatabase、Cache、AndmessageBroker、ExcellingInspeedandversatility.ItisisWidely-susederCaching、Real-Timeanalytics、Session Management、AndleaderboardsdueTotutsuptorututrututrututruturturturturturturesturesaddataacys

    See all articles

    ホットAIツール

    Undresser.AI Undress

    Undresser.AI Undress

    リアルなヌード写真を作成する AI 搭載アプリ

    AI Clothes Remover

    AI Clothes Remover

    写真から衣服を削除するオンライン AI ツール。

    Undress AI Tool

    Undress AI Tool

    脱衣画像を無料で

    Clothoff.io

    Clothoff.io

    AI衣類リムーバー

    Video Face Swap

    Video Face Swap

    完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

    ホットツール

    AtomエディタMac版ダウンロード

    AtomエディタMac版ダウンロード

    最も人気のあるオープンソースエディター

    SublimeText3 英語版

    SublimeText3 英語版

    推奨: Win バージョン、コードプロンプトをサポート!

    ゼンドスタジオ 13.0.1

    ゼンドスタジオ 13.0.1

    強力な PHP 統合開発環境

    mPDF

    mPDF

    mPDF は、UTF-8 でエンコードされた HTML から PDF ファイルを生成できる PHP ライブラリです。オリジナルの作者である Ian Back は、Web サイトから「オンザフライ」で PDF ファイルを出力し、さまざまな言語を処理するために mPDF を作成しました。 HTML2FPDF などのオリジナルのスクリプトよりも遅く、Unicode フォントを使用すると生成されるファイルが大きくなりますが、CSS スタイルなどをサポートし、多くの機能強化が施されています。 RTL (アラビア語とヘブライ語) や CJK (中国語、日本語、韓国語) を含むほぼすべての言語をサポートします。ネストされたブロックレベル要素 (P、DIV など) をサポートします。

    Dreamweaver Mac版

    Dreamweaver Mac版

    ビジュアル Web 開発ツール