Práticas recomendadas para aplicativos de RTB

Este guia explica as práticas recomendadas a serem consideradas ao desenvolver aplicativos de acordo com o protocolo RTB.

Gerenciar conexões

Manter as conexões ativas

Estabelecer uma nova conexão aumenta a latência e consome muito mais recursos em ambas as extremidades do que reutilizar uma conexão existente. Ao fechar menos conexões, você pode reduzir o número de conexões que precisam ser abertas novamente.

Primeiro, cada nova conexão exige uma ida e volta de rede extra para ser estabelecida. Como estabelecemos conexões sob demanda, a primeira solicitação em uma conexão tem um prazo de validade mais curto e é mais propensa a esgotar do que as solicitações subsequentes. Qualquer tempo limite extra aumenta a taxa de erro, o que pode levar ao limitação do seu bidder.

Em segundo lugar, muitos servidores da Web geram uma linha de execução de worker dedicada para cada conexão estabelecida. Isso significa que, para fechar e recriar a conexão, o servidor precisa encerrar e descartar uma linha de execução, alocar uma nova, torná-la executável e criar o estado de conexão antes de processar a solicitação. Isso gera uma sobrecarga desnecessária.

Evitar o fechamento de conexões

Comece ajustando o comportamento da conexão. A maioria dos padrões do servidor é adaptada para ambientes com um grande número de clientes, cada um fazendo um pequeno número de solicitações. Já no RTB, um pequeno pool de máquinas envia solicitações em nome de um grande número de navegadores, relativamente falando. Nessas condições, faz sentido reutilizar as conexões o máximo possível. Recomendamos que você defina:

  • Tempo limite de inatividade para 2,5 minutos.
  • Número máximo de solicitações em uma conexão para o valor mais alto possível.
  • Número máximo de conexões para o valor mais alto que a RAM pode acomodar, tomando o cuidado de verificar se o número de conexões não se aproxima muito desse valor.

No Apache, por exemplo, isso implicaria definir KeepAliveTimeout como 150, MaxKeepAliveRequests como zero e MaxClients como um valor que depende do tipo de servidor.

Depois que o comportamento de conexão for ajustado, também é necessário garantir que o código do bidder não feche conexões desnecessariamente. Por exemplo, se você tiver um código front-end que retorna uma resposta padrão "sem lance" no caso de erros ou timeouts do back-end, verifique se o código retorna a resposta sem fechar a conexão. Assim, você evita a situação em que, se o bidder ficar sobrecarregado, as conexões começarão a ser encerradas e o número de tempos limite aumentará, causando a limitação do bidder.

Equilibre as conexões

Se os compradores autorizados se conectarem aos servidores do seu bidder por um servidor proxy, as conexões poderão ficar desequilibradas ao longo do tempo porque, conhecendo apenas o endereço IP do servidor proxy, os compradores autorizados não podem determinar qual servidor do bidder está recebendo cada chamada. Com o tempo, à medida que os compradores autorizados estabelecem e encerram conexões e os servidores do bidder são reiniciados, o número de conexões mapeadas para cada um pode se tornar muito variável.

Quando algumas conexões são usadas com frequência, outras conexões abertas podem permanecer inativas porque não são necessárias no momento. À medida que o tráfego dos compradores autorizados muda, as conexões inativas podem se tornar ativas, e as ativas podem ficar inativas. Isso pode causar cargas irregulares nos servidores do bidder se as conexões forem agrupadas incorretamente. O Google tenta evitar isso fechando todas as conexões após 10.000 solicitações, para reequilibrar automaticamente as conexões ativas ao longo do tempo. Se o tráfego ainda estiver desequilibrado no seu ambiente, siga estas etapas:

  1. Selecione o back-end por solicitação, em vez de uma vez por conexão, se você estiver usando proxies de front-end.
  2. Especifique um número máximo de solicitações por conexão se você estiver fazendo proxy de conexões por um balanceador de carga de hardware ou firewall e o mapeamento for fixo depois que as conexões forem estabelecidas. O Google já especifica um limite máximo de 10.000 solicitações por conexão. Portanto, você só precisará fornecer um valor mais restrito se as conexões agrupadas continuarem aparecendo no seu ambiente. No Apache, por exemplo, defina MaxKeepAliveRequests como 5.000.
  3. Configure os servidores do bidder para monitorar as taxas de solicitação e fechar algumas das próprias conexões se ele estiver processando muitas solicitações em comparação com os pares.

Processar sobrecarga de maneira suave

O ideal é que as cotas sejam definidas em um nível alto o suficiente para que o bidder receba todas as solicitações que consegue processar, mas não mais do que isso. Na prática, manter as cotas em níveis ideais é uma tarefa difícil, e sobrecargas acontecem por vários motivos: um back-end que cai durante horários de pico, uma mistura de tráfego que muda para que seja necessário mais processamento para cada solicitação ou um valor de cota definido muito alto. Por isso, é importante considerar como seu bidder vai se comportar com muito tráfego.

Para acomodar mudanças temporárias no tráfego (até uma semana) entre regiões (especialmente entre a Ásia e os EUA Ocidental e Oriental), recomendamos uma margem de 15% entre o pico de 7 dias e o QPS por local de negociação.

Em termos de comportamento sob cargas pesadas, os bidders se enquadram em três categorias amplas:

O bidder "responde a tudo"

Embora seja simples de implementar, esse bidder tem o pior desempenho quando sobrecarregado. Ele simplesmente tenta responder a cada solicitação de lance que chega, não importa o que aconteça, enfileirando qualquer um que não possa ser veiculado imediatamente. O cenário que se segue é geralmente algo como este:

  • À medida que a taxa de solicitações aumenta, as latências de solicitação também aumentam, até que todas as solicitações comecem a expirar.
  • As latências aumentam rapidamente à medida que as taxas de chamadas de atenção se aproximam do pico
  • O limite é aplicado, reduzindo drasticamente o número de chamadas permitidas.
  • As latências começam a se recuperar, fazendo com que o estrangulamento seja reduzido.
  • O ciclo começa de novo.

O gráfico de latência desse bidder se assemelha a um padrão de dente de serra muito íngreme. Como alternativa, as solicitações em fila fazem com que o servidor inicie a paginação de memória ou faça outra coisa que cause uma desaceleração de longo prazo. Além disso, as latências não se recuperam até que os horários de pico terminem, o que leva a taxas de chamada deixadas de lado durante todo o período de pico. Em ambos os casos, menos chamadas são feitas ou respondidas do que se a cota tivesse sido definida como um valor menor.

O bidder "error on overload"

Esse bidder aceita chamadas até uma determinada taxa e, em seguida, começa a retornar erros para algumas chamadas. Isso pode ser feito por meio de tempos limite internos, desativando a fila de conexões (controlada por ListenBackLog no Apache), implementando um modo de descarte probabilístico quando a utilização ou latência fica muito alta ou algum outro mecanismo. Se o Google observar uma taxa de erro acima de 15%, vamos começar a limitar. Ao contrário do proponente "responder a tudo", esse proponente "reduz as perdas", o que permite que ele se recupere imediatamente quando as taxas de solicitação diminuem.

O gráfico de latência desse bidder se assemelha a um padrão de dente de serra superficial durante sobrecargas, localizado em torno da taxa máxima aceitável.

O bidder "sem lance em sobrecarga"

Esse bidder aceita chamadas até uma determinada taxa e, em seguida, começa a retornar respostas "sem lance" para qualquer sobrecarga. Assim como o bidder "error on overload", isso pode ser implementado de várias maneiras. A diferença aqui é que nenhum sinal é retornado ao Google. Por isso, nunca reduzimos os destaques. A sobrecarga é absorvida pelas máquinas front-end, que permitem apenas que o tráfego que elas podem processar continue até os back-ends.

O gráfico de latência desse bidder mostra um platô que (artificialmente) para de paralelizar a taxa de solicitação nos horários de pico e uma queda correspondente na fração de respostas que contêm um lance.

Recomendamos combinar a abordagem "erro na sobrecarga" com a abordagem "sem lance na sobrecarga", da seguinte maneira:

  • Provisione demais os front-ends e defina-os para gerar erros em caso de sobrecarga, para maximizar o número de conexões que eles podem responder de alguma forma.
  • Quando ocorre um erro de sobrecarga, as máquinas front-end podem usar uma resposta "sem lance" predefinida e não precisam analisar a solicitação.
  • Implemente a verificação de integridade dos back-ends para que, se nenhum deles tiver capacidade suficiente disponível, eles retornem uma resposta "sem lance".

Isso permite que parte da sobrecarga seja absorvida e dá aos back-ends a chance de responder a exatamente quantas solicitações puderem. Pense nisso como "sem lance em sobrecarga", com máquinas front-end voltando para "erro em sobrecarga" quando as contagens de solicitações são significativamente maiores do que o esperado.

Se você tiver um bidder "responder a tudo", considere transformá-lo em um bidder "erro na sobrecarga" ajustando o comportamento de conexão para que ele se recuse a ser sobrecarregado. Embora isso cause mais erros, ele reduz os tempos limite e evita que o servidor entre em um estado em que não possa responder a nenhuma solicitação.

Considere o peering

Outra maneira de reduzir a latência ou variabilidade da rede é fazer peering com o Google. O peering ajuda a otimizar o caminho que o tráfego percorre para chegar ao seu bidder. Os endpoints de conexão permanecem os mesmos, mas os links intermediários mudam. Consulte o guia de peering para mais detalhes. O motivo para considerar o peering como uma prática recomendada pode ser resumido da seguinte forma:

  • Na Internet, os links de trânsito são escolhidos principalmente pelo "roteamento hot-potato", que encontra o link mais próximo fora da nossa rede que pode levar um pacote ao destino e encaminha o pacote por esse link. Quando o tráfego atravessa uma seção de backbone de um provedor com quem temos muitas conexões de peering, o link escolhido provavelmente fica próximo de onde o pacote começa. Além desse ponto, não temos controle sobre a rota que o pacote segue para o bidder. Portanto, ele pode ser reencaminhado para outros sistemas autônomos (redes) ao longo do caminho.

  • Por outro lado, quando um acordo de peering direto está em vigor, os pacotes são sempre enviados por um link de peering. Não importa de onde o pacote se origina, ele atravessa links que o Google possui ou aluga até chegar ao ponto de peering compartilhado, que precisa estar próximo ao local do proponente. A viagem reversa começa com um salto curto para a rede do Google e permanece na rede do Google pelo resto do caminho. Manter a maior parte da viagem na infraestrutura gerenciada pelo Google garante que o pacote siga uma rota de baixa latência e evita muita variabilidade.

Enviar DNS estático

Recomendamos que os compradores sempre enviem um único resultado de DNS estático ao Google e confiem no Google para processar a entrega de tráfego.

Confira duas práticas comuns dos servidores DNS dos bidders ao tentar carregar o equilíbrio ou gerenciar a disponibilidade:

  1. O servidor DNS fornece um endereço ou um subconjunto de endereços em resposta a uma consulta e, em seguida, percorre essa resposta de alguma forma.
  2. O servidor DNS sempre responde com o mesmo conjunto de endereços, mas alterna a ordem dos endereços na resposta.

A primeira técnica é ruim no balanceamento de carga, porque há muito armazenamento em cache em vários níveis da pilha, e as tentativas de ignorar o armazenamento em cache provavelmente não vão gerar os resultados preferidos, já que o Google cobra o tempo de resolução do DNS para o licitante.

A segunda técnica não alcança o balanceamento de carga, já que o Google seleciona aleatoriamente um endereço IP da lista de respostas do DNS. Portanto, a ordem na resposta não importa.

Se um bidder fizer uma alteração no DNS, o Google vai respeitar o TTL(time to live) definido nos registros DNS, mas o intervalo de atualização vai permanecer incerto.