我在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,您可以在所有参与者之间共享一个连接,因为它们是线程安全的。在两种情况下,您不能共享一个生菜连接:
MULTI
/EXEC
,因为您会将不同的操作与事务混合在一起,所以您当然不希望这样做)Jedis没有异步接口(interface),因此您需要自己执行此操作。这是可行的,我对MongoDB做了类似的工作,将I/O部分卸载/解耦给其他参与者。您可以从代码中使用该方法,但是由于您在可运行的侦听器中执行非阻塞操作,因此不需要提供自己的执行程序服务。
使用lettuce 4.0,您将获得Java 8支持(由于具有CompletionStage接口(interface),因此在异步API方面要好得多),甚至可以使用RxJava(响应式编程)来实现并发。
生菜对您的并发模型没有意见。它允许您根据需要使用它,除了Java 6/7的普通
Future
/ListenableFuture
API和Guava并不是很好用。HTH,马克