Подтвердить что ты не робот

Ассистские способности 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.

4b9b3361

Ответ 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");