分散型データベースのプライマリ・キー:スノー・アルゴリズムスノーアルゴリズム

5179 ワード

snowflakeアルゴリズム
snowflakeアルゴリズムはtwitterオープンソースの分布式id生成アルゴリズムで、1つの64ビットのlong型のidを、1ビットは不要で、そのうち41ビットをミリ秒数、10 bitをワークマシンid、12 bitをシーケンス番号とする.
  • 1 bit:いいえ、どうしてですか.バイナリの最初のbitは1であれば負数ですが、私たちが生成したidは正数なので、最初のbitは0に統一されています.
  • 41 bit:タイムスタンプを表し、単位はミリ秒です.41 bitで表すことができる数字は2^41-1、つまり2^41-1ミリ秒の値を表すことができ、大人に換算すると69年の時間を表すことができます.
  • 10 bit:ワークマシンidを記録し、このサービスが最大2^10台のマシンに配備できることを示しています.つまり1024台のマシンです.しかし10 bitでは5 bitが機械室idを表し、5 bitが機械idを表す.最大2^5個の機械室(32個の機械室)を表し、各機械室に2^5個の機械(32台の機械)を表すことができるという意味です.
  • 12 bit:これは同じミリ秒以内に生成された異なるidを記録するために使用され、12 bitが表すことができる最大正の整数は2^12-1=4096であり、つまりこの12 bitが表す数字で同じミリ秒内の4096個の異なるidを区別することができる.

  • 0 | 0001100 10100010 10111110 10001001 01011100 00 | 10001 | 1 1001 | 0000 00000000
    public class IdWorker {
    
        private long workerId;
        private long datacenterId;
        private long sequence;
    
        public IdWorker(long workerId, long datacenterId, long sequence) {
            // sanity check for workerId
            //          ,            id   id    32,    0
            if (workerId > maxWorkerId || workerId < 0) {
                throw new IllegalArgumentException(
                        String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
            }
            if (datacenterId > maxDatacenterId || datacenterId < 0) {
                throw new IllegalArgumentException(
                        String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
            }
            System.out.printf(
                    "worker starting. timestamp left shift %d, datacenter id bits %d, worker id bits %d, sequence bits %d, workerid %d",
                    timestampLeftShift, datacenterIdBits, workerIdBits, sequenceBits, workerId);
    
            this.workerId = workerId;
            this.datacenterId = datacenterId;
            this.sequence = sequence;
        }
    
        private long twepoch = 1288834974657L;
    
        private long workerIdBits = 5L;
        private long datacenterIdBits = 5L;
    
        //         ,   5 bit     31   ,      id     32  
        private long maxWorkerId = -1L ^ (-1L << workerIdBits);
    
        //        ,   5 bit     31   ,  id     32  
        private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
        private long sequenceBits = 12L;
    
        private long workerIdShift = sequenceBits;
        private long datacenterIdShift = sequenceBits + workerIdBits;
        private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
        private long sequenceMask = -1L ^ (-1L << sequenceBits);
    
        private long lastTimestamp = -1L;
    
        public long getWorkerId() {
            return workerId;
        }
    
        public long getDatacenterId() {
            return datacenterId;
        }
    
        public long getTimestamp() {
            return System.currentTimeMillis();
        }
    
        public synchronized long nextId() {
            //            ,     
            long timestamp = timeGen();
    
            if (timestamp < lastTimestamp) {
                System.err.printf("clock is moving backwards.  Rejecting requests until %d.", lastTimestamp);
                throw new RuntimeException(String.format(
                        "Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
            }
    
            if (lastTimestamp == timestamp) {
                //                 4096   
                //          ,            4096     ,        sequence   4096    
                sequence = (sequence + 1) & sequenceMask;
                if (sequence == 0) {
                    timestamp = tilNextMillis(lastTimestamp);
                }
            } else {
                sequence = 0;
            }
    
            //             id    ,     
            lastTimestamp = timestamp;
    
            //           ,   41 bit  ;
            //     id     5 bit  ;
            //    id    5 bit  ;      12 bit;
            //           64 bit      ,    10       long  
            return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift)
                    | (workerId << workerIdShift) | sequence;
        }
    
        private long tilNextMillis(long lastTimestamp) {
            long timestamp = timeGen();
            while (timestamp <= lastTimestamp) {
                timestamp = timeGen();
            }
            return timestamp;
        }
    
        private long timeGen() {
            return System.currentTimeMillis();
       }
    
       // ---------------  ---------------
       public static void main(String[] args) {
           IdWorker worker = new IdWorker(1, 1, 1);
           for (int i = 0; i < 30; i++) {
               System.out.println(worker.nextId());
           }
       }
    
    }

    なんというか、たぶんそういう意味でしょう.41 bitは現在のミリ秒単位のタイムスタンプです.そして5 bitはあなたが伝えた1つの機械室id(ただし最大32以内)であり、また5 bitはあなたが伝えた機械id(ただし最大32以内)であり、残りの12 bitシーケンス番号は、前回idを生成した時間が1ミリ秒以内であれば、順序を加算し、最大4096シーケンス番号以内にします.
    だからあなたは自分でこのツール類を利用して、自分でサービスをして、それから各機械室のすべての機械に対してこのようなものを初期化して、この機械室のこの機械の番号は0です.そして、この機械室のこの機械がidを生成するという要求を受信するたびに、対応するWorker生成を見つけます.
    このsnowflakeアルゴリズムを利用して、あなたは自分の会社のサービスを開発することができて、甚だしきに至っては機械室idと機械idに対して、どうせあなたに5 bit+5 bitを予約して、あなたは別の業務の意味のあるものに変えてもいいです.
    このsnowflakeアルゴリズムは相対的に頼りになるので、本当に分布式id生成をしなければなりません.もし高同時とかなら、これを使うと性能がいいはずです.普通は毎秒数万同時のシーンでも、十分です.