Redisキュー(一):リストベースのメッセージキューの使用

10467 ワード

一、概説

  • 使用面では、Redisは文字列データを格納するためのリストというデータ型を提供している.
  • は内部データ構造実装の面で、リストは主にチェーンテーブルに基づいて実装され、文字列データは挿入順序に従ってチェーンテーブルの中でソートされ、挿入方式はチェーンテーブルの前と後ろに挿入することができる.それ以外に、Redisはリストのブロック読取BLPOPとBRPOPを提供した.
  • 上記リストのようなデータ型の特徴に加えて、Redisサーバはクライアントの要求を単一スレッドで処理するので、Redisのリストは、生産者がキューにデータを充填し、消費者がキューからデータを読み取るのを待つ軽量レベルのメッセージキュー、すなわちJavaのようなブロックキューLinkedBlockingQueueのデータ型を分散システム間で実現するのに非常に適している.LinkedBlockingQueueは、Javaプログラミングで同じJavaプロセスを実装するためによく使用される複数のスレッド間の生産者消費者モデルのスレッドセキュリティのキュー実装である.

  • 二、使用方法

  • の使用態様では、Redisにおいて1つのメッセージキューを実装することは、主に、リストがキューヘッダと末尾から文字列要素を挿入し、リストがブロック可能な読み取りをサポートする特性に基づいている.このほか、プログラミングにおいても、メッセージキュー消費者側でwhile(true)デッドサイクルを使用して取得キューのデータをポーリングすることができるが、この方式はプログラム性能に大きな影響を及ぼし、使用を推奨しない.
  • 生産者がリストにデータを埋め込み、消費者がリストから消費データを読み取らない場合、データは消費者が読み取るまでリストに格納され、削除される.

  • Redisコマンドラインに基づく使用
  • は、Redisコマンドライン操作リストに基づいてメッセージキューを実装するために主にこの機能を実証するために使用され、実際のアプリケーションでは使用されず、言語に対応するRedisコードライブラリによって提供されるAPIに基づいてプログラミング実装される.FIFOを実装するメッセージキューを以下に示す:
  • メッセージキューの消費者はBLPOPコマンドを呼び出し、メッセージキューのヘッダまたは左側から、ブロックしてデータを取得し、コマンドフォーマットは:BLPOP[key 1 key 2...]timeoutであり、keyはキュー名であり、複数のキューを指定することができ、1つのキューにデータが返されると、呼び出しは返される.timeoutはブロックに指定された時間であり、値が0の場合はデータが読み取れるまでブロックされたまま戻り、0より大きい場合はブロックに指定された秒数である.1回目のブロックは1秒で直接戻り、データは読み込まれず、2回目はキューにデータが来るまでブロックされ、1つのデータが読み込まれると戻ります.
    127.0.0.1:6379> BLPOP queueList 1
    (nil)
    (1.05s)
    127.0.0.1:6379> BLPOP queueList 0
    1) "queueList"
    2) "stringData1"
    (3.94s)
    
  • メッセージキューの生産者は、RPUSHコマンドを呼び出してメッセージキューの末尾または右側にデータを埋め込む.以下のように、RPUSHを呼び出してリストqueueListの末尾、すなわち右側から2つの文字列データを埋め込み、そのうち最初の文字列内容はstringData 1であるため、上面の消費者もこの文字列を読み取った.
    127.0.0.1:6379> RPUSH queueList stringData1 stringData2
    (integer) 2
    
  • しばらくしてから、再びBLPOPコマンドを呼び出すと、ブロックする必要がなく、リストから埋め込まれた2番目の文字列データstringData 2が直接読み込まれます.
    127.0.0.1:6379> BLPOP queueList 0
    1) "queueList"
    2) "stringData2"
    
  • .
    JavaクライアントJedisベースの使用
  • Java言語を使用してRedisリストに基づいてメッセージキューを実装する場合、RedisのJavaクライアントJedisを使用することができ、spring-data-redisを使用する場合、RedisTemplateのようなパッケージが提供する関連クラスおよびAPIを使用することができる.JedisとRedisベースのリストを用いてメッセージキューを実装するコードを以下に示す:
  • メッセージキュー作成者:リストqueueListに2つのデータstringData 1とstringData 2を順次入力します.
    @Test
    public void queuePublish() {
        Jedis producer = new Jedis("127.0.0.1", 6379);
        //                  
        producer.rpush("queueList", "stringData1", "stringData2");
    }
    
  • メッセージキューコンシューマ:Jedisのリストのblpopメソッドは、戻りタイプがJavaリストタイプで、サイズが2で、最初のデータがリスト名で、2番目が読み出したデータです.
    @Test
    public void queueSubscribe() {
        Jedis consumer = new Jedis("127.0.0.1", 6379);
        System.out.println("consumer waiting data...");
        //           ,                 ,
        //        List,   2,            ,         
        List<String> listData = consumer.blpop(0, "queueList");
        System.out.println("consumer get data: " + listData);
    }
    
    印刷結果は以下の通りである:
    consumer waiting data...
    consumer get data: [queueList, stringData1]
    
  • 以下のデモンストレーションキューの消費者は、ブロックされていないバージョンのリストメソッドとwhile(true)ポーリングリストを組み合わせて実装する:
    @Test
    public void queueSubscribeNotBlocking() {
        Jedis consumer = new Jedis("127.0.0.1", 6379);
        System.out.println("consumer waiting data...");
        while (true) {
            try {
                String data = consumer.lpop("queueList");
                if (data != null) {
                    System.out.println("consumer get data: " + data);
                    //         
                    continue;
                }
                //        1     
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    結果は、
    consumer waiting data...
    consumer get data: stringData1
    consumer get data: stringData2
    
  • のように印刷される.

    三、欠陥分析


    Redisのリストに基づいて軽量レベルのメッセージキューを実装することができるが、この方法には以下のような欠点もある.
    1.メッセージの信頼性
  • Redisがクラッシュした場合、キュー・メッセージは失われます.クラッシュは永続化メカニズムによって実現できますが、Redisは通常キャッシュとして使用され、データ・ストレージとしては適していません.永続化はパフォーマンスに一定の影響を与えるためです.特に、キューのメッセージは通常、一定のリアルタイム性を有するため、クラッシュ・リカバリ後にメッセージを再同期することは意味がありません.

  • 2.メモリ資源の消耗
  • 生産者がメッセージをキューに埋め込む速度が消費者の消費速度より大きい場合、Redisのデータはメモリに格納されているため、メモリが急騰する.

  • 3.メッセージがブロードキャストできない
  • Redisキューは、リストに基づいて実装されるため、1つのメッセージがキューから読み出された後は存在しないため、各メッセージは1回しか存在しない.この特性はRabbitMQのキューと同様であり、RabbitMQのあるキューには複数の消費者が存在することができるが、キューのメッセージはポーリングの負荷等化方式に基づいてこれらの消費者にメッセージを配布し、各メッセージは通常1つの消費者によって正常に消費されるしかない.Kafkaであれば、キューの各メッセージを異なる消費者グループによって複数回消費することができ、すなわち消費者グループの概念によってブロードキャストを実現することができるが、その主な実現原理は、Kafkaが追加方式に基づいて順次このファイルにデータを追加してデータを格納し、このファイル内で読み取りインデックスを維持することによってキュー機能をシミュレートすることである.したがって、各消費者は、複数の消費を行うために独立した読み取りインデックスを維持することができる.