-
Notifications
You must be signed in to change notification settings - Fork 386
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Habilita rate-limit em todas as rotas da API #715
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
@aprendendofelipe veja o que acha do commit 8621f5c junto desse PR. Fiz isso, pois enquanto eu estava navegando pela paginação, o negócio estava sofrido. O banco estava furioso demais fechando as conexões e isto atrasa demais o trabalho dos estáticos em |
Bora! É aquilo que já conversamos. Ficar encerrando as conexões de Lambdas acordadas causa um efeito cascata de perda de performance, pois cada request irá demorar mais para ser respondida (por necessitar estabelecer nova conexão), o que exige mais lambdas rodando paralelamente, o que aumenta a quantidade de conexões ativas, o que força novas conexões a serem encerradas e por aí vai... |
Uma sugestão para testar também é diminuir o intervalo entre as 5 tentativas de conexão ao banco. Hoje está assim: async function tryToGetNewClientFromPool() {
const clientFromPool = await retry(newClientFromPool, {
retries: 5,
minTimeout: 1000,
factor: 2,
});
... Por causa do Sugiro testar o seguinte: const configurations = {
...
connectionTimeoutMillis: 500 async function tryToGetNewClientFromPool() {
const clientFromPool = await retry(newClientFromPool, {
retries: 5,
minTimeout: 150,
maxTimeout: 1000,
factor: 2,
});
... Com isso é esperado que todas as 5 tentativas ocorram randomicante em no máximo 6,4s. Passado esse tempo sem sucesso na conexão, então a request irá retornar o erro de timeout de conexão com o banco de dados, ao invés de ocorrer o timeout da lambda e a request ficar sem resposta. Isso só vai ocorrer quando o banco não estiver aceitando conexões, então a liberação mais rápida da lambda irá evitar que novas lambdas subam paralelamente e afoguem ainda mais o banco de dados. |
8621f5c
to
6383b2b
Compare
Show @aprendendofelipe 😍 apliquei isso junto do commit 6383b2b |
Hmm... bizarro, ta dando erro de timeout:
URL fixa para testar: https://tabnews-2d31js0xn-tabnews.vercel.app/ |
6383b2b
to
9227826
Compare
Mudei um pouco os valores: 9227826 Agora está indo: https://tabnews-d73obab3r-tabnews.vercel.app/ E seria muito legal a Vercel para Preview conseguir subir as lambdas em uma região e para Production em outra. É muito ruim trabalhar em Preview, muita distância entre o banco e lambda que ele chora: Mas ta consumindo bem a quantidade de conexões, e isso é ótimo 👍 |
Merged! Let's goooooo! Vou ficar acompanhando aqui 👍 |
Tava pensando aqui @aprendendofelipe se não seria uma boa ideia habilitar o rate limit em tudo... e por tudo eu digo páginas estáticas e |
Vamos pensar aqui...
Sobre aquele monte de timeout que deu, os 500ms para o Já a mudança no
Você diz deixar isso configurado definitivamente, né? Pra não precisar trocar a região no vercel.json de gru para iad1? |
Pensando no gap que existe entre o limite de conexões do banco e a quantidade de lambdas que podem ser executas ao mesmo tempo, que tal a gente usar um pool de verdade? Por exemplo, colocar o PgBouncer em uma instância na AWS na mesma rede que o Postgres para proteger o banco e aumentar a quantidade de lambdas que podem ficar conectadas ao mesmo tempo se revezando nas conexões do PgBouncer com o Postgres. Considerando o fluxo atual, acredito que o custo seria equivalente ao de colocar o UpStash na frente de tudo, mas é uma solução mais robusta e que escala bem melhor. Algumas vantagens do PgBouncer:
Segue uma fonte com informações relacionadas: |
Para esse caso não seria IP vs Endpoint e deveria só IP mesmo para cair no limite global
Isso! Para termos o comportamento de latência bem próximo ao de Produção 😍
Curto total a ideia!!! No artigo que você apontou, destaco isso:
Muito massa 😍 lembro que no começo do TabNews a gente tinha escolhido o Digital Ocean porque eles oferecem a instalação do PgBouncer com "1 click". De quaquer forma, eu trataria a proteção por ataque separadamente do banco por causa de um detalhe: processamento. A nossa instância hoje é muito fraca nesse quesito e deixar o atacante chegar no pool, depois no banco e ter que pegar o estado do limite lá vai constantemente consumir todo o processamento do banco eu imagino. Talvez seja interessante alguma outra peça receber primeiro essa carga (no caso hoje o Upstash, mas pode ser qualquer outra coisa) e ela decidir ou não repassar a request em diante. |
Massa e fácil demais! Pena esse limite de 20 conexões! > However, these PgBouncer pool connections are currently limited to 20 per database. E isso que você destacou 🚀🚀🚀
Estarei bastante ocupado nessa semana, mas depois posso criar uma instância na AWS para fazermos testes.
Sem dúvidas o pool não é solução para todos os problemas e definitivamente não é solução para um ataque. Mas é algo que pode nos fazer suportar um volume de acesso esporádico acima do comum (como aqui #735) sem precisar lidar com isso como se fosse um ataque. E talvez dê para deixar para a Vercel lidar com um ataque de verdade que esteja explorando a geração de páginas estáticas. Já o rate-limit fica principalmente para lidar com abusos do serviço e menos preocupado em proteger o banco. Até porque o rate-limit precisa ser bem mais limitante do que a capacidade do sistema.
Usar a Edge e o Upstash como rate-limit (ou qualquer outra limitação) para as páginas estáticas me parece com um rabo balançando o cachorro... hehe... Mas sim, não há dúvidas que funcionaria até certo ponto! Mas me parece que cria mais problemas do que soluções. Por exemplo, estaremos criando alguns limites de acessos simultâneos para as páginas estáticas (1000 por segundo do UpStash e 950 simultâneos da Edge). Na prática esse limite seria ainda menor, pois seria dividido com a API. E em caso de ataque que atinja esse limite, nenhum usuário conseguirá acessar nem mesmo as páginas estáticas. E se criar alguma forma de transbordo para quando atingir esses limites o acesso acontecer sem passar pelo rate-limit, aí o atacante pode explorar isso e não existirá rate-limit nenhum. Falando especificamente de um ataque por tentativa de geração de páginas estáticas inválidas. Uma maneira de lidar com isso pode ser criando no PostgreSQL um usuário diferente para ser utilizado pelas lambdas responsáveis pela API e outro para as lambdas que geram os conteúdos estáticos. Com isso dá pra definir Mas também podemos fazer qualquer outro limite entre as lambdas e o banco, mas que não limite de forma alguma o acesso aos estáticos já gerados em cache na Vercel. |
@filipedeschamps, temos a alternativa de migrar de funções sem servidor para funções de borda (beta). Só precisamos testar se todos os endpoints podem ser migrados, pois a Edge Runtime tem algumas limitações como tempo de CPU e de execução e as APIs aceitas. Também é bom considerarmos que as funções de borda ainda estão em beta e, por isso, ainda não tem custos. A princípio as funções de borda rodam mais próximo do client, mas podemos configurar regiões específicas, então dá pra fazer serem executadas na região do banco de dados, independentemente de onde está o client. E podemos utilizar diferentes regiões para Preview e Production, de acordo com as variáveis de ambiente. Se achar interessante eu abro um PR. |
Que massa! Não sabia que dava para configurar a região pelo código, isso com a variável de ambiente para decidir onde rodar seria sensacional! Mas pelo que entendo a Edge não deixará usar o O que talvez eu faria, que não tem nada a ver com o assunto aqui, é entender como fazer para aceitar html como o GitHub faz, mas sem conseguir reconstruir os elementos gráficos da interface, como aconteceu aqui mas que por algum motivo não está mais funcionando, não entendi porque. Será que o @gabrielsozinho alterou o |
Verdade! Esqueci desse grande detalhe.
Não sei se entendi. Você diz aceitar menos do que é aceito hoje, ou seja, ficar mais restrito?
Acho que parou de funcionar quando atualizou as dependências |
Isso! Na verdade, aceitar tudo, porém mostrar filtrado.
Puts, é verdade, olha que louco: Antes: https://tabnews-hip4st1lb-tabnews.vercel.app/gsozinhos/teste E é realmente muito louco, porque foi atualizado essas dependências: https://github.com/filipedeschamps/tabnews.com.br/pull/773/files |
Eu acho que só parou de funcionar pq mudaram os nomes das classes que o @gabrielsozinho aproveitou. O que deve ter ocorrido por causa da atualização do |
Foi o nome das classes que mudou mesmo. Atualizei só a parte de "Responder" com a nova classe e voltou a funcionar na nova versão, ao mesmo tempo que parou de funcionar com a antiga. |
Após o maravilhoso PR #685 do @aprendendofelipe sugiro passarmos todas as rotas da API por dentro do rate-limit. Então atualizei os comentários para explicar a situação e fiz
skip
nos dois testes que quebram enquanto o Next.js não conserta esse bug: vercel/next.js#39262Meu racional foi otimizar para proteção dos endpoints em troca da "garantia" de que conseguimos criar e atualizar conteúdos com 20k caracteres. Coloquei "garantia" entre aspas, porque infelizmente não há garantia alguma nesse caso, uma vez que o Middleware está se comportando de uma forma em
development
e outra forma empreview
eproduction
.Em paralelo, caso seja necessário desproteger o ambiente de homologação para testes de carga, basta alterar o middleware em um commit temporário 🤝