Jedis 和 Lettuce 异步能力
Jedis and Lettuce async abilities
我正在将 Redis 与 Akka 一起使用,因此我不需要阻塞调用。 Lettuce 内置了异步未来调用。但是Jedis是Redis推荐的客户端。有人可以告诉我我是否以正确的方式使用它们。如果可以,哪个更好
杰迪斯
我正在使用静态 Jedis 连接池来获取 con 并使用 Akka 未来回调来处理结果。我在这里担心的是,当我使用另一个线程(可调用)来获取结果时,该线程最终会为结果而阻塞。虽然生菜可能有一些更有效的方法来做到这一点。
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);
如果 lettuce 是异步调用的更好选择。那么我应该在生产环境中使用什么类型的执行器。如果可能的话,我可以使用 Akka 调度程序作为 Letture 未来调用的执行上下文。
您的问题没有唯一的答案,因为这要视情况而定。
Jedis和lettuce都是成熟客户。为了完成 Java 客户端列表,还有 Redisson,它添加了另一层抽象(Collection/Queue/Lock/... 接口而不是原始 Redis 命令)。
这在很大程度上取决于您与客户的合作方式。一般来说,Jedis(java 基于客户端连接到 redis)在数据访问方面是单线程的,所以并发的唯一好处是卸载协议和 I/O 工作到不同的线程。这对 lettuce 和 Redisson 来说并不完全正确,因为它们在底层使用 netty(netty 将一个套接字通道绑定到一个特定的事件循环线程)。
使用 Jedis,您一次只能对一个线程使用一个连接。这与 Akka actor 模型密切相关,因为一个 actor 实例一次仅被一个线程占用。
另一方面,您需要与处理特定参与者的线程一样多的 Jedis 连接。如果您开始在不同的 actor 之间共享 Jedis 连接,您要么选择连接池,要么需要为每个 actor 实例提供一个专用的 Jedis 连接。请记住,您需要自己处理重新连接(一旦 Redis 连接断开)。
对于 Redisson 和 lettuce,如果你愿意,你可以获得透明的重新连接(这是 lettuce 的默认值,Redisson 不确定)。
通过使用 lettuce 和 Redisson,您可以在所有参与者之间共享一个连接,因为它们是线程安全的。在两种情况下您不能共享一个生菜连接:
- 阻止操作(因为您会阻止连接的所有其他用户)
- 事务(
MULTI
/EXEC
,因为您会将不同的操作与事务混合使用,这当然是您不想这样做的事情)
Jedis 没有异步接口,所以你需要自己做。这是可行的,我对其他演员做了类似 MongoDB、offloading/decoupling 和 I/O 的部分。您可以使用代码中的方法,但不需要提供自己的执行程序服务,因为您在可运行侦听器中执行非阻塞操作。
使用 lettuce 4.0,您将获得 Java 8 支持(由于 CompletionStage 接口,在异步 API 方面更好),您甚至可以使用 RxJava(反应式编程)来实现并发。
Lettuce 对您的并发模型没有意见。它允许您根据需要使用它,除了 Future
/ListenableFuture
API of Java 6/7 和 Guava 不是很好用。
HTH,马克
尝试Redisson 框架。它通过与 Project Reactor 和 RxJava3 库集成来提供异步 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) -> {
// ...
});
Reactive Streams API 与 Project Reactor 库使用示例:
RedissonReactiveClient client = Redisson.createReactive(config);
RMapReactive<String, String> map = client.getMap("myMap");
Mono<String> resp = map.get("myKey");
Reactive Streams API 与 RxJava2 lib 用法示例:
RedissonRxClient client = Redisson.createRx(config);
RMapRx<String, String> map = client.getMap("myMap");
Flowable<String> resp = map.get("myKey");
我正在将 Redis 与 Akka 一起使用,因此我不需要阻塞调用。 Lettuce 内置了异步未来调用。但是Jedis是Redis推荐的客户端。有人可以告诉我我是否以正确的方式使用它们。如果可以,哪个更好
杰迪斯 我正在使用静态 Jedis 连接池来获取 con 并使用 Akka 未来回调来处理结果。我在这里担心的是,当我使用另一个线程(可调用)来获取结果时,该线程最终会为结果而阻塞。虽然生菜可能有一些更有效的方法来做到这一点。
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);
如果 lettuce 是异步调用的更好选择。那么我应该在生产环境中使用什么类型的执行器。如果可能的话,我可以使用 Akka 调度程序作为 Letture 未来调用的执行上下文。
您的问题没有唯一的答案,因为这要视情况而定。
Jedis和lettuce都是成熟客户。为了完成 Java 客户端列表,还有 Redisson,它添加了另一层抽象(Collection/Queue/Lock/... 接口而不是原始 Redis 命令)。
这在很大程度上取决于您与客户的合作方式。一般来说,Jedis(java 基于客户端连接到 redis)在数据访问方面是单线程的,所以并发的唯一好处是卸载协议和 I/O 工作到不同的线程。这对 lettuce 和 Redisson 来说并不完全正确,因为它们在底层使用 netty(netty 将一个套接字通道绑定到一个特定的事件循环线程)。
使用 Jedis,您一次只能对一个线程使用一个连接。这与 Akka actor 模型密切相关,因为一个 actor 实例一次仅被一个线程占用。
另一方面,您需要与处理特定参与者的线程一样多的 Jedis 连接。如果您开始在不同的 actor 之间共享 Jedis 连接,您要么选择连接池,要么需要为每个 actor 实例提供一个专用的 Jedis 连接。请记住,您需要自己处理重新连接(一旦 Redis 连接断开)。
对于 Redisson 和 lettuce,如果你愿意,你可以获得透明的重新连接(这是 lettuce 的默认值,Redisson 不确定)。
通过使用 lettuce 和 Redisson,您可以在所有参与者之间共享一个连接,因为它们是线程安全的。在两种情况下您不能共享一个生菜连接:
- 阻止操作(因为您会阻止连接的所有其他用户)
- 事务(
MULTI
/EXEC
,因为您会将不同的操作与事务混合使用,这当然是您不想这样做的事情)
Jedis 没有异步接口,所以你需要自己做。这是可行的,我对其他演员做了类似 MongoDB、offloading/decoupling 和 I/O 的部分。您可以使用代码中的方法,但不需要提供自己的执行程序服务,因为您在可运行侦听器中执行非阻塞操作。
使用 lettuce 4.0,您将获得 Java 8 支持(由于 CompletionStage 接口,在异步 API 方面更好),您甚至可以使用 RxJava(反应式编程)来实现并发。
Lettuce 对您的并发模型没有意见。它允许您根据需要使用它,除了 Future
/ListenableFuture
API of Java 6/7 和 Guava 不是很好用。
HTH,马克
尝试Redisson 框架。它通过与 Project Reactor 和 RxJava3 库集成来提供异步 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) -> {
// ...
});
Reactive Streams API 与 Project Reactor 库使用示例:
RedissonReactiveClient client = Redisson.createReactive(config);
RMapReactive<String, String> map = client.getMap("myMap");
Mono<String> resp = map.get("myKey");
Reactive Streams API 与 RxJava2 lib 用法示例:
RedissonRxClient client = Redisson.createRx(config);
RMapRx<String, String> map = client.getMap("myMap");
Flowable<String> resp = map.get("myKey");