Lendo os números: Solid Cable contra Redis sob carga
O curso de nível Pleno "Solid Cable: escalando WebSockets" examinou a tabela solid_cable_messages desta aplicação em desenvolvimento. Ali, uma única aba do navegador, ao longo de algumas sessões, tinha escrito todas as linhas. Isso nunca precisou responder a uma pergunta mais difícil: o que acontece quando não é uma aba, e sim mil?
Não é preciso adivinhar. O repositório rails/solid_cable tem um diretório bench/ com uma pequena aplicação Rails, uma configuração de deploy e um script de teste de carga feito com o k6. A montagem segue um artigo da Evil Martians sobre testes de estresse com WebSockets. O bench/ não faz parte da gem instalada; a lista do pacote instalado não tem arquivos de bench/. Mas os mantenedores o rodaram num servidor, um Hetzner CCX13, com um número crescente de conexões WebSocket simuladas. Depois publicaram os números no README.md da gem, que vem instalado, em solid_cable-4.0.2/README.md. São os números da versão que está no Gemfile.lock desta aplicação, e não uma página de marketing.
O que o benchmark mede
Cada conexão simulada é um usuário virtual, ou VU: um WebSocket, inscrito e recebendo broadcasts, parecido com uma aba de navegador conectada à aplicação. O teste roda com 100, 250, 500 e 750 VUs e registra o RTT. É o tempo de ida e volta desde o broadcast de uma mensagem até um cliente inscrito recebê-la. Quanto menor, melhor. O relatório dá a média e os percentis p(90) e p(95), o RTT que 90% e 95% das mensagens superam. Eles importam mais que a média quando a pergunta é se a maioria dos usuários tem uma boa experiência, e não só o caso típico.
PostgreSQL com Solid Cable, contra Redis no mesmo host
Estes são os números da gem para o RTT médio, com PostgreSQL nos padrões do Solid Cable (polling_interval: 0.1.seconds, autotrim ligado) contra Redis na mesma máquina:
VUs Solid Cable (PG) Redis
100 137.45ms 68.95ms
250 151.63ms 69.32ms
500 362.79ms 87.50ms
Com 100 VUs, a latência do Solid Cable já é cerca do dobro da do Redis. Com 500 VUs, é mais de quatro vezes maior, enquanto o Redis quase não se mexe. Os 87 ms dele ficam perto o bastante do número de 100 VUs para chamar de estável. A diferença não é um bug nem uma configuração errada. É o custo de os dois adaptadores funcionarem de jeitos diferentes.
Por que as curvas se afastam
"Solid Cable: escalando WebSockets" mostrou a thread do listener: uma por processo do servidor, em laço eterno, dormindo o polling_interval (0,1 segundo por padrão) entre as passadas. A cada passada ela roda uma query, o scope broadcastable filtrado por canal e ordenado por id, para os canais com inscritos naquele processo. O custo dessa query depende de quanto há para conferir: mais canais inscritos e mais linhas escritas desde a última passada significam um resultado maior para percorrer. Conforme o número de VUs sobe, sobe o volume que cada passada atravessa, e o RTT sobe junto.
O SUBSCRIBE e o PUBLISH do Redis não têm esse passo. Não há tabela, intervalo nem query agendada. O Redis guarda os inscritos de cada canal em memória e empurra uma mensagem publicada para todos eles assim que ela chega. Não há laço de consulta cujo custo cresça com o que precisa conferir.
É essa a troca que este curso desmonta. O Solid Cable abre mão da curva quase plana do Redis em troca de um serviço a menos para manter, e os números publicados mostram a forma dessa troca.
Para onde o curso vai
- Aula 2: o adaptador vizinho, o
LISTEN/NOTIFYdo próprio PostgreSQL, que o Action Cable traz há tempos, e o limite rígido que decide se você pode usá-lo. - Aula 3: o
polling_interval, a única configuração que mexe diretamente na latência, e o custo dela. - Aula 4: o
autotrim, o que muda quando o volume de broadcasts sobe, e um detalhe do código da gem que uma leitura rápida do README perde. - Aula 5: o
connects_toe odatabase.ymlde produção desta aplicação, uma troca deliberada. - Aula 6: o que acontece quando você roda mais de um processo de servidor.
- Aula 7: o quadro inteiro, de onde os padrões do Solid Cable bastam até onde a resposta é outro adaptador.
No fim, você não vai escolher entre Solid Cable e Redis por fé. Vai saber que número troca por qual dependência.
Pontos-chave
- Os números vêm do teste de carga do próprio
bench/da gem, rodado com k6 num Hetzner CCX13 e publicado noREADME.mdinstalado dosolid_cable4.0.2. - Com 100 VUs, o Solid Cable no PostgreSQL tem, em média, cerca do dobro do tempo de ida e volta do Redis. Com 500 VUs, mais de quatro vezes.
- O RTT do Solid Cable sobe porque cada passada da consulta tem mais para conferir conforme canais e linhas crescem. O Redis empurra cada mensagem aos inscritos assim que ela chega.
- Um VU é uma conexão WebSocket simulada, inscrita e recebendo broadcasts.
Continue com a aula 2
O adaptador vizinho: o próprio LISTEN/NOTIFY do PostgreSQL
Compara o Solid Cable com o adaptador postgresql do Action Cable, que usa LISTEN/NOTIFY e limita payloads a quase 8 kB.
Com uma conta grátis você também tem os quizzes, seu progresso e suas anotações, e a discussão.