我在Akka上使用Redis,所以不需要阻塞 call 。生菜内置了异步 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);
    }

LETTUCE
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 调用的执行上下文。

最佳答案

您的问题没有答案,因为这要看情况。
Jedis和生菜都是成熟的客户。为了完成Java客户端列表,还有Redisson,它增加了另一层抽象(Collection/Queue/Lock/...接口(interface),而不是原始的Redis命令)。
这在很大程度上取决于您与客户的合作方式。通常,Jedis(连接到Redis的基于Java的客户端)在数据访问方面是单线程的,因此并发获得的唯一好处是将协议(protocol)和I/O工作卸载到了不同的线程上。对于lettuce和Redisson而言,这并不完全正确,因为它们在后台使用netty(netty将一个套接字 channel 绑定(bind)到特定的事件循环线程)。
使用Jedis,一次只能将一个连接与一个线程一起使用。这与Akka actor模型很好地关联,因为一个actor实例一次只能被一个线程占用。
另一方面,您需要与处理特定角色的线程一样多的Jedis连接。如果开始在不同角色之间共享Jedis连接,则要么进行连接池连接,要么需要每个角色实例具有专用的Jedis连接。请记住,您需要自己进行重新连接(一旦Redis连接断开)。
使用Redisson和生菜,您可以进行透明的重新连接(这是生菜的默认值,不确定Redisson)。
通过使用生菜和Redisson,您可以在所有参与者之间共享一个连接,因为它们是线程安全的。在两种情况下,您不能共享一个生菜连接:

  • 阻止操作(因为您将阻止连接的所有其他用户)
  • Transactions(MULTI/EXEC,因为您会将不同的操作与事务混合在一起,所以您当然不希望这样做)

    Jedis没有异步接口(interface),因此您需要自己执行此操作。这是可行的,我对MongoDB做了类似的工作,将I/O部分卸载/解耦给其他参与者。您可以从代码中使用该方法,但是由于您在可运行的侦听器中执行非阻塞操作,因此不需要提供自己的执行程序服务。
    使用lettuce 4.0,您将获得Java 8支持(由于具有CompletionStage接口(interface),因此在异步API方面要好得多),甚至可以使用RxJava(响应式编程)来实现并发。
    生菜对您的并发模型没有意见。它允许您根据需要使用它,除了Java 6/7的普通Future/ListenableFuture API和Guava并不是很好用。
    HTH,马克

  • 10-06 09:13