最も一般的に使用される分散IDソリューションはここにあります!

「1.分散IDの概念」
IDと言えば、その特徴は独自性です。人間の世界では、IDはIDカードであり、各人の固有のIDです。複雑な分散システムでは、多くの場合、大量のデータとメッセージを一意に識別する必要があります。たとえば、データベースのIDフィールドは、単一のエンティティの場合、IDとして自己インクリメントを使用できますが、サブデータベースサブテーブルの後に、データの一部を識別するために一意のIDが必要です。このIDは分散ID。分散IDの場合、分散システムの特性(高い同時実行性、高可用性、高いパフォーマンスなど)も必要です。

「2つの分散ID実装計画」

次の表は、いくつかの一般的なソリューションの比較です
ここに画像の説明を挿入
。「番号セグメントモード」と「スノーアルゴリズム」の2つの一般的な分散IDソリューションがあります。

「番号セグメントモード」はデータベースによって異なりますが、データベースの主キーを増やすモードとは異なります。100を100、200、300、100の数値セグメントとすると、フェッチするたびにIDを取得でき、パフォーマンスが大幅に向上します。

「スノーアルゴリズム」は、図に示すように、符号ビット+タイムスタンプ+作業機ID +シリアル番号で構成されます。
ここに画像の説明を挿入
符号ビットは0、0は正の数、IDは正の数です。

言うまでもなく、タイムスタンプビットはタイムスタンプを格納するために使用され、単位はミリ秒です。

稼働中のマシンのIDビットは、マシンのIDを格納するために使用され、通常、5つのエリアビット+5つのサーバー識別ビットに分割されます。

シリアル番号ビットは自己増加します。

スノーフレークアルゴリズムはどのくらいのデータを保存できますか?時間範囲:2 ^ 41 /(3652460601000)= 69年の作業プロセス範囲:2 ^ 10 = 1024シリアル番号範囲:2 ^ 12 = 4096、つまり4096IDを1ミリ秒で生成できます。
このアルゴリズムのロジックによれば、このアルゴリズムをJava言語で実装し、ツールメソッドとしてカプセル化するだけで、各ビジネスアプリケーションはツールメソッドを直接使用して分散IDを取得でき、各ビジネスアプリケーションを確認するだけで済みます。独自の作業がありますマシンIDで十分であり、配布IDを個別に取得するためのアプリケーションを構築する必要はありません。以下は、SnowflakeアルゴリズムのTwitterバージョンです。

public class SnowFlake {
    
    

    /**
     * 起始的时间戳
     */
    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 SnowFlake(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;
    }

    /**
     * 产生下一个ID
     *
     * @return
     */
    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 {
    
    
            //不同毫秒内,序列号置为0
            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();
    }

    public static void main(String[] args) {
    
    
        SnowFlake snowFlake = new SnowFlake(2, 3);

        for (int i = 0; i < (1 << 12); i++) {
    
    
            System.out.println(snowFlake.nextId());
        }

    }
}

「3つの分散IDオープンソースコンポーネント」

3.1オープンソースコンポーネントの選び方

オープンソースコンポーネントを選択するには、まず、互換性やスケーラビリティなど、ソフトウェア機能がニーズを満たしているかどうかを確認する必要があります。

第二に、現在の技術力と、現在の技術スタックや自分やチームの技術力に応じてスムーズに使えるかどうかを見極める必要があります。

第三に、それはオープンソースコンポーネントのコミュニティに依存します。それは主に、更新が頻繁であるかどうか、プロジェクトが誰かによって維持されているかどうか、ピットに遭遇したときに助けを求めることができるかどうか、そしてそれが広く使用されているかどうかに焦点を当てています業界で。

3.2美団の葉

Leafは、Meituanの基本的なR&Dプラットフォームによって開始された分散ID生成サービスです。その名前は、ドイツの哲学者で数学者のLeibnizによる「世界に同じ葉は2つありません」という文に由来しています。Leafは信頼性が高く、待ち時間が短いなどの機能を備えています。そしてグローバルな独自性。現在、Meituan Finance、Meituan Takeaway、MeituanLiquorなどの多くの部門で広く使用されています。具体的な技術的な詳細については、MeituanTechnologyブログの記事「LeafMeituanDistributed IDGenerationService」を参照してください。現在、LeafプロジェクトはGithubでオープンソース化されています:https://github.com/Meituan-Dianping/Leaf。リーフの特徴は次のとおりです。

グローバルに一意であるため、IDが重複することはなく、IDの全体的な傾向は高まっています。
高可用性を備えたこのサービスは、完全に分散アーキテクチャに基づいており、MySQLがダウンしている場合でも、一定期間データベースが使用できないことを許容できます。
高い同時実行性と低い遅延。CentOS4C8G仮想マシンでは、QPSを最大5W +までリモートで呼び出すことができ、TP99は1ミリ秒以内です。
アクセスは簡単で、会社のRPCサービスまたはHTTP呼び出しを介して直接アクセスできます。
3.3 Baidu UidGenerator

UidGenerator Baiduオープンソースは、スノーフレークアルゴリズムに基づく分散型の高性能一意IDジェネレーターです。公式ウェブサイトの説明を使用:UidGeneratorは、コンポーネントの形式でアプリケーションプロジェクトで動作し、カスタムのworkerIdビットと初期化戦略をサポートし、dockerなどの仮想化環境でのインスタンスの自動再起動やドリフトなどのシナリオに適しています。実装に関しては、UidGeneratorは将来の時間を使用して、シーケンスに固有の同時実行制限を解決します。RingBufferを使用して生成されたUIDをキャッシュし、UIDの生成と消費を並列化し、CacheLineを補完してRingBufferによって引き起こされるハードウェアレベルを回避します。 「疑似共有」の問題。最終的な単一マシンのQPSは600万に達する可能性があります。UidGeneratorのGitHubアドレス:https://github.com/baidu/uid-generator

3.4オープンソースコンポーネントの比較

Baidu UidGeneratorはJava言語であり、最後の送信レコードは2年前であり、基本的に保守されていません。スノーフレークアルゴリズムのみがサポートされています。

Meituan LeafもJava言語であり、最近2020年まで維持されており、番号セグメントモードとスノーフレークアルゴリズムをサポートしています。

要約すると、理論と2つのオープンソースコンポーネントを比較すると、MeituanLeafの方がわずかに優れていることがわかります。

一般的に使用されている分散IDソリューションをまだ知っていますか?

おすすめ

転載: blog.csdn.net/ncw8080/article/details/113854360