Antes de prosseguir, considere nos dar uma estrela do GitHub ️. Obrigado!
Outros idiomas: 简体中文 日本語 한국어
Site • Documentos • Início rápido • Discord da comunidade • Fórum Dragonfly • Junte-se à comunidade Dragonfly
Discussões do GitHub • Problemas do GitHub • Contribuições • Dragonfly Cloud
Dragonfly é um armazenamento de dados na memória criado para cargas de trabalho de aplicativos modernos.
Totalmente compatível com APIs Redis e Memcached, o Dragonfly não requer alterações de código para ser adotado. Em comparação com datastores legados na memória, o Dragonfly oferece 25 vezes mais rendimento, taxas de acerto de cache mais altas com menor latência final e pode ser executado com até 80% menos recursos para a carga de trabalho do mesmo tamanho.
Primeiro comparamos o Dragonfly com o Redis na instância m5.large
, que é comumente usada para executar o Redis devido à sua arquitetura de thread único. O programa de benchmark é executado a partir de outra instância de teste de carga (c5n) na mesma AZ usando memtier_benchmark -c 20 --test-time 100 -t 4 -d 256 --distinct-client-seed
Dragonfly mostra um desempenho comparável:
--ratio 1:0
):Redis | DF |
---|---|
QPS: 159K, P99,9: 1,16 ms, P99: 0,82 ms | QPS: 173K, P99,9: 1,26 ms, P99: 0,9 ms |
--ratio 0:1
):Redis | DF |
---|---|
QPS: 194K, P99,9: 0,8 ms, P99: 0,65 ms | QPS: 191K, P99,9: 0,95 ms, P99: 0,8 ms |
O benchmark acima mostra que a camada algorítmica dentro do DF que permite escalar verticalmente não tem um grande custo ao executar thread único.
No entanto, se tomarmos uma instância um pouco mais forte (m5.xlarge), a lacuna entre DF e Redis começa a crescer. ( memtier_benchmark -c 20 --test-time 100 -t 6 -d 256 --distinct-client-seed
):
--ratio 1:0
):Redis | DF |
---|---|
QPS: 190K, P99,9: 2,45 ms, P99: 0,97 ms | QPS: 279K, P99,9: 1,95 ms, P99: 1,48 ms |
--ratio 0:1
):Redis | DF |
---|---|
QPS: 220K, P99,9: 0,98 ms, P99: 0,8 ms | QPS: 305K, P99,9: 1,03 ms, P99: 0,87 ms |
A capacidade de transferência do Dragonfly continua a crescer com o tamanho da instância, enquanto o Redis de thread único tem gargalos na CPU e atinge máximos locais em termos de desempenho.
Se compararmos o Dragonfly e o Redis na instância c6gn.16xlarge com maior capacidade de rede, o Dragonfly mostrou um aumento de 25X na taxa de transferência em comparação com o processo único do Redis, ultrapassando 3,8 milhões de QPS.
Métricas de latência do 99º percentil do Dragonfly em seu pico de rendimento:
operação | r6g | c6gn | c7g |
---|---|---|---|
definir | 0,8ms | 1ms | 1ms |
pegar | 0,9ms | 0,9ms | 0,8ms |
setex | 0,9ms | 1,1ms | 1,3ms |
Todos os benchmarks foram realizados usando memtier_benchmark
(veja abaixo) com número de threads ajustados por servidor e tipo de instância. memtier
foi executado em uma máquina c6gn.16xlarge separada. Definimos o tempo de expiração em 500 para o benchmark SETEX para garantir que ele sobreviveria ao final do teste.
memtier_benchmark --ratio ... -t < threads > -c 30 -n 200000 --distinct-client-seed -d 256
--expiry-range=...
No modo pipeline --pipeline=30
, o Dragonfly atinge 10 milhões de QPS para operações SET e 15 milhões de QPS para operações GET.
Comparamos o Dragonfly com o Memcached em uma instância c6gn.16xlarge na AWS.
Com uma latência comparável, a taxa de transferência do Dragonfly superou a taxa de transferência do Memcached em cargas de trabalho de gravação e leitura. O Dragonfly demonstrou melhor latência em cargas de trabalho de gravação devido à contenção no caminho de gravação no Memcached.
Servidor | QPS (milhares de qps) | latência 99% | 99,9% |
---|---|---|---|
Libélula | ? 3844 | ? 0,9ms | ? 2,4ms |
Memcached | 806 | 1,6ms | 3,2ms |
Servidor | QPS (milhares de qps) | latência 99% | 99,9% |
---|---|---|---|
Libélula | ? 3717 | 1ms | 2,4ms |
Memcached | 2100 | ? 0,34ms | ? 0,6ms |
O Memcached exibiu menor latência para o benchmark de leitura, mas também menor rendimento.
Para testar a eficiência da memória, preenchemos o Dragonfly e o Redis com aproximadamente 5 GB de dados usando o comando debug populate 5000000 key 1024
, enviamos o tráfego de atualização com memtier
e iniciamos o snapshot com o comando bgsave
.
Esta figura demonstra como cada servidor se comportou em termos de eficiência de memória.
O Dragonfly foi 30% mais eficiente em termos de memória do que o Redis no estado inativo e não mostrou nenhum aumento visível no uso de memória durante a fase de snapshot. No pico, o uso de memória do Redis aumentou para quase 3 vezes o do Dragonfly.
O Dragonfly finalizou o snapshot mais rápido, em poucos segundos.
Para obter mais informações sobre eficiência de memória no Dragonfly, consulte nosso documento Dashtable.
O Dragonfly oferece suporte a argumentos comuns do Redis quando aplicável. Por exemplo, você pode executar: dragonfly --requirepass=foo --bind localhost
.
Atualmente, o Dragonfly oferece suporte aos seguintes argumentos específicos do Redis:
port
: porta de conexão Redis ( default: 6379
).bind
: Use localhost
para permitir apenas conexões localhost ou um endereço IP público para permitir conexões com esse endereço IP (ou seja, de fora também). Use 0.0.0.0
para permitir todo IPv4.requirepass
: A senha para autenticação AUTH ( default: ""
).maxmemory
: Limite de memória máxima (em bytes legíveis por humanos) usada pelo banco de dados ( default: 0
). Um valor maxmemory
de 0
significa que o programa determinará automaticamente seu uso máximo de memória.dir
: Dragonfly Docker usa a pasta /data
para instantâneo por padrão, a CLI usa ""
. Você pode usar a opção -v
Docker para mapeá-lo para sua pasta host.dbfilename
: O nome do arquivo para salvar e carregar o banco de dados ( default: dump
).Existem também alguns argumentos específicos do Dragonfly:
memcached_port
: a porta para ativar a API compatível com Memcached ( default: disabled
).
keys_output_limit
: Número máximo de chaves retornadas no comando keys
( default: 8192
). Observe que keys
é um comando perigoso. Truncamos seu resultado para evitar uma explosão no uso da memória ao buscar muitas chaves.
dbnum
: Número máximo de bancos de dados suportados para select
.
cache_mode
: Consulte a nova seção de design de cache abaixo.
hz
: Frequência de avaliação de expiração da chave ( default: 100
). A frequência mais baixa usa menos CPU quando ociosa, às custas de uma taxa de despejo mais lenta.
snapshot_cron
: Expressão de agendamento Cron para instantâneos de backup automáticos usando sintaxe cron padrão com granularidade de minutos ( default: ""
). Aqui estão alguns exemplos de expressões de agendamento cron abaixo e fique à vontade para ler mais sobre esse argumento em nossa documentação.
Expressão de agendamento Cron | Descrição |
---|---|
* * * * * | A cada minuto |
*/5 * * * * | A cada 5 minutos |
5 */2 * * * | No minuto 5 a cada 2 horas |
0 0 * * * | Às 00:00 (meia-noite) todos os dias |
0 6 * * 1-5 | Às 06:00 (madrugada) de segunda a sexta |
primary_port_http_enabled
: Permite acessar o console HTTP na porta TCP principal se true
( default: true
).
admin_port
: Para habilitar o acesso de administrador ao console na porta atribuída ( default: disabled
). Suporta protocolos HTTP e RESP.
admin_bind
: Para vincular a conexão TCP do console de administração a um determinado endereço ( default: any
). Suporta protocolos HTTP e RESP.
admin_nopass
: Para habilitar o acesso de administrador aberto ao console na porta atribuída, sem necessidade de token de autenticação ( default: false
). Suporta protocolos HTTP e RESP.
cluster_mode
: modo cluster suportado ( default: ""
). Atualmente suporta apenas emulated
.
cluster_announce_ip
: o IP que os comandos do cluster anunciam ao cliente.
announce_port
: a porta que os comandos do cluster anunciam ao cliente e ao mestre de replicação.
./dragonfly-x86_64 --logtostderr --requirepass=youshallnotpass --cache_mode=true -dbnum 1 --bind localhost --port 6379 --maxmemory=12gb --keys_output_limit=12288 --dbfilename dump.rdb
Argumentos também podem ser fornecidos por meio de:
--flagfile <filename>
: O arquivo deve listar um sinalizador por linha, com sinais de igual em vez de espaços para sinalizadores de valor-chave. Não são necessárias aspas para valores de sinalizadores.DFLY_x
, onde x
é o nome exato do sinalizador, diferenciando maiúsculas de minúsculas. Para obter mais opções, como gerenciamento de logs ou suporte TLS, execute dragonfly --help
.
O Dragonfly atualmente suporta cerca de 185 comandos Redis e todos os comandos Memcached além de cas
. Quase no mesmo nível da API Redis 5, o próximo marco do Dragonfly será estabilizar a funcionalidade básica e implementar a API de replicação. Se houver um comando que você precisa e que ainda não foi implementado, abra um problema.
Para replicação nativa do Dragonfly, estamos projetando um formato de log distribuído que suportará velocidades mais altas em ordem de grandeza.
Seguindo o recurso de replicação, continuaremos adicionando comandos ausentes para APIs das versões 3 a 6 do Redis.
Consulte nossa Referência de Comandos para os comandos atuais suportados pelo Dragonfly.
O Dragonfly possui um algoritmo de cache único, unificado e adaptativo que é simples e eficiente em termos de memória.
Você pode ativar o modo de cache passando o sinalizador --cache_mode=true
. Uma vez ativado este modo, o Dragonfly irá despejar os itens com menor probabilidade de serem encontrados no futuro, mas apenas quando estiver próximo do limite maxmemory
.
Os intervalos de validade são limitados a aproximadamente 8 anos.
Prazos de expiração com precisão de milissegundos (PEXPIRE, PSETEX, etc.) são arredondados para o segundo mais próximo para prazos maiores que 2^28ms , que tem erro inferior a 0,001% e deve ser aceitável para intervalos grandes. Caso não seja adequado ao seu caso de uso, entre em contato ou abra um issue explicando seu caso.
Para diferenças mais detalhadas entre os prazos de expiração do Dragonfly e as implementações do Redis, veja aqui.
Por padrão, o Dragonfly permite acesso HTTP através de sua porta TCP principal (6379). Isso mesmo, você pode se conectar ao Dragonfly via protocolo Redis e via protocolo HTTP — o servidor reconhece o protocolo automaticamente durante o início da conexão. Vá em frente e experimente com seu navegador. O acesso HTTP atualmente não possui muitas informações, mas incluirá informações úteis de depuração e gerenciamento no futuro.
Vá para a URL :6379/metrics
para visualizar as métricas compatíveis com o Prometheus.
As métricas exportadas do Prometheus são compatíveis com o painel Grafana, veja aqui.
Importante! O console HTTP deve ser acessado em uma rede segura. Se você expor a porta TCP do Dragonfly externamente, recomendamos desabilitar o console com --http_admin_console=false
ou --nohttp_admin_console
.
O Dragonfly começou como um experimento para ver como seria a aparência de um armazenamento de dados na memória se fosse projetado em 2022. Com base nas lições aprendidas com nossa experiência como usuários de armazenamentos de memória e engenheiros que trabalharam para empresas de nuvem, sabíamos que precisávamos preservar dois propriedades principais do Dragonfly: Garantias de atomicidade para todas as operações e latência baixa, abaixo de um milissegundo, em uma taxa de transferência muito alta.
Nosso primeiro desafio foi como utilizar totalmente os recursos de CPU, memória e E/S usando servidores que estão disponíveis hoje em nuvens públicas. Para resolver isso, usamos a arquitetura shared-nothing, que nos permite particionar o espaço-chave do armazenamento de memória entre threads para que cada thread possa gerenciar sua própria fatia de dados do dicionário. Chamamos essas fatias de “fragmentos”. A biblioteca que alimenta o gerenciamento de thread e E/S para arquitetura sem compartilhamento é de código aberto aqui.
Para fornecer garantias de atomicidade para operações multichave, utilizamos os avanços de pesquisas acadêmicas recentes. Escolhemos o artigo "VLL: um redesenho do gerenciador de bloqueio para sistemas de banco de dados de memória principal" para desenvolver a estrutura transacional para Dragonfly. A escolha da arquitetura de nada compartilhado e VLL nos permitiu compor operações atômicas de múltiplas chaves sem usar mutexes ou spinlocks. foi um marco importante para nosso PoC e seu desempenho se destacou de outras soluções comerciais e de código aberto.
Nosso segundo desafio foi projetar estruturas de dados mais eficientes para a nova loja. Para atingir esse objetivo, baseamos nossa estrutura central de hashtable no artigo "Dash: Scalable Hashing on Persistent Memory". O artigo em si está centrado no domínio da memória persistente e não está diretamente relacionado aos armazenamentos da memória principal, mas ainda é mais aplicável ao nosso problema. O design da tabela hash sugerido no artigo nos permitiu manter duas propriedades especiais que estão presentes no dicionário Redis: A capacidade de hash incremental durante o crescimento do armazenamento de dados e a capacidade de percorrer o dicionário sob alterações usando uma operação de varredura sem estado. Além dessas duas propriedades, o Dash é mais eficiente no uso de CPU e memória. Aproveitando o design do Dash, conseguimos inovar ainda mais com os seguintes recursos:
Depois de construirmos a base para o Dragonfly e ficarmos satisfeitos com seu desempenho, implementamos a funcionalidade Redis e Memcached. Até o momento, implementamos cerca de 185 comandos Redis (aproximadamente equivalente à API Redis 5.0) e 13 comandos Memcached.
E finalmente,
Nossa missão é construir um armazenamento de dados na memória bem projetado, ultrarrápido e econômico para cargas de trabalho em nuvem que aproveite os mais recentes avanços de hardware. Pretendemos abordar os pontos fracos das soluções atuais, preservando as APIs e propostas de seus produtos.