web-dev-qa-db-ja.com

ジェディスとレタスの非同期能力

Akkaでredisを使用しているため、ブロッキングコールは必要ありません。レタスにはasync-future呼び出しが組み込まれています。ただし、JedisはRedisが推奨するクライアントです。両方を正しい方法で使用している場合、誰かに教えてもらえますか。もしそうなら、どちらが良いでしょう。

[〜#〜] jedis [〜#〜]静的なJedis接続プールを使用してconを取得し、Akka futureコールバックを使用して結果を処理しています。ここでの懸念は、別のスレッド(呼び出し可能)を使用して結果を取得するときに、スレッドが結果をブロックすることです。レタスはこれを行うより効率的な方法があるかもしれませんが。

 private final class OnSuccessExtension extends OnSuccess<String> {
            private final ActorRef senderActorRef;
            private final Object message;
            @Override
            public void onSuccess(String valueRedis) throws Throwable {
                log.info(getContext().dispatcher().toString());
                senderActorRef.tell((String) message, ActorRef.noSender());
            }
             public OnSuccessExtension(ActorRef senderActorRef,Object message) {
                    this.senderActorRef = senderActorRef;
                    this.message=message;
                }
        }
        ActorRef senderActorRef = getSender(); //never close over a future
            if (message instanceof String) {
        Future<String> f =akka.dispatch.Futures.future(new Callable<String>() {
                    public String call() {
                        String result;
                        try(Jedis jedis=JedisWrapper.redisPool.getResource()) {
                            result = jedis.get("name");
                        }
                        return result;
                    }
                }, ex);
                f.onSuccess(new OnSuccessExtension(senderActorRef,message), ex);
    }

[〜#〜]レタス[〜#〜]

ExecutorService executorService = Executors.newFixedThreadPool(10);
public void onReceive(Object message) throws Exception {
        ActorRef senderActorRef = getSender(); //never close over a future
        if (message instanceof String) {

            final RedisFuture<String> future = lettuce.connection.get("name");
            future.addListener(new Runnable() {
                final ActorRef sender = senderActorRef;
                final String msg =(String) message;
                @Override
                public void run() {
                    try {
                        String value = future.get();
                        log.info(value);
                        sender.tell(message, ActorRef.noSender());
                    } catch (Exception e) {
                    }
                }
            }, executorService);

レタスが非同期呼び出しに適している場合。次に、実稼働環境でどのタイプのエグゼキューターを使用する必要がありますか。可能であれば、AkkaディスパッチャーをLetture future callの実行コンテキストとして使用できますか。

21
cykopath

それは依存するため、あなたの質問に対する誰の答えもありません。

ジェディスとレタスはどちらも成熟した顧客です。 Javaクライアントのリストを完成させるために、Redissonもあります。これは、抽象化のレイヤー(生のRedisコマンドの代わりにCollection/Queue/Lock/...インターフェース)を追加します。

それは、あなたがクライアントとどのように働いているかにかなり依存します。一般に、Redisはデータアクセスの観点からシングルスレッドであるため、同時実行によって得られる唯一の利点は、プロトコルとI/O作業を異なるスレッドにオフロードすることです。フードの下でnettyを使用するため、レタスとRedissonには完全に当​​てはまりません(nettyは特定のイベントループスレッドに1つのソケットチャネルをバインドします)。

Jedisでは、一度に1つのスレッドでのみ1つの接続のみを使用できます。 1つのアクターインスタンスは一度に1つのスレッドだけで占有されるため、これはAkkaアクターモデルとうまく相関しています。

一方、特定のアクターを処理するスレッドと同じ数のJedis接続が必要です。異なるアクター間でJedis接続の共有を開始する場合は、接続プーリングに進むか、アクターインスタンスごとに専用のJedis接続が必要です。再接続(Redis接続が切断された後)を自分で処理する必要があることに注意してください。

Redissonとレタスを使用すると、必要に応じて透過的な再接続が得られます(これはレタスのデフォルト値であり、Redissonについては不明です)。

レタスとRedissonを使用すると、スレッドセーフであるため、すべてのアクター間で1つの接続を共有できます。次の2つの場合、1つのレタス接続を共有することはできません。

  1. 操作のブロック(接続の他のすべてのユーザーをブロックするため)
  2. トランザクション(MULTI/EXEC。異なるオペレーションをトランザクションと混合するため、これは絶対にしたくないことです)

Jedisには非同期インターフェイスがないため、これを自分で行う必要があります。それは実現可能であり、I/O部分を他のアクターにオフロード/デカップリングするMongoDBで同様のことを行いました。コードからアプローチを使用できますが、実行可能リスナーで非ブロッキング操作を行うため、独自のエグゼキューターサービスを提供する必要はありません。

Lettuce 4.0では、Java 8のサポート(CompletionStageインターフェースのおかげで非同期APIの点ではるかに優れています)が得られます。また、RxJava(リアクティブプログラミング)を使用して並行性にアプローチすることもできます) 。

レタスは、同時実行モデルについて意見を表明していません。 Java 6/7であり、Guavaを使用するのはあまり適切ではありません)の単純なFuture/ListenableFuture AP​​Iを除き、必要に応じて使用できます。

HTH、マーク

45
mp911de

Redisson フレームワークを試してください。 Project ReactorおよびRxJava2 libsとの統合によりサポートされるReactive Streams APIと同様に非同期APIを提供します。

非同期APIの使用例:

RedissonClient client = Redisson.create(config);
RMap<String, String> map = client.getMap("myMap");

// implements CompletionStage interface
RFuture<String> future = map.get("myKey");

future.whenComplete((res, exception) -> {
  // ...
});

Project Reactor libを使用したReactive Streams APIの使用例:

RedissonReactiveClient client = Redisson.createReactive(config);
RMapReactive<String, String> map = client.getMap("myMap");

Mono<String> resp = map.get("myKey");

RxJava2 libを使用したリアクティブストリームAPIの使用例:

RedissonRxClient client = Redisson.createRx(config);
RMapRx<String, String> map = client.getMap("myMap");

Flowable<String> resp = map.get("myKey");
1