O Redis (Remote Dictionary Server) é um armazenamento de valores-chave na memória imensamente popular que também oferece durabilidade opcional, particionamento, replicação e uma série de outros recursos. Atualmente, é o banco de dados de chave-valor mais popular e é conhecido por sua simplicidade, baixo consumo de memória e baixa curva de aprendizado. O Redis também é chamado de servidor de estrutura de dados e tem suporte para operações atômicas em estruturas de dados como hashes, listas, conjuntos, conjuntos classificados, bitmaps e hiperloglogs. Nesta postagem, veremos o tipo de dados definido fornecido pelo Redis, juntamente com seu uso e casos de uso da vida real.
Conjuntos Redis
Os conjuntos do Redis são coleções não ordenadas de strings (uma string é o valor básico do Redis que pode conter quase tudo) que fornece adição, remoção e verificações de associação em tempo constante. O Redis também suporta operações de união, interseção e subtração razoavelmente rápidas entre conjuntos. Como esperado, não permite valores repetidos.
Aqui estão alguns exemplos de conjuntos Redis em ação do redis-cli . Aqui está um resumo das principais representações no exemplo abaixo:
- usuários:todos representa um conjunto de todos os usuários registrados em um site.
- usuários:actv representa usuários ativos.
- usuários:inactv representa usuários inativos (usuários que não visitam o site há algum tempo).
# sadd key member [member ...] : add members to a set 127.0.0.1:6379> sadd users:all 11 12 13 14 15 Rocket Pocket Socket (integer) 8 127.0.0.1:6379> type users:all set # smembers key: get all members of a set 127.0.0.1:6379> smembers users:all 1) "Pocket" 2) "11" 3) "Socket" 4) "13" 5) "14" 6) "Rocket" 7) "12" 8) "15" # sismember key member: is the given value a member of the set? 127.0.0.1:6379> sismember users:all 00 (integer) 0 127.0.0.1:6379> sismember users:all 11 (integer) 1 127.0.0.1:6379> sismember users:all Socket (integer) 1 127.0.0.1:6379> sadd users:inactv 11 12 13 (integer) 3 # sinter key [key ...]: Intersection of multiple sets # Similar: sinterstore stores the result of intersection of sets to a new set 127.0.0.1:6379> sinter users:all users:inactv 1) "11" 2) "12" 3) "13" # scard key: cardinality of the set i.e. number of members present in the set 127.0.0.1:6379> scard users:all (integer) 8 # sdiff key [key ...] : Subtract multiple sets # Similar: sdiffstore: subtract and store result in a new destination set 127.0.0.1:6379> sdiff users:all 1) "Pocket" 2) "11" 3) "Socket" 4) "13" 5) "14" 6) "12" 7) "Rocket" 8) "15" 127.0.0.1:6379> sdiff users:all users:inactv 1) "14" 2) "Pocket" 3) "Rocket" 4) "Socket" 5) "15" # sdiffstore destination key [key ...] 127.0.0.1:6379> sdiffstore users:actv users:all users:inactv (integer) 5 127.0.0.1:6379> smembers users:actv 1) "14" 2) "Pocket" 3) "Rocket" 4) "Socket" 5) "15" 127.0.0.1:6379> sdiff users:all users:actv users:inactv (empty list or set) # smove source destination member: move a member from source set to destination. 127.0.0.1:6379> smove users:inactv users:actv 11 (integer) 1 127.0.0.1:6379> smembers users:actv 1) "Pocket" 2) "11" 3) "Socket" 4) "14" 5) "Rocket" 6) "15"
Outros comandos de conjunto importantes incluem:
- SUNION – união do conjunto
- SPOP – remove aleatoriamente um elemento
- SREM – remove um ou mais elementos
A lista completa de comandos Redis relacionados ao conjunto pode ser encontrada aqui.
Internos do Redis
O Redis armazena internamente conjuntos como dicionários. Os dicionários no Redis são implementados como tabelas de hash que usam a função de hash MurmurHash2 e crescem por meio de redimensionamento incremental. As colisões de hash são tratadas por encadeamento. Os conjuntos têm uma codificação especial para conjuntos pequenos quando todos os membros de um conjunto estão na raiz 10 no intervalo # de inteiros assinados de 64 bits chamados IntSets. Este é essencialmente um array ordenado de inteiros. As pesquisas dentro da matriz são realizadas por meio de pesquisa binária. Obviamente, esta implementação é eficiente para conjuntos muito pequenos. O tamanho até o qual esta codificação é usada é governado por set-max-intset-entries parâmetro de configuração. O valor padrão é 512. Uma boa descrição das estruturas de dados internas usadas pelo Redis pode ser encontrada aqui.
Aplicativos Redis
Aqui está uma pequena lista de alguns dos possíveis aplicativos do Redis Set:
- Como um conjunto, pode ser usado para rastrear itens exclusivos:
- Todos os endereços IP exclusivos que visitam seu site.
- Todas as instâncias de jobs exclusivas atualmente em um determinado estado etc.
- Novamente, como um conjunto, pode ser usado para denotar como “pertence a” ou relacionamento semelhante:
- Todos os SKUs pertencentes a uma categoria específica.
- Todos os objetos com uma tag específica etc.
- Os conjuntos só podem ser usados para combinar relacionamentos, ou seja, união/interseção/subtração de conjuntos:
- Todos os SKUs que pertencem à categoria de camisetas, mas não a uma subcategoria de golas polo.
Vamos pegar um exemplo da vida real e explorar ainda mais os casos de uso relacionados.
Visual Profiler para sua loja de e-books
Digamos que você seja o proprietário de uma grande livraria on-line que lista milhões de títulos. Seu banco de dados principal é o MongoDB e funciona razoavelmente bem para a maioria dos seus casos de uso com o uso correto de indexação, fragmentação, etc. Aqui está um esquema de documento de banco de dados parcial para os livros coleções:
... sku: SKU, pid: Product ID, title: String, auth: String, pub: String, isbn: ISBN, edition: Int, price: Float, rating: Float, cats: [String, String ...], tags: [String, String ...], ...
Você também registra transações em uma coleção chamada txns que pode parecer:
txnid: TxnID, cid: CustomerID, amnt: Float, curr: Currency, sku: [sku1, sku2, ...], time: TimeStamp, ...
E uma coleção de visualizações chamada visualizações:
time: TimeStamp, # daily aggregated cid: CustomerID, sku: [sku1, sku2, ...], ...
Obviamente, este é um exemplo altamente simplificado que faz suposições amplas. Nossa intenção é mostrar um exemplo do conjunto Redis em um cenário (quase) do mundo real.
Ok, agora você, como gerente da loja, deseja uma ferramenta Visual Profiler para analisar os relacionamentos e o comportamento do cliente em diferentes categorias. Por exemplo:
- Qual é a categoria mais popular?
- As pessoas que assistem ou compram ficção científica também veem não ficção?
Você deseja poder fazer isso em tempo real, ou seja, a interface do usuário do criador de perfil marcará caixas, botões que permitem alterar parâmetros e visualizar resultados (quase) imediatamente.
Fazer tais operações no MongoDB implicará realizar consultas bastante complicadas para juntar várias categorias, tags e outros dados que você possa se interessar. Com um conjunto de trabalho que não cabe na memória, essas não seriam as operações mais rápidas. Por exemplo:
- Encontrar todos os livros vendidos hoje que eram de ficção, mas não de ficção científica, envolverá consultar o txn coleção das transações de hoje. Em seguida, iterar sobre os SKUs para coletar suas categorias e, em seguida, realizar as operações $in/$nin.
Vamos ver como isso seria tratado trazendo o Redis para a mistura. No final de cada dia, os trabalhos agendados diariamente podem ser executados nessas coleções do MongoDB para criar conjuntos Redis. O tipo de conjunto que você deseja criar dependerá do tipo de filtro que deseja oferecer suporte em seu frontend. Por exemplo, digamos que você gostaria de oferecer suporte a consultas relacionadas a categorias, criaremos conjuntos como:
cat:type:catID cat:sku:fiction cat:sku:nonfiction cat:sku:scfiction cat:sku:history cat:sku:milhistory cat:sku:military ... cat:cid:fiction cat:cid:nonfiction cat:cid:scfiction cat:cid:history cat:cid:milhistory cat:cid:military ...
Os conjuntos cat:sku:* conterão SKUs de livros vendidos/visualizados hoje nessa categoria. Da mesma forma, cat:cid:* conterá o CID dos clientes que compraram/venderam livros nessa categoria. Uma amostra de consultas que podemos responder com esses conjuntos são:
- Clientes (ou # de clientes) que visualizaram/compraram livros de ficção (categoria única) hoje:smembers cat:cid:fiction
- Clientes que viram/compraram História, mas não História Militar hoje:sdiff cat:cid:history cat:cid:milhistory
- (Número de) livros vendidos hoje que eram de ficção científica e militar, ou seja, ficção científica militar:sinter cat:sku:scfiction cat:sku:military
- Qualquer número de operações de união, interseção e diferença de que você goste.
Isso por si só nos dá recursos de consulta muito poderosos. Vamos adicionar mais conjuntos! Digamos, criamos conjuntos adicionais com base nas classificações do livro. Por exemplo:
rat:sku:5str: Set of books with ratings > 4.5 rat:sku:4str: Set of books with ratings > 3.5 && <= 4.5 rat:sku:3str: ... rat:sku:2str: ... ... rat:cid:5str: Set of customer who bought books with ratings as mentioned above. rat:cid:4str: ... ..
Equipado com esses conjuntos, agora você pode descobrir rapidamente coisas como:
- Livros de ficção com classificação de 4 estrelas e acima comprados hoje: sunionstore rat:sku:4strabv rat:sku:5str rat:sku:5str/sinter rat:sku:4strabv cat :sku:ficção
- Cliente que comprou livros de 3 estrelas e acima na história:sunionstore rat:cid:5strabv rat:cid:3str rat:cid:5str rat:cid:5str/sinter cat:cid:history rat:cid:5strabv
Agora, digamos que você queira enviar um cupom de desconto para todos os clientes que compraram um livro de astrologia hoje com uma classificação igual ou inferior a 2 (como um pedido de desculpas pela experiência ruim de ter que ler aquele livro!). Você pode exportar essa lista de CustomerID s e envie-o para seu aplicativo de e-mail. Da mesma forma, você pode criar conjuntos para outras coisas que deseja expor como filtros em seu Visual Profiler, como tags, faixas de preço etc.
As vantagens de usar Redis Sets são óbvias aqui. O armazenamento na memória levará a um acesso realmente rápido, para que o frontend pareça ágil. Além disso, as operações de conjunto do Redis são de tempo constante ou linear.
Conclusão
Neste post, apresentamos com exemplos uma das estruturas de dados Redis mais úteis:conjuntos. Aqui estão algumas de nossas outras postagens na série de estruturas de dados do Redis:
- Redis Hashes
- Bitmaps do Redis
- Conjuntos Redis
- Conjuntos classificados do Redis