Qi Li | Ingegnere del software, servizi principali; Zhihuang Chen | Ingegnere del software, servizi principali; Pin Jin | Direttore ingegnere, servizi principali
In Pinterest, un’ampia gamma di funzionalità e caratteristiche per varie esigenze e prodotti aziendali è supportata da una piattaforma di esecuzione dei lavori asincrona chiamata Pinlater, che è stata resa open source alcuni anni fa. I casi d’uso sulla piattaforma vanno dal salvataggio dei Pin da parte dei Pinner, alla notifica ai Pinner di vari aggiornamenti, all’elaborazione di immagini/video, ecc. Pinlater gestisce miliardi di esecuzioni di lavoro su base giornaliera. La piattaforma supporta molte funzionalità desiderabili, come la semantica almeno una volta, la pianificazione dei lavori per l’esecuzione futura e il controllo della velocità di eliminazione dalla coda/elaborazione sulle singole code dei lavori.
Con la crescita di Pinterest negli ultimi anni e l’aumento del traffico verso Pinlater, abbiamo scoperto numerosi limiti di Pinlater, tra cui il collo di bottiglia della scalabilità, l’efficienza dell’hardware, la mancanza di isolamento e l’usabilità. Abbiamo anche incontrato nuove sfide con la piattaforma, comprese quelle che hanno influito sulla velocità effettiva e sull’affidabilità del nostro archivio dati.
Analizzando questi problemi, ci siamo resi conto che alcuni problemi come la contesa dei blocchi e l’isolamento a livello di coda non potevano essere risolti nella piattaforma esistente. Pertanto, abbiamo deciso di rinnovare l’architettura della piattaforma nella sua interezza, affrontando i limiti individuati e ottimizzando le funzionalità esistenti. In questo post, esamineremo questa nuova architettura e le nuove opportunità che ha prodotto (come una coda FIFO).
Pinlater ha tre componenti principali:
- Un servizio Thrift senza stato per gestire l’invio e la pianificazione dei lavori, con tre API principali: accodamento, rimozione dalla coda e ACK
- Un datastore di back-end per salvare il lavoro, inclusi payload e metadati
- Job worker nei pool di worker per estrarre continuamente i lavori, eseguirli e inviare un ACK positivo o negativo per ogni lavoro a seconda che l’esecuzione sia riuscita o meno
Poiché Pinlater gestisce più casi d’uso e traffico, la piattaforma non funziona altrettanto bene. I problemi esposti includono, ma non sono limitati a:
- Poiché tutte le code hanno una tabella in ogni frammento del datastore e ogni richiesta di rimozione dalla coda esegue la scansione di tutti i frammenti per trovare i lavori disponibili, la contesa di blocco si verifica nel datastore quando più thread del server dell’usato tentano di acquisire dati dalla stessa tabella. Diventa più grave con l’aumentare del traffico e l’aumento dei servizi di risparmio. Ciò degrada le prestazioni di Pinlater, influisce sul throughput della piattaforma e limita la scalabilità.
- Le esecuzioni dei lavori si influenzano a vicenda poiché i lavori di più code di lavoro con caratteristiche diverse sono in esecuzione sullo stesso host di lavoro. Una coda di lavori errati potrebbe arrestare l’intero cluster di lavoro in modo che anche altre code di lavoro ne risentano. Inoltre, la combinazione di questi processi rende quasi impossibile l’ottimizzazione delle prestazioni, poiché le code dei processi potrebbero richiedere diversi tipi di istanza.
- Varie funzionalità condividono gli stessi servizi di risparmio e si influenzano a vicenda, ma hanno requisiti di affidabilità molto diversi. Ad esempio, il fallimento dell’accodamento potrebbe influenzare la SR a livello di sito poiché l’accodamento dei lavori è una fase di alcuni flussi critici, mentre il fallimento della rimozione dalla coda si traduce solo in un ritardo nell’esecuzione del lavoro, che possiamo permetterci per un breve periodo di tempo.
Per ottenere prestazioni migliori e risolvere i problemi sopra menzionati, abbiamo rinnovato l’architettura in Pacer introducendo nuovi componenti e nuovi meccanismi per l’archiviazione, l’accesso e l’isolamento dei dati e delle code dei lavori.
Pacer è composto dai seguenti componenti principali:
- Un servizio Thrift senza stato per gestire l’invio e la programmazione dei lavori
- Un datastore back-end per salvare i lavori e i relativi metadati
- Un servizio broker di rimozione dalla coda con stato per estrarre i processi dal datastore
- Helix con Zookeeper per assegnare dinamicamente le partizioni delle code di lavoro al servizio di annullamento della coda
- Pool di lavoratori dedicati per ogni coda su K8 per eseguire i lavori
Come puoi vedere, vengono introdotti nuovi componenti, come un servizio di broker dequeue dedicato, Helix e K8. La motivazione di questi componenti nella nuova architettura è risolvere i problemi in Pinlater.
- Helix con Zookeeper aiuta a gestire l’assegnazione delle partizioni delle code di lavoro ai broker di rimozione dalla coda. Ogni partizione di una coda di processi nel datastore verrà assegnata a un host del servizio broker di annullamento accodamento dedicato e solo questo host broker può rimuovere l’accodamento da questa partizione in modo che non vi sia concorrenza sugli stessi dati di processo.
- Il servizio Dequeue Broker si occupa del recupero dei dati delle code di lavoro dal datastore e li memorizza nella cache nei buffer di memoria locale. Il precaricamento ridurrà la latenza quando un pool di nodi di lavoro estrae i lavori da una coda dei lavori perché il buffer di memoria è molto più veloce dell’archivio dati. Inoltre, il disaccoppiamento di accodamento e accodamento dal servizio di risparmio eliminerà qualsiasi potenziale impatto su accodamento e rimozione dalla coda.
- I pod di lavoro dedicati per una coda di lavoro vengono allocati su K8, invece di condividere host di lavoro con altre code di lavoro in Pinlater. Questo elimina completamente l’impatto delle esecuzioni dei lavori da diverse code di lavoro. Inoltre, questo rende possibile la personalizzazione dell’allocazione delle risorse e la pianificazione di una coda di lavoro grazie all’ambiente di runtime indipendente in modo da migliorare l’efficienza dell’hardware.
Migrando le code di lavoro esistenti in Pinlater a Pacer, finora sono stati raggiunti alcuni miglioramenti:
- La contesa di blocco è completamente scomparsa nel datastore a causa del nuovo meccanismo di estrazione dei dati
- L’efficienza complessiva dell’utilizzo dell’hardware è notevolmente migliorata, inclusi datastore e host di lavoro.
- Il lavoro viene eseguito in modo indipendente nel proprio ambiente, con configurazione personalizzata, che ha prestazioni migliorate (rispetto a quella di Pinlater).
Come mostrato sopra, in Pacer vengono introdotti nuovi componenti per risolvere vari problemi in Pinlater. Vale la pena menzionare alcuni punti con maggiori dettagli.
Frazionamento dei dati del lavoro
In Pinlater, ogni coda di lavoro ha una partizione in ogni frammento del cluster di datastore, indipendentemente dalla quantità di dati e traffico di una coda di lavoro. Ci sono alcuni problemi con questo design.
- Le risorse sono sprecate. Anche per le code di lavoro con piccoli volumi di dati, viene creata una partizione in ogni frammento del datastore e può contenere pochissimi dati o nessun dato. Poiché il servizio di risparmio deve eseguire la scansione di ogni partizione per ottenere un numero sufficiente di lavori, ciò comporta chiamate extra al datastore. In base alle metriche, oltre il 50% delle chiamate ottiene risultati vuoti prima di ottenere i dati.
- La contesa dei blocchi peggiora in alcuni scenari, come quando più thread di servizi di risparmio competono per pochi dati di una piccola coda di lavoro in un frammento. L’archivio dati deve utilizzare le proprie risorse per mitigare la contesa dei blocchi durante l’interrogazione dei dati.
- Alcune funzionalità non possono essere supportate, ad esempio le esecuzioni dei lavori di una coda dei lavori in ordine cronologico di tempo di accodamento (FIFO), poiché i lavoratori estraggono i lavori da più shard contemporaneamente e non può essere garantito alcun ordine globale ma solo l’ordine locale.
In Pacer, vengono apportati i seguenti miglioramenti.
- Una coda di processi verrà partizionata in frammenti parziali del datastore a seconda del volume di dati e del traffico. Viene creata una mappatura di quali shard contengono i dati di una coda di processi.
- La contesa dei blocchi nel datastore può essere affrontata con l’aiuto di un livello dedicato del servizio di broker di rimozione dalla coda. E il broker di rimozione dalla coda non ha bisogno di interrogare ogni frammento di archivio dati per una coda perché sa quale frammento di archivio dati memorizza le partizioni di una coda.
- È possibile il supporto per alcune funzionalità, ad esempio l’esecuzione in ordine cronologico, purché venga creata una sola partizione per una coda di lavoro.
Servizio di broker di rimozione dalla coda con Helix e Zookeeper
Il broker di rimozione dalla coda in Pacer risolve molteplici limitazioni critiche in Pinlater eliminando la contesa di blocco nel datastore.
Il broker di rimozione dalla coda è in esecuzione come servizio con stato e una partizione di una coda processi verrà assegnata a un broker specifico nel cluster. Questo broker è responsabile dell’estrazione dei dati del lavoro dalla tabella corrispondente esclusivamente in un frammento di datatore e nessuna concorrenza tra broker diversi. Il nuovo modo di recupero deterministico del lavoro senza conflitto di blocco nelle risorse Pacer in MySQL ospita in modo più efficiente il recupero effettivo del lavoro (invece di gestire i problemi di blocco).
Buffer di coda in un broker
Quando un broker di rimozione dalla coda estrae i dati del lavoro dallo storage di destinazione, inserisce i dati in un buffer in memoria appropriato per consentire ai lavoratori di ottenere i lavori con una latenza ottimale. Verrà creato un buffer dedicato per ogni partizione della coda e la sua capacità massima verrà impostata per evitare un uso eccessivo della memoria nell’host del broker.
Una coda thread-safe viene utilizzata come buffer perché più worker riceveranno lavori dallo stesso broker contemporaneamente e le richieste di rimozione dalla coda per la stessa partizione di una coda processi verranno elaborate in sequenza dal broker di rimozione dalla coda. L’invio di processi dal buffer in memoria è un’operazione semplice con una latenza minima. Le nostre statistiche mostrano che la latenza della richiesta di rimozione dalla coda è inferiore a 1 ms.
Gestione delle risorse del broker di rimozione dalla coda
Come accennato in precedenza, una coda verrà suddivisa in più partizioni e a un broker verrà assegnata una o più partizioni di una coda processi. Gestire un numero elevato di partizioni e assegnarle in modo ottimale ai broker appropriati è una delle sfide principali. Come framework di gestione cluster generico utilizzato per la gestione automatica di risorse partizionate, replicate e distribuite ospitate su un cluster di nodi, Elica viene utilizzato per il caso d’uso di sharding e gestione delle partizioni di coda.
La figura sopra mostra l’architettura generale di come Helix interagisce con i broker di dequeue.
- Zookeeper viene utilizzato per comunicare le configurazioni delle risorse tra il controller Helix e i broker di rimozione dalla coda e altre informazioni rilevanti.
- Il controller Helix monitora costantemente gli eventi che si verificano nel cluster del broker di annullamento della coda, ad esempio le modifiche alla configurazione e l’unione e l’uscita degli host del broker di annullamento della coda. Con l’ultimo stato del cluster del broker di rimozione dalla coda, il controller Helix tenta di calcolare uno stato ideale delle risorse e invia messaggi al cluster del broker di rimozione dalla coda tramite Zookeeper per portare gradualmente il cluster allo stato ideale.
- Ogni singolo host di dequeue broker continuerà a riferire a Zookeeper sulla sua attività e riceverà una notifica quando le attività assegnategli cambieranno. In base al messaggio di notifica, l’host del broker di rimozione dalla coda cambierà il proprio stato locale.
Una volta create/aggiornate le informazioni sulla partizione di una coda, Helix riceverà una notifica in modo che possa assegnare queste partizioni ai broker di rimozione dalla coda.
Questo lavoro è il risultato della collaborazione tra più team di Pinterest. Si ringraziano le seguenti persone che hanno contribuito a questo progetto:
- Servizi principali: Mauricio Rivera, Yan Li, Harekam Singh, Sidharth Eric, Carlo De Guzman
- Data Org: Ambud Sharma
- Archiviazione e memorizzazione nella cache: Oleksandr Kuzminskyi, Ernie Souhrada, Lianghong Xu
- Cloud Runtime: Jiajun Wang, Harry Zhang, David Westbrook
- Notifiche: Eric Tam, Lin Zhu, Xing Wei
Per saperne di più sull’ingegneria in Pinterest, dai un’occhiata al resto del nostro Blog di ingegneria e visita il nostro Laboratori Pinterest luogo. Per esplorare la vita su Pinterest, visita il nostro Carriere pagina.