Best practice per applicazioni RTB

Questa guida illustra le best practice da tenere in considerazione per lo sviluppo di applicazioni in base al protocollo RTB.

Gestire le connessioni

Mantieni attive le connessioni

La creazione di una nuova connessione aumenta le latenze e richiede molte più risorse su entrambi i lati rispetto al riutilizzo di una connessione esistente. Se chiudi un numero inferiore di connessioni, puoi ridurre il numero di connessioni che devono essere nuovamente aperte.

Innanzitutto, per stabilire ogni nuova connessione è necessaria una rete aggiuntiva di andata e ritorno. Poiché stabiliamo connessioni on demand, la prima richiesta su una connessione ha una scadenza effettiva più breve ed è più probabile che scada rispetto alle richieste successive. Eventuali timeout aggiuntivi aumentano il tasso di errore, il che può portare a una limitazione dello strumento di offerta.

In secondo luogo, molti server web generano un thread di lavoro dedicato per ogni connessione stabilita. Ciò significa che per chiudere e ricreare la connessione, il server deve arrestare ed eliminare un thread, allocarne uno nuovo, renderlo eseguibile e creare lo stato della connessione, prima di elaborare la richiesta. Si tratta di un eccessivo overhead non necessario.

Evita di chiudere le connessioni

Inizia ottimizzando il comportamento della connessione. La maggior parte delle impostazioni predefinite del server è studiata su misura per gli ambienti con un gran numero di client, ognuno dei quali effettua un numero limitato di richieste. Per le offerte in tempo reale, invece, un piccolo pool di macchine invia richieste per conto di un numero elevato di browser. In queste condizioni, ha senso riutilizzare le connessioni il più possibile. Ti consigliamo di impostare:

  • Timeout di inattività su 2,5 minuti.
  • Numero massimo di richieste su una connessione al valore più alto possibile.
  • Numero massimo di connessioni al valore più alto che la RAM è in grado di supportare, verificando che il numero di connessioni non si avvicina troppo a questo valore.

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

Una volta ottimizzato il comportamento della connessione, dovresti anche assicurarti che il codice offerente non chiuda le connessioni inutilmente. Ad esempio, se hai un codice front-end 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 lo strumento di offerta viene sovraccarico, le connessioni iniziano a chiudersi e il numero di timeout aumenta, causando una limitazione dello strumento di offerta.

Mantieni bilanciate le connessioni

Se Authorized Buyers si connette ai server dell'offerente tramite un server proxy, nel tempo le connessioni potrebbero non essere bilanciate perché, 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 le connessioni e i server dell'offerente si riavviano, il numero di connessioni mappate a ciascuna può diventare altamente variabile.

Quando alcune connessioni sono molto utilizzate, altre connessioni aperte potrebbero rimanere per lo più inattive perché non sono necessarie al momento. Al variare del traffico di Authorized Buyers, le connessioni inattive possono diventare attive e quelle attive possono diventare inattive. Questi potrebbero causare carichi non uniformi sui server dello strumento di offerta se le connessioni sono raggruppate in modo scadente. Google cerca di evitare questo problema chiudendo tutte le connessioni dopo 10.000 richieste, in modo da riequilibrare automaticamente le connessioni calde nel tempo. Se noti che il traffico continua ad essere sbilanciato, puoi adottare ulteriori misure:

  1. Seleziona il backend per richiesta anziché una volta per connessione se utilizzi proxy di frontend.
  2. Specifica un numero massimo di richieste per connessione se esegui il proxy delle connessioni attraverso un bilanciatore del carico hardware o un firewall e la mappatura viene corretta dopo aver stabilito le connessioni. Tieni presente che Google specifica già un limite massimo di 10.000 richieste per connessione, quindi dovresti fornire un valore più restrittivo solo se continui a rilevare connessioni attive in cluster nel tuo ambiente. In Apache, ad esempio, imposta MaxKeepAliveRequests su 5000
  3. Configura i server dell'offerente per monitorare le percentuali di richieste e chiudere alcune delle proprie connessioni se gestiscono costantemente troppe richieste rispetto ai peer.

Gestisci il sovraccarico senza problemi

Idealmente, le quote sarebbero sufficientemente elevate in modo che lo strumento di offerta possa ricevere tutte le richieste che è in grado di gestire, ma non di più. In pratica, mantenere le quote a livelli ottimali è un'attività difficile e si possono verificare sovraccarichi per vari motivi: un backend in arresto durante i periodi di picco, un mix di traffico che cambia in modo da rendere necessaria una maggiore elaborazione per ogni richiesta o un valore di quota impostato su un valore troppo elevato. Di conseguenza, conviene valutare come si comporterà lo strumento di offerta con un volume di traffico eccessivo.

Per far fronte a cambiamenti temporanei del traffico (fino a una settimana) tra le regioni (in particolare tra Asia e Stati Uniti occidentali e Stati Uniti orientali e occidentali), consigliamo un attenuazione del 15% tra il picco di 7 giorni e il QPS per sede di scambio.

In termini di comportamento in presenza di carichi pesanti, gli offerenti si suddividono in tre grandi categorie:

L'offerente "risponde a tutto"

Per quanto sia semplice da implementare, questo offerente fa il peggio in caso di sovraccarico. Cerca semplicemente di rispondere a ogni richiesta di offerta in arrivo, indipendentemente, mettendo in coda le richieste che non possono essere pubblicate immediatamente. Lo scenario che ne consegue è spesso simile al seguente:

  • Con l'aumento del tasso di richieste aumentano anche le latenze delle richieste, fino al timeout di tutte le richieste
  • Le latenze aumentano drasticamente man mano che le percentuali di callout si avvicinano al picco
  • La limitazione viene attivata, riducendo notevolmente il numero di callout consentiti
  • Le latenze iniziano a ripristinarsi, causando una riduzione della limitazione
  • Il ciclo all'inizio ricomincia.

Il grafico della latenza per questo offerente assomiglia a uno schema a denti di sega molto ripido. In alternativa, le richieste in coda portano il server ad avviare la memoria di paging o a eseguire altre operazioni che causano un rallentamento a lungo termine e le latenze non si recuperano affatto fino al termine dei periodi di picco, determinando percentuali di callout ridotte durante l'intero periodo di picco. In entrambi i casi, vengono effettuati o rispondi meno callout rispetto al caso in cui la quota fosse stata semplicemente impostata su un valore inferiore.

Lo strumento di offerta "Errore in caso di sovraccarico"

Questo offerente accetta i callout fino a una determinata tariffa, poi inizia a restituire gli errori per alcuni callout. Ciò può avvenire mediante timeout interni, la disattivazione dell'accodamento della connessione (controllato da ListenBackLog su Apache), l'implementazione di una modalità di eliminazione probabilistica quando l'utilizzo o le latenze diventano troppo elevati, o qualche altro meccanismo. Se Google rileva un tasso di errore superiore al 15%, inizierà la limitazione. A differenza dell'offerente "rispondi a tutto", questo offerente "riduce le perdite", consentendogli di recuperare immediatamente quando i tassi delle richieste scendono.

Il grafico della latenza per questo offerente assomiglia a un modello a denti di sega superficiale durante i sovraccarichi, localizzato attorno al tasso massimo accettabile.

Lo strumento di offerta "nessuna offerta per sovraccarico"

Questo offerente accetta callout fino a una determinata tariffa, poi inizia a restituire risposte "senza offerta" in caso di sovraccarico. Analogamente all'offerente "Errore di sovraccarico", può essere implementato in vari modi. La differenza sta nel fatto che a Google non viene restituito alcun indicatore, pertanto non provvediamo mai a limitare i callout. Il sovraccarico viene assorbito dalle macchine front-end, che consentono solo al traffico che è in grado di gestire di passare ai backend.

Il grafico della latenza per questo offerente mostra un altopiano che (artificiosamente) smette di supportare il tasso di richieste nei momenti di picco e un corrispondente calo della frazione di risposte che contengono un'offerta.

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

  • Esegui l'overprovisioning dei front-end e impostali su errore in caso di sovraccarico, per massimizzare il numero di connessioni a cui possono rispondere in una certa forma.
  • In caso di errore in caso di sovraccarico, i computer front-end possono utilizzare una risposta "no-bid" predefinita e non hanno bisogno di analizzare la richiesta.
  • Implementa il controllo di integrità dei backend in modo che, se nessuno ha capacità disponibile sufficiente, venga restituita una risposta di "nessuna offerta".

Ciò consente di assorbire un certo sovraccarico e offre ai backend la possibilità di rispondere esattamente al numero di richieste che sono in grado di gestire. Ciò può essere considerato come una "nessuna offerta per il sovraccarico", in cui le macchine front-end tornano all'errore "errore in caso di sovraccarico" quando il numero di richieste è molto più elevato del previsto.

Se hai uno strumento di offerta "risponde a tutto", valuta la possibilità di trasformarlo in uno strumento di offerta "errore di sovraccarico" regolando il comportamento della connessione in modo che, di fatto, rifiuti di sovraccaricare. Anche se questo comporta la restituzione di un numero maggiore di errori, riduce i timeout e impedisce al server di entrare in uno stato in cui non può rispondere alle richieste.

Rispondere ai ping

Assicurarsi che lo strumento di offerta possa rispondere alle richieste di ping, senza gestire la connessione di per sé, è sorprendentemente importante per il debug. Google utilizza le richieste di ping per il controllo di integrità 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:

Google

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

JSON OpenRTB

"id": "4YB27BCXimH5g7wB39nd3t"

Protobuf OpenRTB

id: "7xd2P2M7K32d7F7Y50p631"

Tieni presente che, contrariamente a quanto previsto, la richiesta di ping non contiene aree annuncio. Inoltre, come specificato in precedenza, non devi chiudere la connessione dopo aver risposto a una richiesta di ping.

Valuta il peering

Un altro modo per ridurre la latenza o la variabilità della rete è eseguire il peering con Google. Il peering aiuta a ottimizzare il percorso seguito dal traffico per arrivare allo strumento di offerta. Gli endpoint della connessione rimangono gli stessi, ma i link intermedi cambiano. Per ulteriori dettagli, consulta la Guida al peering. Il motivo per considerare il peering come una best practice può essere riassunto come segue:

  • Su Internet, i link di trasporto pubblico vengono scelti principalmente tramite il routing "hot-potato", che trova il link più vicino all'esterno della nostra rete che può ricevere un pacchetto alla sua destinazione e instrada il pacchetto attraverso questo 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 si trovi vicino al punto di partenza del pacchetto. Oltre questo punto, non abbiamo più il controllo della route che il pacchetto segue per l'offerente, pertanto potrebbe essere rimbalzato su altri sistemi autonomi (reti) lungo il percorso.

  • Al contrario, quando è attivo un accordo di peering diretto, i pacchetti vengono sempre inviati lungo un link di peering. Indipendentemente dall'origine del pacchetto, attraversa i link di proprietà o in leasing da Google fino a raggiungere il punto di peering condiviso, che dovrebbe essere vicino alla posizione dello strumento di offerta. Il percorso inverso inizia con un breve hop verso la rete Google e rimane sulla rete Google per il resto del percorso. Conservare la maggior parte del viaggio sull'infrastruttura gestita da Google garantisce che il pacchetto segua 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 a Google per gestire la distribuzione del traffico.

Di seguito sono riportate due pratiche comuni applicate dai server DNS degli offerenti durante il tentativo di bilanciare il carico o gestire la disponibilità:

  1. Il server DNS passa in risposta a una query un indirizzo o un sottoinsieme di indirizzi, quindi passa la risposta in modo continuativo.
  2. Il server DNS risponde sempre con lo stesso insieme di indirizzi, ma modifica in sequenza l'ordine degli indirizzi nella risposta.

La prima tecnica è scadente nel bilanciamento del carico, poiché esiste un'elevata memorizzazione nella cache a più livelli dello stack e i tentativi di ignorare la memorizzazione nella cache probabilmente non otterranno anche i risultati preferiti, poiché Google addebita il tempo di risoluzione DNS all'offerente.

La seconda tecnica non consente di raggiungere il bilanciamento del carico poiché Google seleziona in modo casuale un indirizzo IP dall'elenco delle risposte DNS in modo che l'ordine nella risposta non sia rilevante.

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