J'utilise Redis avec Akka, je n'ai donc pas besoin de bloquer les appels. La laitue a un appel futur asynchrone intégré. Mais Jedis est le client recommandé par Redis. Quelqu'un peut-il me dire si je les utilise tous les deux correctement? Si oui, lequel est le meilleur?.
JEDIS J'utilise un pool de connexions Jedis statique pour obtenir un con et utilise le rappel ultérieur Akka pour traiter le résultat. Ma préoccupation ici est lorsque j’utilise un autre thread (appelable) pour obtenir le résultat que ce thread va finalement bloquer pour le résultat. Laitue pourrait avoir un moyen plus efficace de le faire.
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);
}
SALADE
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);
Si la laitue est une meilleure option pour les appels asynchrones. Ensuite, quel type d’exécuteur dois-je utiliser dans un environnement de production? Si possible, puis-je utiliser un répartiteur Akka en tant que contexte d'exécution pour un futur appel à Letture.
Il n’ya pas une réponse à votre question car cela dépend.
Jedis et la laitue sont tous deux des clients matures. Pour compléter la liste des clients Java, il existe également Redisson, qui ajoute une autre couche d’abstraction (interfaces Collection/Queue/Lock/... au lieu des commandes brutes Redis).
Cela dépend beaucoup de votre façon de travailler avec les clients. En règle générale, Redis ne dispose que d’un seul thread en termes d’accès aux données. Par conséquent, le seul avantage que vous obtenez en cas de simultanéité est de décharger le protocole et le travail d’E/S sur différents threads. Ce n'est pas tout à fait vrai pour la laitue et Redisson puisqu'ils utilisent netty sous le capot (netty lie un canal de socket à un fil de boucle d'événement particulier).
Avec Jedis, vous ne pouvez utiliser qu'une seule connexion avec un seul thread à la fois. Cela correspond bien au modèle d'acteur Akka car une instance d'acteur n'est occupée que par un thread à la fois.
De l'autre côté, vous avez besoin d'autant de connexions Jedis que de threads traitant d'un acteur particulier. Si vous commencez à partager des connexions Jedis entre différents acteurs, vous devez opter pour le regroupement de connexions ou vous devez disposer d'une connexion Jedis dédiée par instance d'acteur. N'oubliez pas que vous devez prendre en charge la reconnexion (une fois qu'une connexion Redis est rompue) par vous-même.
Avec Redisson et la laitue, vous obtenez une reconnexion transparente si vous le souhaitez (valeur par défaut de la laitue, vous n'êtes pas sûr de Redisson).
En utilisant la laitue et Redisson, vous pouvez partager une connexion entre tous les acteurs car ils sont thread-safe. Vous ne pouvez pas partager une connexion de laitue dans deux cas:
MULTI
/EXEC
, car vous pouvez mélanger différentes opérations avec les transactions et c'est certainement une chose que vous ne voulez pas faire)Jedis n'a pas d'interface asynchrone, vous devez donc le faire vous-même. C'est faisable et j'ai fait quelque chose de similaire avec MongoDB, en déchargeant/découplant la partie I/O à d'autres acteurs. Vous pouvez utiliser l'approche à partir de votre code, mais vous n'êtes pas obligé de fournir un service d'exécution propre, car vous effectuez des opérations non bloquantes dans le programme d'écoute pouvant être exécuté.
Avec lettuce 4.0, vous bénéficiez de la prise en charge de Java 8 (ce qui est bien meilleur en termes d’API asynchrone en raison de l’interface CompletionStage) et vous pouvez même utiliser RxJava (programmation réactive) pour faire face à la concurrence.
La laitue n'a pas d'opinion sur votre modèle de concurrence. Il vous permet de l'utiliser en fonction de vos besoins, à l'exception de l'API simple Future
/ListenableFuture
de Java 6/7 et de Guava n'est pas très agréable à utiliser.
HTH, Mark
Essayez le framework Redisson . Il fournit des API asynchrones ainsi que des API de flux réactifs pris en charge via l'intégration aux bibliothèques Project Reactor et RxJava2.
Exemple d'utilisation d'API asynchrone:
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 Reactive Streams avec exemple d’utilisation de la bibliothèque Project Reactor:
RedissonReactiveClient client = Redisson.createReactive(config);
RMapReactive<String, String> map = client.getMap("myMap");
Mono<String> resp = map.get("myKey");
API Reactive Streams avec exemple d’utilisation de la bibliothèque RxJava2:
RedissonRxClient client = Redisson.createRx(config);
RMapRx<String, String> map = client.getMap("myMap");
Flowable<String> resp = map.get("myKey");