Ассистские способности Jedis и Lettuce
Я использую redis с Akka, поэтому мне не нужно блокировать вызовы. У салата есть встроенный в него асинхронный вызов. Но Джедис - рекомендуемый клиент Редиса. Может кто-нибудь сказать мне, если я использую их оба правильно. Если да, то какой из них лучше.
Jedis
Я использую статический пул соединений Jedis, чтобы получить con и использовать обратный вызов Akka для обработки результата. Меня беспокоит, когда я использую другой поток (вызываемый), чтобы получить результат, который поток в конечном итоге собирается заблокировать для результата. Хотя у Lettuce может быть более эффективный способ сделать это.
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);
Если салат - лучший вариант для вызовов Async. Тогда какой тип исполнителя я должен использовать в производственной среде. Если возможно, я могу использовать диспетчер Akka в качестве контекста выполнения для будущего вызова Letture.
Ответы
Ответ 1
На ваш вопрос нет ответа, потому что это зависит.
Jedis и салат - зрелые клиенты. Чтобы завершить список клиентов Java, есть также Redisson, который добавляет еще один уровень абстракции (Collection/Queue/Lock/... интерфейсы вместо необработанных команд Redis).
В значительной степени это зависит от того, как вы работаете с клиентами. В общем, Redis является однопоточным с точки зрения доступа к данным, поэтому единственное преимущество, которое вы получаете благодаря concurrency, - это разгрузка протокола и операций ввода-вывода на разные потоки. Это не совсем верно для салата и Redisson, поскольку они используют netty под капотом (netty связывает один канал сокета с конкретным потоком цикла событий).
С помощью Jedis вы можете использовать только одно соединение только с одним потоком за раз. Это хорошо согласуется с актерской моделью Akka, потому что один экземпляр актера занят только одним потоком за раз.
С другой стороны, вам нужно столько соединений Jedis, как потоки, которые касаются конкретного актера. Если вы начинаете совместное использование Jedis-подключений между разными участниками, вы либо отправляетесь на пул соединений, либо вам нужно иметь выделенное соединение Jedis для каждого актера. Имейте в виду, что вам необходимо позаботиться о повторном подключении (как только соединение Redis будет нарушено).
С Redisson и салатом вы получите прозрачное пересоединение, если хотите это сделать (это значение по умолчанию для салата, не уверенное в Redisson).
Используя lettuce и Redisson, вы можете поделиться одним соединением между всеми участниками, потому что они потокобезопасны. Вы не можете поделиться одним соединением салата в двух случаях:
- Операции блокировки (поскольку вы заблокировали всех других пользователей соединения)
- Транзакции (
MULTI
/EXEC
, так как вы будете смешивать разные операции с транзакциями, и это, безусловно, то, чего вы не хотите делать)
Jedis не имеет асинхронного интерфейса, поэтому вам необходимо сделать это самостоятельно. Это выполнимо, и я сделал что-то подобное с MongoDB, разгружая/разделяя часть ввода/вывода на других участников. Вы можете использовать этот подход из своего кода, но вам не требуется предоставлять собственную службу исполнителя, потому что вы выполняете неблокирующие операции в исполняемом слушателе.
С lettuce 4.0 вы получите поддержку Java 8 (что лучше с точки зрения асинхронного API из-за интерфейса CompletionStage), и вы даже можете использовать RxJava (реактивное программирование), чтобы приблизиться к concurrency.
Салат-латук не уверен в вашей модели concurrency. Он позволяет использовать его в соответствии с вашими потребностями, за исключением простого Future
/ListenableFuture
API Java 6/7 и Guava не очень приятно использовать.
HTH, Mark
Ответ 2
Попробуйте Redison framework. Он обеспечивает асинхронный API, а также API реактивных потоков, поддерживаемый путем интеграции с библиотеками Project Reactor и RxJava2.
Пример использования асинхронного 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) -> {
// ...
});
API реактивных потоков с использованием примера использования проекта Reactor:
RedissonReactiveClient client = Redisson.createReactive(config);
RMapReactive<String, String> map = client.getMap("myMap");
Mono<String> resp = map.get("myKey");
API реактивных потоков с использованием примера использования RxJava2:
RedissonRxClient client = Redisson.createRx(config);
RMapRx<String, String> map = client.getMap("myMap");
Flowable<String> resp = map.get("myKey");