Se uma API estiver implementada corretamente, o número de usuários acessando o serviço pode ser inesperado. Milhões de usuários e dispositivos se conectam à internet todo dia, utilizando APIs para converter mídia, construir cidades inteligentes, efetuar cálculos fitness, e até ajudar no tratamento de câncer.
O sonho do desenvolvedor da API se tornou realidade, mas também pode se tornar um pesadelo! O sonho é ter a API mais popular, o melhor serviço possível e encarar taxas crescentes de adoção. E o pesadelo? Conforme cresce o número legítimo de usuários e chamadas ao sistema da API, também aumenta o número de acessos e chamadas ilegítimas feitas à API.
E como o desenvolvedor consegue conter essa avalanche de requisições na API? Colocar limites de requisições na API é uma solução incrível, e quando feita corretamente, corrige muitos dos problemas inerentes às grandes bases de usuários.
O que é o Limite de Requisição?
Uma analogia simples para contextualizar esse fundamento da arquitetura de API é comparar a API a uma cidade moderna. A cidade tem alguns recursos (lojas de serviços), e esses recursos são conectados uns com os outros através das ruas. As ruas possuem limitações físicas (na quantidade de faixas aonde cabem os carros) e também limitações de segurança (como as placas de velocidades, radares, semáforos, lombadas).
Da mesma forma, os recursos oferecidos pelas APIs precisam oferecer as mesmas limitações. Ao desenvolver uma API, o desenvolvedor precisa considerar as limitações físicas do sistema, que são a largura de banda da internet, o número de conexões simultâneas que podem ser roteadas e que o servidor suporta além da quantidade de dados que podem ser transferidos entre o sistema e os usuários. Prevenir que o limite de segurança seja ultrapassado irá prevenir acidentes, assim como nas ruas!
Do ponto de vista dos negócios, a técnica de limitação irá fazer que os clientes com um alto volume de requisições tenham que pagar por um plano adequado, habilitando vários níveis de acesso com valores compatíveis às demandas utilizadas.
O limite de requisição é o processo pelo qual a API recusa requisições por uma variedade de motivos, que englobam desde muitas requisições em um curto espaço de tempo, à requisições variadas ou suspeitas de fraude como por exemplo, a mesma chave sendo utilizada por três IPs simultaneamente. Ao implementar um limite o desenvolvedor instala uma torneira, que pode ser aberta ou fechada, permitindo um maior ou menor fluxo pelo sistema.
Além disso, podemos considerar o limite de requisições como um recurso de segurança no escopo dos fundamentos de segurança de redes (Confidencialidade, Integridade e Disponibilidade). Garantindo que o sistema não fique indisponível pela sobrecarga das requisições a API permanece disponível para todos os usuários.
Finalmente, um dos grandes benefícios do limite de requisições para os negócios é o fato de que impor esse limite requer a implementação de análises e métricas, que são ferramentas importantes para gerir a sua API.
3 Tipos de Limite de Requisições em APIs
Limitar requisições é uma arte, não uma ciência. Existem diversas formas de controlar os acessos, sempre que possível escolha os limites dinâmicos ao invés de utilizar regras genéricas e fixas, cujas exceções podem se tornar um problema a longo prazo. Esses são os tipos de limites utilizados:
Limitações por usuário. Esses limites são atrelados diretamente à chave API do usuário. Depois de uma determinada quantidade de requisições as requisições subsequentes são negadas, e depois de um determinado período de tempo esse contador é reiniciado, permitindo novas requisições.
Limitações por serviço. São uma boa escolha também, definindo taxas em serviços específicos os desenvolvedores garantem que serviços de uso comum (como os de login) consigam lidar com uma quantidade muito maior de requisições do que outros serviços diversos.
Limitações geográficas. É especialmente útil quando implementado com base em comportamentos. Por exemplo, o desenvolvedor sabe que o número de requisições ao serviço durante o meio dia no Brasil é maior do que durante as duas da manhã, e qualquer comportamento contrário a esse é um bom motivo para sugerir uma atividade suspeita. Limitando as regiões demográficas em seu período de baixa utilização pode prevenir ataques de negação de serviço (DDOS).
Considerações de Negócios
Enquanto poderia se argumentar que as limitações de acesso têm um efeito amortizador entre os usuários e os sistemas comerciais, essa é uma visão contrária do que pode ser esperado, a limitação pode realmente ter um impacto positivo no comércio.
Primeiro que as limitações de acesso definem a disponibilidade para toda uma amplitude de usuários, garantindo que os acessos sejam compartilhados entre todos os usuários e regiões, sem haver sobrecarga por algum deles. Isso garante que uma quantidade maior de usuários e com as necessidades mais diversas possam ter acesso a uma vasta gama de serviços, aumentando a base de usuários e os ganhos em potencial. A longo prazo, preservar a funcionalidade para os seus usuários tem um efeito positivo em rede, mesmo quando comparada à redução imediata nas requisições em potencial.
As limitações também têm o potencial de criar um fluxo diferenciado no modelo de negócio pela possibilidade de ofertar planos mais lucrativos que reduzem ou eliminam esses limites. Um usuário gratuito utilizando milhares de conexões custa caro, contudo, se um parceiro deseja fazer esse tanto de requisições, será possível ofertar um modelo de assinatura que reduza o custo da utilização deles na API e disponibilize quantas conexões forem necessárias. Esse modelo de assinatura pode ser adotado para os usuários também, monetizando a sua API de diversas formas.
Como alternativa às soluções com implementações de hardware, alguns Gateways de APIs oferecem em seu design o recurso de medição e limitação de requisições. Um limite real pode ser implementado agrupando diversos sistemas atrás do gateway central e limitando a quantidade das conexões dos usuários logados e das requisições vindas do servidor através do gateway.
É uma arte encontrar o meio termo, limitar muito as requisições tendo um preço de entrada alto irá afastar os consumidores. Não criar limitações, somando a baixa segurança com o mau uso da plataforma irá resultar em perda de performance e prejuízo ao longo do tempo. Conseguir balancear a experiência oferecida aos usuários com o desenvolvimento de uma API é provavelmente um dos elementos chaves para o sucesso da API.
Implementando a limitação das requisições
Existem muitas formas para se implementar a limitação, pode-se utilizar um appliance, um gateway, ou programando direto no código. Uma das formas mais comuns é utilizando o cache interno no servidor. Um exemplo, para quem usa o Alternative PHP Cache:
array apc_cache_info([ string $cache_type="" [, bool $limited=false ]])
Essa função verifica se o IP está no cache de conexões simultâneas, e se estiver, verifica se o limite foi atingido.
Isso também pode ser feito na configuração do nginx:
http { limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s; ... server { ... location /search/ { limit_req zone=one burst=5; } } }
Esse caso é melhor do que o Alternative PHP Cache acima porquê ele permite definir tanto o limite estático (1 requisição por segundo) quanto um limite que pode ser ultrapassado momentaneamente (burst de 5 requisições por segundo), as conexões podem ser limitadas dinamicamente para permitir o uso regular e também um aumento abrupto durante um curtíssimo espaço de tempo.
Para quem usa o Redis, é possível implementar com:
FUNCTION LIMIT_API_CALL(ip) ts = CURRENT_UNIX_TIME() keyname = ip+":"+ts current = GET(keyname) IF current != NULL AND current > 10 THEN ERROR "too many requests per second" ELSE MULTI INCR(keyname,1) EXPIRE(keyname,10) EXEC PERFORM_API_CALL() END
Esse exemplo apenas limita as interações no servidor, como nos outros exemplos, e cria um contador dinâmico para cada IP conectado que expira a cada 10 segundos. Essa solução também serve para mostrar uma mensagem de erro quando os limites são atingidos.
Exemplos de Limites de Requisição
Para ilustrar melhor as possibilidades, vamos ver alguns exemplos reais com os limites praticados pelo Twitter em sua API, os limites são separados por usuário e por aplicativo em algumas circunstâncias.
Por exemplo GET friendships/show
. Essa requisição retorna uma informação sobre a relação entre dois usuários específicos. É uma chamada bastante utilizada pois ela forma a base do Twitter. Os usuários podem efetuar 180 requisições a cada 15 minutos, e cada aplicativo tem o limite de 15 requisições por minuto. (Isso nos mostra que cada usuário pode utilizar no máximo 12 de seus aplicativos registrados para esse tipo de requisição.)
Comparando essa chamada a GET favorites/list
. Essa requisição retorna os últimos 20 Tweets do usuário, e está limitada a 15 requisições a cada 15 minutos, tanto para os usuários quanto para os aplicativos. (Os “aplicativos” são as chaves de APIs independentes que um usuário pode registrar em sua conta do Twitter).
Com essas duas chamadas, podemos ver exatamente porque a limitação das requisições é tão importante. Considere o poder computacional empregado pela primeira chamada, que verifica apenas os dados em comum entre os dois usuários. É uma chamada simples, com retorno rápido, que pode ser facilmente processada em grande volume.
A segunda chamada é um pouco mais complexa, a lista de tweets de um usuário qualquer pode variar em tamanho de minúscula para gigantesca e precisa ser ordenada, formatada, apresentada e mantida na memória para permitir a paginação, além da possibilidade de se modificar a qualquer momento quando o usuário publicar um novo tweet.
Podemos ver porque uma limitação variável nas requisições – de acordo com seu uso – é tão importante. A segunda chamada utiliza mais recursos computacionais e é limitada de acordo, para prevenir que muitas chamadas a esse recurso possa prejudicar o processamento das outras chamadas mais simples.
Algumas vezes a limitação não é só pelo custo, mas pela finalidade do recurso, como podemos observar nesse exemplo das limitações praticadas pelo Twilio:
Chamadas Efetuadas: Por padrão, cada conta do Twilio pode efetuar 1 chamada por segundo. Se você precisar de um limite superior, precisará entrar em contato com a equipe de vendas e cotar outras opções.
Chamadas Entrantes e SMS: O Twilio não coloca limitações na frequência em que um número pode receber chamadas entrantes ou mensagens SMS. O Twilio irá fazer uma requisição HTTP para cada chamada e mensagem recebida em seu número Twilio. Portanto, é preciso ter certeza de que o seu servidor será capaz de lidar com a carga se você estiver esperando por uma grande quantidade de tráfego.
Esses limites fazem sentido se você considerar o que o Twilio faz – lida com chamadas telefônicas de voz e mensagens SMS, assim sendo, iniciar mais de uma chamada por segundo não faz sentido para um usuário comum que será capaz de falar em apenas uma chamada por vez. Mas na recepção das ligações pode-se utilizar URAs (Unidades de Resposta Audível) e seus serviços de espera, aonde um limite para chamadas entrantes não faz sentido pois elas serão tratadas automaticamente por esse sistema do cliente.
Os desenvolvedores de APIs devem considerar cuidadosamente os recursos específicos que serão limitados. Como nos casos acima os recursos podem ser limitados pelas suas finalidades, mas isso é só parte da técnica, limitar também por acesso (usuário ou aplicação), por região e mesmo pelo tipo (login, listagem, etc) é possível dentro do escopo da limitação de requisições.
Conclusão
O limite de requisições é uma ferramenta incrível e poderosa para se implementar, mas deve ser implementada com pleno conhecimento da sua base de usuários e das suas necessidades.
Utilizar um sistema efetivo de limite de requisições estabelece segurança e disponibilidade para a sua API, e quando balanceado com as ressalvas inerentes, pode levar a um controle dinâmico e incluir novos canais de rentabilidade. Pense nisso como a estrada central da sua cidade API – você quer pavimentar um tapete liso cinco estrelas ou ter uma estrada de terra cheia de pedrinhas e buracos? Um caminho leva ao grande sucesso e crescimento acelerado, o outro, não.
Traduzido de NordicAPIs