Best practice per applicazioni RTB

Questa guida illustra le best practice da tenere presenti durante lo sviluppo di applicazioni secondo il protocollo RTB.

Gestire le connessioni

Mantenere attive le connessioni

Stabilire una nuova connessione aumenta le latenze e richiede molto di più le risorse da entrambi i lati rispetto al riutilizzo di una esistente. Chiudendo meno puoi ridurre il numero di connessioni da aprire di nuovo.

Innanzitutto, ogni nuova connessione richiede un round-trip di rete aggiuntivo per stabilire. Dal momento che stabiliamo connessioni on demand, la prima richiesta ha una scadenza effettiva più breve e ha maggiori probabilità di scadere richieste successive. Eventuali timeout aggiuntivi aumentano il tasso di errore, il che può portare alla limitazione dell'offerente.

In secondo luogo, molti server web generano un thread worker dedicato per ogni connessione. la creazione di un progetto. Ciò significa che per chiudere e ricreare la connessione, il server deve arrestare ed eliminare un thread, allocarne uno nuovo, renderlo eseguibile e compilare lo stato della connessione prima di elaborare definitivamente la richiesta. Sono tante di costi non necessari.

Evitare di chiudere le connessioni

Inizia ottimizzando il comportamento di connessione. La maggior parte dei valori predefiniti del server è personalizzata per ambienti con un numero elevato di client, ognuno dei quali effettua un numero ridotto di richieste. Per l'RTB, invece, un piccolo pool di macchine invia richieste per conto di un numero relativamente elevato di browser. In queste ha senso riutilizzare le connessioni il più possibile. Ti consigliamo di impostare:

  • Timeout per inattività su 2,5 minuti.
  • Numero massimo di richieste su una connessione al valore possibile più alto.
  • Numero massimo di connessioni al valore massimo possibile per la RAM soddisfare, prestando attenzione a verificare che il numero di connessioni non si avvicina troppo a quel valore.

In Apache, ad esempio, ciò comporterebbe l'impostazione di KeepAliveTimeout su 150, MaxKeepAliveRequests su zero e MaxClients su un valore che dipende dal tipo di server.

Una volta ottimizzato il comportamento di connessione, devi anche assicurarti che il codice dell'offerente non chiuda le connessioni inutilmente. Ad esempio, se hai un codice frontend che restituisce una risposta predefinita "Nessuna offerta" in caso di errori o timeout del backend, assicurati che il codice restituisca la risposta senza chiudere la connessione. In questo modo, eviterai la situazione in cui, se l'offerente ottiene sovraccarico, le connessioni iniziano a chiudersi e il numero di timeout aumenta. causando la limitazione dello strumento di offerta.

Mantieni un equilibrio delle connessioni

Se Authorized Buyers si connette ai server del tuo strumento di offerta attraverso un server proxy, le connessioni potrebbero risultare sbilanciate nel tempo poiché conoscendo solo l'indirizzo IP del server proxy, Authorized Buyers non è in grado di determinare quale server dello strumento di offerta riceve ciascun callout. Nel tempo, man mano che Authorized Buyers stabilisce e chiude di connessioni e server dell'offerente riavviati, il numero di connessioni mappati a ciascuno può diventare molto variabile.

Quando alcune connessioni sono molto utilizzate, altre connessioni aperte potrebbero rimangono per lo più inattivi perché non sono necessari in quel momento. Man mano che il traffico di Authorized Buyers cambia, le connessioni inattive possono diventare attive e le connessioni attive possono diventare inattive. Potrebbero causare caricamenti non uniformi sui server degli offerenti se le connessioni sono in cluster in modo scadente. Google tenta di evitarlo chiudendo tutte le connessioni dopo 10.000 richieste, per ribilanciare automaticamente connessioni nel tempo. Se noti che il traffico continua a essere sbilanciato nella tua puoi seguire altri passaggi:

  1. Seleziona il backend per richiesta anziché una volta per connessione se utilizzi proxy frontend.
  2. Specifica un numero massimo di richieste per connessione se utilizzi un proxy per le connessioni tramite un bilanciatore del carico o un firewall hardware e la mappatura è fissa una volta stabilite le connessioni. Tieni presente che Google specifica già un limite massimo di 10.000 richieste per connessione, quindi dovresti fornire un valore più rigoroso solo se continui a trovare connessioni calde che si raggruppano nel tuo ambiente. In Apache, ad esempio, imposta MaxKeepAliveRequests su 5000
  3. Configura i server dell'offerente per monitorare le frequenze di richiesta e chiudere alcune delle proprie connessioni se gestiscono costantemente troppe richieste rispetto ai coetanei.

Gestisci il sovraccarico con eleganza

Idealmente, le quote dovrebbero essere impostate in modo sufficientemente elevato da consentire all'offerente di ricevere tutte le richieste che può gestire, ma non più di quelle. In pratica, mantenere le quote a livelli ottimali è un compito difficile e si verificano sovraccarichi per una serie di motivi: un backend che si arresta durante i picchi di traffico, una modifica del mix di traffico che richiede un'elaborazione maggiore per ogni richiesta o un valore di quota impostato troppo elevato. Di conseguenza, vale la pena valutare il comportamento dello strumento di offerta perché il traffico in entrata è eccessivo.

Per gestire i cambiamenti temporanei del traffico (fino a una settimana) tra le regioni (in particolare tra Asia e Stati Uniti occidentali e Stati Uniti orientali e Stati Uniti occidentali), consigliamo di prevedere un margine del 15% tra il picco di 7 giorni e il QPS per località di scambio.

In termini di comportamento sotto carico, gli offerenti rientrano in tre categorie categorie:

La "risposta a tutto" offerente

Sebbene sia semplice da implementare, questo offerente ha il rendimento peggiore quando è sovraccaricato. Cerca semplicemente di rispondere a ogni richiesta di offerta in arrivo, , mettendo in coda quelli che non possono essere pubblicati immediatamente. Lo scenario che ne consegue è spesso qualcosa di simile:

  • Se la percentuale di richieste aumenta, aumentano anche le latenze delle richieste, finché tutte le richieste avvio del timeout
  • Le latenze aumentano notevolmente quando le percentuali di callout si avvicinano al picco
  • Viene applicata la limitazione, che riduce drasticamente il numero di callout consentiti
  • Le latenze iniziano a recuperare, causando una riduzione del throttling
  • Il ciclo ricomincia.

Il grafico della latenza per questo offerente assomiglia a un dente di sega molto ripido pattern. In alternativa, le richieste in coda inducono il server ad avviare la paginazione della memoria o a eseguire un'altra operazione che causa un rallentamento a lungo termine e le latenze non si riprendono fino al termine delle ore di picco, con un conseguente calo dei tassi di callout durante l'intero periodo di picco. In entrambi i casi, vengono effettuati o risposti meno callout rispetto a quanto accadrebbe se la quota fosse stata impostata su un valore inferiore.

"Errore in caso di sovraccarico" offerente

Questo offerente accetta i callout fino a una certa percentuale, poi inizia a restituire errori per alcuni callout. Questa operazione può essere eseguita tramite timeout interni, disattivando accodamento delle connessioni (controllato da ListenBackLog su Apache), implementazione di una modalità di caduta probabilistica quando si applicano anche casi di utilizzo o latenze alta o con un altro meccanismo. Se Google osserva un tasso di errore superiore al 15%, inizierà la limitazione. A differenza dell'offerente "risponde a tutto", questo offerente "riduce le perdite", il che gli consente di recuperare immediatamente quando i tassi di richiesta diminuiscono.

Il grafico della latenza per questo offerente assomiglia a un dente di sega superficiale durante i sovraccarichi, localizzato attorno al limite massimo accettabile di conversione.

L'offerente "nessuna offerta in caso di sovraccarico"

Questo offerente accetta callout fino a una determinata frequenza, quindi inizia a restituire risposte "nessuna offerta" per eventuali sovraccarichi. Simile a "Errore relativo al sovraccarico" offerente, questo può essere implementato in vari modi. La differenza qui è che no vengono restituiti a Google, pertanto non riduciamo mai le limitazioni dei callout. La il sovraccarico viene assorbito dalle macchine front-end, che consentono solo il traffico gestibili da gestire per raggiungere i backend.

Il grafico della latenza per questo offerente mostra un plateau che (artificialmente) si interrompe parallelamente al tasso di richieste nei periodi di picco e un corrispondente calo della frazione di risposte contenenti un'offerta.

Ti consigliamo di combinare l'approccio "errore in caso di sovraccarico" con quello "nessuna offerta in caso di sovraccarico", nel seguente modo:

  • Esegui l'overprovisioning dei front-end e impostali su un errore in caso di sovraccarico, in modo da massimizzare il numero di connessioni a cui possono rispondere in un determinato formato.
  • In caso di errore di sovraccarico, le macchine front-end possono utilizzare una risposta predefinita "no-bid" e non devono analizzare la richiesta.
  • Implementa il controllo di integrità dei backend in modo che, se nessuno dispone di capacità sufficiente, restituiscano una risposta di tipo "no-bid".

In questo modo è possibile assorbire un certo sovraccarico e i backend hanno la possibilità di rispondere esattamente al numero di richieste che possono gestire. Puoi considerare questa situazione come "Nessuna offerta in caso di sovraccarico", con le macchine di front-end che tornano a "Errore in caso di sovraccarico" quando il numero di richieste è notevolmente superiore alle aspettative.

Se hai uno strumento di offerta che risponde a tutto, valuta la possibilità di trasformarlo in uno strumento di offerta che genera un errore in caso di sovraccarico regolando il comportamento di connessione in modo che, in pratica, rifiuti di essere sovraccaricato. Sebbene questo causi il ritorno di più errori, riduce i timeout e impedisce al server di entrare in uno stato in cui non può rispondere a nessuna richiesta.

Rispondi ai ping

Assicurarsi che l'offerente possa rispondere alle richieste di ping senza connettersi della gestione di per sé, è sorprendentemente importante per il debug. Google utilizza le richieste di ping per il controllo di congruità e il debug dello stato dell'offerente, del comportamento di chiusura della connessione, della latenza e altro ancora. Le richieste di ping hanno il seguente formato:

OpenRTB Protobuf

id: "7xd2P2M7K32d7F7Y50p631"

JSON OpenRTB

{
  "id": "4YB27BCXimH5g7wB39nd3t"
}

Google (disponibile solo per i partner)

id: "\3503cg\3023P\364\230\240\270\020\255\002\231\314\010\362\347\351\246\357("
is_test: true
is_ping: true

Tieni presente che, contrariamente a quanto potresti pensare, la richiesta di ping non contiene annunci. Inoltre, come descritto sopra, non devi chiudere la connessione dopo aver risposto a una richiesta di ping.

Valuta la possibilità di utilizzare il peering

Un altro modo per ridurre la latenza o la variabilità della rete è eseguire il peering con Google. Il peering consente di ottimizzare il percorso seguito dal traffico per raggiungere lo strumento di offerta. Gli endpoint di connessione rimangono invariati, ma i link intermedi cambiano. Per maggiori dettagli, consulta la guida al peering. Il motivo per cui considerare il peering come una best practice può essere riassunto come segue:

  • Su internet, i link al trasporto pubblico vengono scelti principalmente attraverso routing" che trova il link più vicino all'esterno della nostra rete che può ricevere un pacchetto alla sua destinazione e instradalo attraverso quel link. Quando il traffico attraversa una sezione di backbone di proprietà di un provider con cui abbiamo molte connessioni in peering, è probabile che il link scelto sia vicino al punto durante l'avvio del pacchetto. Dopodiché non abbiamo alcun controllo del percorso del pacchetto segue all'offerente, quindi potrebbe essere reindirizzato ad altri sistemi autonomi (reti) lungo il percorso.

  • Al contrario, quando è in atto un accordo di peering diretto, i pacchetti vengono viene sempre inviato insieme a un link di peering. Indipendentemente dalla sua origine, il pacchetto attraversa i link di proprietà o in leasing di Google fino a raggiungere il punto di peering condiviso, che dovrebbe essere vicino alla località dell'offerente. Il viaggio di ritorno inizia con un breve salto sulla rete Google e rimane sulla rete Google per il resto del percorso. Mantenere la maggior parte del viaggio con gli strumenti gestiti da Google infrastruttura assicura che il pacchetto prenda una route a bassa latenza ed evita molta variabilità potenziale.

Invia DNS statico

Consigliamo agli acquirenti di inviare sempre un singolo risultato DNS statico a Google e di affidarsi su Google per gestire la distribuzione del traffico.

Ecco due pratiche comuni degli offerenti Server DNS durante il tentativo di caricamento bilanciare o gestire la disponibilità:

  1. Il server DNS distribuisce in risposta un indirizzo o un sottoinsieme di indirizzi a una query, per poi scorrere la risposta in qualche modo.
  2. Il server DNS risponde sempre con lo stesso insieme di indirizzi, ma cicli l'ordine degli indirizzi nella risposta.

La prima tecnica è scadente nel bilanciamento del carico poiché c'è molta memorizzazione nella cache da più livelli dello stack e i tentativi di aggirare la memorizzazione nella cache probabilmente ottenere anche i risultati preferiti, poiché Google addebita i tempi di risoluzione DNS offerente.

La seconda tecnica non consente alcun bilanciamento del carico, poiché Google seleziona in modo casuale un indirizzo IP dall'elenco di risposte DNS, quindi l'ordine nella risposta non ha importanza.

Se un offerente apporta una modifica al DNS, Google rispetterà il TTL (Time-to-live) impostato nei suoi record DNS, ma l'intervallo di aggiornamento rimane incerto.