Um guia para Redis com Redisson

Um guia para Redis com Redisson

1. Visão geral

Redisson is a Redis client for Java. Neste artigo, exploraremos alguns de seus recursos e demonstraremos como isso poderia facilitar a criação de aplicativos de negócios distribuídos.

Redisson constitutes an in-memory data grid que oferece objetos e serviços Java distribuídos com o suporte do Redis. Seu modelo de dados na memória distribuído permite o compartilhamento de objetos de domínio e serviços entre aplicativos e servidores.

Este artigo nos guiará sobre como configurar o Redisson, entender como ele funciona e explorar alguns dos objetos e serviços do Redisson.

2. Dependências do Maven

Vamos começar importandoRedisson para o nosso projeto, adicionando a seção abaixo ao nossopom.xml:


    org.redisson
    redisson
    3.3.0

A versão mais recente desta dependência pode ser encontradahere.

3. Configuração

Antes de começarmos, precisamos garantir que temos a versão mais recente da instalação e execução do Redis. Se você não tem Redis e usa Linux ou Macintosh, pode seguir as informaçõeshere para configurá-lo. Se você for um usuário do Windows, poderá configurar o Redis usando esteport não oficial.

Precisamos configurar o Redisson para se conectar ao Redis. O Redisson suporta conexões com as seguintes configurações do Redis:

  • Nó único

  • Mestre com nós escravos

  • Nós Sentinel

  • Nós em cluster

  • Nós replicados

Redisson supports Amazon Web Services (AWS) ElastiCache Cluster and Azure Redis Cache para nós agrupados e replicados.

Vamos nos conectar a uma única instância de nó do Redis. Esta instância está sendo executada localmente na porta padrão, 6379:

RedissonClient client = Redisson.create();

Você pode passar diferentes configurações para o métodocreate do objetoRedisson. Podem ser configurações para conectar-se a uma porta diferente ou, talvez, para conectar-se a um cluster Redis. Esteconfiguration could be in Java code or loaded from an external configuration file.

3.1. Configuração Java

Vamos configurar o Redisson no código Java:

Config config = new Config();
config.useSingleServer()
  .setAddress("127.0.0.1:6379");

RedissonClient client = Redisson.create(config);

Nósspecify Redisson configurations in an instance of a Config objecte passamos para o métodocreate. Acima, especificamos ao Redisson que queremos conectar a uma instância de nó único do Redis. Para fazer isso, usamos o métodouseSingleServer do objetoConfig. Isso retorna uma referência a um objetoSingleServerConfig.

O objetoSingleServerConfig possui configurações que o Redisson usa para se conectar a uma única instância de nó do Redis. Aqui, usamos seu métodosetAddress para definir a configuraçãoaddress. Isso define o endereço do nó ao qual estamos nos conectando. Algumas outras configurações incluemretryAttempts,connectionTimeout eclientName. Essas configurações são definidas usando seus métodos de setter correspondentes.

Podemos configurar o Redisson para diferentes configurações do Redis de maneira semelhante, usando os seguintes métodos do objetoConfig:

  • useSingleServer - para instância de nó único. Obter configurações de nó únicohere

  • useMasterSlaveServers - para mestre com nós escravos. Obter configurações de nó mestre-escravohere

  • useSentinelServers - para nós sentinela. Obtenha as configurações do nó sentinelahere

  • useClusterServers - para nós agrupados. Obter configurações de nó em clusterhere

  • useReplicatedServers - para nós replicados. Obter configurações de nó replicadohere

3.2. Configuração de arquivo

Redisson can load configurations from external JSON or YAML arquivos:

Config config = Config.fromJSON(new File("singleNodeConfig.json"));
RedissonClient client = Redisson.create(config);

O métodofromJSON do objetoConfig pode carregar configurações de uma string, arquivo, fluxo de entrada ou URL.

Aqui está o exemplo de configuração no arquivosingleNodeConfig.json:

{
    "singleServerConfig": {
        "idleConnectionTimeout": 10000,
        "pingTimeout": 1000,
        "connectTimeout": 10000,
        "timeout": 3000,
        "retryAttempts": 3,
        "retryInterval": 1500,
        "reconnectionTimeout": 3000,
        "failedAttempts": 3,
        "password": null,
        "subscriptionsPerConnection": 5,
        "clientName": null,
        "address": "redis://127.0.0.1:6379",
        "subscriptionConnectionMinimumIdleSize": 1,
        "subscriptionConnectionPoolSize": 50,
        "connectionMinimumIdleSize": 10,
        "connectionPoolSize": 64,
        "database": 0,
        "dnsMonitoring": false,
        "dnsMonitoringInterval": 5000
    },
    "threads": 0,
    "nettyThreads": 0,
    "codec": null,
    "useLinuxNativeEpoll": false
}

Aqui está um arquivo de configuração YAML correspondente:

singleServerConfig:
    idleConnectionTimeout: 10000
    pingTimeout: 1000
    connectTimeout: 10000
    timeout: 3000
    retryAttempts: 3
    retryInterval: 1500
    reconnectionTimeout: 3000
    failedAttempts: 3
    password: null
    subscriptionsPerConnection: 5
    clientName: null
    address: "redis://127.0.0.1:6379"
    subscriptionConnectionMinimumIdleSize: 1
    subscriptionConnectionPoolSize: 50
    connectionMinimumIdleSize: 10
    connectionPoolSize: 64
    database: 0
    dnsMonitoring: false
    dnsMonitoringInterval: 5000
threads: 0
nettyThreads: 0
codec: ! {}
useLinuxNativeEpoll: false

Podemos definir outras configurações do Redis a partir de um arquivo de maneira semelhante, usando configurações peculiares a essa configuração. Para sua referência, veja os formatos de arquivo JSON e YAML:

Para salvar uma configuração Java no formato JSON ou YAML, podemos usar os métodostoJSON outoYAML do objetoConfig:

Config config = new Config();
// ... we configure multiple settings here in Java
String jsonFormat = config.toJSON();
String yamlFormat = config.toYAML();

Agora que sabemos como configurar o Redisson, vamos ver como o Redisson executa as operações.

4. Operação

Redisson supports synchronous, asynchronous and reactive interfaces. Operações nessesinterfaces are thread-safe.

Todas as entidades (objetos, coleções, bloqueios e serviços) geradas por aRedissonClient têm métodos síncronos e assíncronos. Synchronous methods bear asynchronous variants. Esses métodos normalmente possuem o mesmo nome de método de suas variantes síncronas anexadas com "Async". Vejamos um método síncrono do objetoRAtomicLong:

RedissonClient client = Redisson.create();
RAtomicLong myLong = client.getAtomicLong('myLong');

A variante assíncrona do métodocompareAndSet síncrono seria:

RFuture isSet = myLong.compareAndSetAsync(6, 27);

A variante assíncrona do método retorna um objetoRFuture. Podemos definir ouvintes nesse objeto para recuperar o resultado quando ele estiver disponível:

isSet.handle((result, exception) -> {
    // handle the result or exception here.
});

Para gerar objetos reativos, precisaríamos usar oRedissonReactiveClient: `++`

RedissonReactiveClient client = Redisson.createReactive();
RAtomicLongReactive myLong = client.getAtomicLong("myLong");

Publisher isSetPublisher = myLong.compareAndSet(5, 28);

Este método retorna objetos reativos com base no padrãoReactive Streams para Java 9.

Vamos explorar alguns dos objetos distribuídos fornecidos pelo Redisson.

5. Objetos

Uma instância individual de aRedisson object is serialized and stored in any of the available Redis nodes backing Redisson. Esses objetos podem ser distribuídos em um cluster por vários nós e podem ser acessados ​​por um único aplicativo ou vários aplicativos / servidores.

Esses objetos distribuídos seguem as especificações dejava.util.concurrent.atomic package.They support lock-free, thread-safe and atomic operations on objects stored in Redis. A consistência dos dados entre aplicativos / servidores é garantida, pois os valores não são atualizados enquanto outro aplicativo está lendo o objeto.

Os objetos Redisson estão vinculados às teclas Redis. Podemos gerenciar essas chaves por meio da interfaceRKeys. Acessamos nossos objetos Redisson usando essas chaves.

Podemos obter todas as chaves:

RKeys keys = client.getKeys();

Podemos extrair todos os nomes de chave como coleções de seqüências iteráveis:

Iterable allKeys = keys.getKeys();

Podemos obter chaves em conformidade com um padrão:

Iterable keysByPattern = keys.getKeysByPattern('key*')

A interface RKeys também permite excluir chaves, excluir chaves por padrão e outras operações úteis baseadas em chaves que poderíamos usar para gerenciar nossas chaves e objetos.

Os objetos distribuídos fornecidos pelo Redisson incluem:

  • ObjectHolder

  • BinaryStreamHolder

  • GeospatialHolder

  • BitSet

  • AtomicLong

  • AtomicDouble

  • Tema

  • BloomFilter

  • HyperLogLog

Vamos dar uma olhada em três desses objetos:ObjectHolder, AtomicLong,eTopic.

5.1. Titular do objeto

Representado pela classeRBucket, este objeto pode conter qualquer tipo de objeto. Este objeto tem um tamanho máximo de 512 MB:

RBucket bucket = client.getBucket("ledger");
bucket.set(new Ledger());
Ledger ledger = bucket.get();

O objetoRBucket pode realizar operações atômicas comocompareAndSet andgetAndSet em objetos que contém.

5.2. AtomicLong

Representado pela classeRAtomicLong, este objeto se assemelha muito à classejava.util.concurrent.atomic.AtomicLong e representa um valorlong que pode ser atualizado atomicamente:

RAtomicLong atomicLong = client.getAtomicLong("myAtomicLong");
atomicLong.set(5);
atomicLong.incrementAndGet();

5.3. Tema

O objetoTopic suporta o mecanismo de “publicação e assinatura” do Redis. Para ouvir as mensagens publicadas:

RTopic subscribeTopic = client.getTopic("example");
subscribeTopic.addListener(
  (channel, customMessage)
  -> future.complete(customMessage.getMessage()));

Acima, oTopic está registrado para ouvir as mensagens do canal “exemplo”. Em seguida, adicionamos um ouvinte ao tópico para lidar com as mensagens recebidas desse canal. Podemos adicionar vários ouvintes a um canal.

Vamos publicar mensagens no canal “exemplo”:

RTopic publishTopic = client.getTopic("example");
long clientsReceivedMessage
  = publishTopic.publish(new CustomMessage("This is a message"));

Isso pode ser publicado a partir de outro aplicativo ou servidor. O objetoCustomMessage será recebido pelo ouvinte e processado conforme definido no métodoonMessage.

Podemos aprender mais sobre outros objetos Redissonhere.

6. Colecções

Lidamos com coleções Redisson da mesma maneira que lidamos com objetos.

As coleções distribuídas fornecidas pela Redisson incluem:

  • Map

  • Multimap

  • Set

  • SortedSet

  • ScoredSortedSet

  • LexSortedSet

  • List

  • Fila

  • Deque

  • BlockingQueue

  • BoundedBlockingQueue

  • BlockingDeque

  • BlockingFairQueue

  • DelayedQueue

  • Fila de prioridade

  • PriorityDeque

Vamos dar uma olhada em três dessas coleções:Map, Set,eList.

6.1. Map

Mapas baseados em redisson implementam as interfacesjava.util.concurrent.ConcurrentMapejava.util.Map. Redisson tem quatro implementações de mapas. Estes sãoRMap,RMapCache,RLocalCachedMapeRClusteredMap.

Vamos criar um mapa com Redisson:

RMap map = client.getMap("ledger");
Ledger newLedger = map.put("123", new Ledger());map

RMapCache suporta despejo de entrada de mapa. RLocalCachedMap permite o armazenamento em cache local das entradas do mapa. RClusteredMap permite que os dados de um único mapa sejam divididos entre os nós mestres do cluster Redis.

Podemos aprender mais sobre mapas de Redissonhere.

6.2. Set

Set baseado em redisson implementa a interfacejava.util.Set.

O Redisson tem três implementaçõesSet,RSet,RSetCache eRClusteredSet com funcionalidade semelhante às suas contrapartes no mapa.

Vamos criar umSet com Redisson:

RSet ledgerSet = client.getSet("ledgerSet");
ledgerSet.add(new Ledger());

Podemos aprender mais sobre conjuntos de Redissonhere.

6.3. List

Lists baseado em redisson implementa a interfacejava.util.List.

Vamos criar umList com Redisson:

RList ledgerList = client.getList("ledgerList");
ledgerList.add(new Ledger());

Podemos aprender mais sobre outras coleções de Redissonhere.

7. Bloqueios e sincronizadores

distributed locks allow for thread synchronization de Redisson em aplicativos / servidores. A lista de bloqueios e sincronizadores do Redisson inclui:

  • Lock

  • FairLock

  • MultiLock

  • ReadWriteLock

  • Semáforo

  • PermitExpirableSemaphore

  • CountDownLatch

Vamos dar uma olhada emLock eMultiLock.

7.1. Lock

Lock do Redisson implementa a interfacejava.util.concurrent.locks.Lock.

Vamos implementar um bloqueio, representado pela classeRLock:

RLock lock = client.getLock("lock");
lock.lock();
// perform some long operations...
lock.unlock();

7.2. MultiLock

ORedissonMultiLock do Redisson agrupa vários objetosRLock e os trata como um único bloqueio:

RLock lock1 = clientInstance1.getLock("lock1");
RLock lock2 = clientInstance2.getLock("lock2");
RLock lock3 = clientInstance3.getLock("lock3");

RedissonMultiLock lock = new RedissonMultiLock(lock1, lock2, lock3);
lock.lock();
// perform long running operation...
lock.unlock();

Podemos aprender mais sobre outros bloqueioshere.

8. Serviços

Redisson expõe 4 tipos de serviços distribuídos. São eles:Remote Service,Live Object Service,Executor ServiceeScheduled Executor Service. Vejamos o Remote Service e o Live Object Service.

8.1. Serviço Remoto

Este serviço forneceJava remote method invocation facilitated by Redis. Um serviço remoto Redisson consiste em uma implementação do lado do servidor (instância do trabalhador) e do lado do cliente. A implementação do lado do servidor executa um método remoto chamado pelo cliente. As chamadas de um serviço remoto podem ser síncronas ou assíncronas.

O lado do servidor registra uma interface para chamada remota:

RRemoteService remoteService = client.getRemoteService();
LedgerServiceImpl ledgerServiceImpl = new LedgerServiceImpl();

remoteService.register(LedgerServiceInterface.class, ledgerServiceImpl);

O lado do cliente chama um método da interface remota registrada:

RRemoteService remoteService = client.getRemoteService();
LedgerServiceInterface ledgerService
  = remoteService.get(LedgerServiceInterface.class);

List entries = ledgerService.getEntries(10);

Podemos aprender mais sobre os serviços remotoshere.

8.2. Live Object Service

Os Redisson Live Objects estendem o conceito de objetos Java padrão que só podem ser acessados ​​de uma única JVM paraenhanced Java objects that could be shared between different JVMs in different machines. Isso é feito mapeando os campos de um objeto para um hash Redis. Esse mapeamento é feito por meio de uma classe proxy construída em tempo de execução. Os getters e setters de campo são mapeados para os comandos Redis hget / hset.

O Redisson Live Objects suporta o acesso a campos atômicos como resultado da natureza de thread único do Redis.

Criar um objeto ao vivo é simples:

@REntity
public class LedgerLiveObject {
    @RId
    private String name;

    // getters and setters...
}

Anotamos nossa classe com@REntitye um campo único ou de identificação com@RId. Depois de fazer isso, podemos usar nosso Live Object em nosso aplicativo:

RLiveObjectService service = client.getLiveObjectService();

LedgerLiveObject ledger = new LedgerLiveObject();
ledger.setName("ledger1");

ledger = service.persist(ledger);

Criamos nosso Live Object como objetos Java padrão usando a palavra-chavenew. Em seguida, usamos uma instância deRLiveObjectService para salvar o objeto no Redis usando seu métodopersist.

Se o objeto já foi persistido no Redis, podemos recuperá-lo:

LedgerLiveObject returnLedger
  = service.get(LedgerLiveObject.class, "ledger1");

UsamosRLiveObjectService para obter nosso Objeto Live usando o campo anotado com@RId.

Podemos aprender mais sobre Redisson Live Objectshere.

Também podemos aprender mais sobre outros serviços Redissonhere.

9. Pipelining

Redisson suporta pipelining. Multiple operations can be batched as a single atomic operation. Isso é facilitado pela classeRBatch. Vários comandos são agregados a uma instância de objetoRBatch antes de serem executados:

RBatch batch = client.createBatch();
batch.getMap("ledgerMap").fastPutAsync("1", "2");
batch.getMap("ledgerMap").putAsync("2", "5");

List result = batch.execute();

10. Script

Redisson suporta scripts LUA. We can execute LUA scripts against Redis:

client.getBucket("foo").set("bar");
String result = client.getScript().eval(Mode.READ_ONLY,
  "return redis.call('get', 'foo')", RScript.ReturnType.VALUE);

11. Cliente de baixo nível

É possível que desejemos executar operações Redis ainda não suportadas pelo Redisson. Redisson provides a low-level client that allows execution of native Redis commands:

RedisClient client = new RedisClient("localhost", 6379);
RedisConnection conn = client.connect();
conn.sync(StringCodec.INSTANCE, RedisCommands.SET, "test", 0);

conn.closeAsync();
client.shutdown();

O cliente de baixo nível também suporta operações assíncronas.

12. Conclusão

Este artigo apresentou o Redisson e alguns dos recursos que o tornam ideal para o desenvolvimento de aplicativos distribuídos. Exploramos seus objetos distribuídos, coleções, bloqueios e serviços. Também exploramos alguns de seus outros recursos, como pipelining, scripts e seu cliente de baixo nível.

Redisson also provides integration with other frameworks como a API JCache, Spring Cache, Hibernate Cache e Spring Sessions. Podemos aprender mais sobre sua integração com outros frameworkshere.

Você pode encontrar exemplos de código emGitHub project.