
Nel rapporto, Andrei Borodin parlerà di come hanno tenuto conto dell'esperienza di scalabilità di PgBouncer durante la progettazione del connection pooler. , come è stato introdotto in produzione. Inoltre, discuteremo quali funzioni del pooler ci piacerebbe vedere nelle nuove versioni: è importante per noi non solo soddisfare le nostre esigenze, ma anche sviluppare la comunità degli utenti. .
Video:


Ciao a tutti! Mi chiamo Andrei.

In Yandex mi occupo dello sviluppo di database open source. Oggi parleremo del connection pooler.

Se sai come si chiama il connection pooler in russo, fammelo sapere. Vorrei davvero trovare un buon termine tecnico che si affermi nella letteratura tecnica.
L'argomento è piuttosto complesso, perché in molti database il connection pooler è integrato e non è nemmeno necessario saperlo. Ci sono sicuramente alcune impostazioni ovunque, ma in Postgres non funziona così. Parallelamente, a HighLoad++ 2019, si svolgerà una presentazione di Nikolay Samokhvalov sulla configurazione delle query in Postgres. E da quello che capisco, sono venute persone che hanno già configurato le query in modo impeccabile, e queste persone affrontano problemi sistemici più rari, legati alla rete e all'utilizzo delle risorse. E a volte può essere piuttosto complicato nel senso che i problemi non sono evidenti.

In Yandex abbiamo Postgres. In Yandex.Cloud vivono molti servizi di Yandex. E abbiamo diversi petabyte di dati che generano non meno di un milione di richieste al secondo in Postgres.

E forniamo un cluster piuttosto standard a tutti i servizi: è il nodo primario principale, due repliche normali (una sincrona e una asincrona), backup e scaling delle query di lettura sulla replica.

Ogni nodo del cluster è un Postgres, su cui oltre a Postgres e ai sistemi di monitoraggio è installato anche il connection pooler. Il connection pooler è utilizzato per il fencing e per il suo scopo principale.

Qual è lo scopo principale del connection pooler?

In Postgres si adotta un modello basato su processi quando si lavora con il database. Questo significa che una connessione è un processo, un backend di Postgres. E in questo backend ci sono molti cache diversi, che è piuttosto costoso avere diversi per diverse connessioni.

Inoltre, nel codice Postgres c'è un array chiamato procArray. Contiene le informazioni principali sulle connessioni di rete. E quasi tutti gli algoritmi che elaborano il procArray hanno una complessità lineare, poiché attraversano tutto l'array delle connessioni di rete. Questo è un ciclo abbastanza veloce, ma con un numero elevato di connessioni in entrata tutto diventa un po' più costoso. Quando tutto diventa un po' più costoso, alla fine si può pagare un prezzo molto alto per un gran numero di connessioni di rete.

Esistono 3 approcci possibili:
- Dalla parte dell'applicazione.
- Dalla parte del database.
- E in mezzo, cioè tutte le possibili combinazioni.
Sfortunatamente, il pooler integrato è attualmente in fase di sviluppo. Gli amici della PostgreSQL Professional stanno principalmente lavorando su questo. Quando sarà disponibile, è difficile prevederlo. In effetti, l'architetto ha due soluzioni tra cui scegliere. Questo è un pool a livello di applicazione e un proxy pool.

Il pool a livello di applicazione è il modo più semplice. E quasi tutti i driver client vi offrono un modo per rappresentare milioni delle vostre connessioni nel codice come alcune dozzine di connessioni al database.

Sorge un problema quando a un certo punto volete scalare il backend, volete distribuirlo su molte macchine virtuali.

Poi vi rendete conto che avete anche diverse zone di disponibilità, diversi data center. E l'approccio con il client side pooling porta a numeri elevati. Elevati sono circa 10.000 connessioni. Questo è il limite che può funzionare normalmente.

Parlando dei proxy poolers, ci sono due poolers che sanno fare molte cose. Non sono solo poolers. Sono poolers + un'ottima funzionalità. Questo è e .
Ma sfortunatamente, questa funzionalità aggiuntiva non è necessaria per tutti. E porta al fatto che i poolers supportano solo il pooling di sessione, cioè un client in entrata, un client in uscita nel database.
Per le nostre esigenze, questo non è molto adatto, quindi utilizziamo PgBouncer, che implementa il transaction pooling, cioè le connessioni del server sono associate alle connessioni dei client solo durante la transazione.

E sulla nostra carico – è vero. Ma ci sono alcuni problemi.
I problemi iniziano quando volete diagnosticare una sessione, perché tutte le connessioni in entrata sono locali. Tutte provengono dal loopback e quindi è difficile tracciare la sessione.

Certo, puoi utilizzare application_name_add_host. Questo è un modo per Bouncer di aggiungere un indirizzo IP a application_name. Ma application_name è impostato tramite una connessione aggiuntiva.

In questo grafico, dove la linea gialla rappresenta le richieste reali e la linea blu rappresenta le richieste che arrivano al database. E questa differenza è precisamente l'impostazione di application_name, che è necessaria solo per il tracciamento, ma non è affatto gratuita.

Inoltre, in Bouncer non è possibile limitare un pool, ovvero il numero di connessioni al database per un determinato utente su un determinato database.

A cosa porta questo? Hai un servizio pesantemente carico, scritto in C++, e accanto a esso un piccolo servizio in Node che non fa nulla di terribile con il database, ma il suo driver impazzisce. Apre 20.000 connessioni e tutto il resto aspetta. Anche il tuo codice è a posto.

Naturalmente, abbiamo scritto una piccola patch per Bouncer che ha aggiunto questa impostazione, cioè la limitazione dei clienti sul pool.

Si potrebbe fare questo lato Postgres, cioè limitare i ruoli nel database con un numero massimo di connessioni.

Ma in tal caso perdi la possibilità di capire perché non hai connessioni con il server. PgBouncer non inoltra l'errore di connessione, restituisce sempre la stessa informazione. E non puoi capire: forse la tua password è cambiata, forse semplicemente il database è andato giù, forse c'è qualcosa che non va. Ma non ci sono diagnosi. Se la sessione non può essere stabilita, non scopri perché non sia possibile farlo.

A un certo punto guardi i grafici dell'applicazione e vedi che l'app non funziona.

Guardi nel top e vedi che Bouncer è a thread singolo. Questo è un punto di svolta nella vita del servizio. Realizzi che ti stavi preparando a scalare il database tra un anno e mezzo, mentre devi scalare il pooler.

Siamo arrivati alla conclusione che abbiamo bisogno di più PgBouncer.

Abbiamo fatto qualche piccolo patch su Bouncer.

E abbiamo fatto in modo che possano essere avviati più Bouncer riutilizzando la porta TCP. E il sistema operativo smista automaticamente le connessioni TCP in entrata tra di loro con round-robin.

Questo è trasparente per i clienti, cioè tutto appare come se avessi un solo Bouncer, ma hai una frammentazione delle connessioni idle tra i Bouncer in esecuzione.

E a un certo punto potresti notare che questi 3 Bouncers consumano ciascuno il proprio core al 100%. Hai bisogno di un numero consistente di Bouncers. Perché?

Perché hai TLS. Hai una connessione crittografata. E se esegui un benchmark di Postgres con TLS e senza TLS, scoprirai che il numero di connessioni stabilite diminuisce quasi di due ordini di grandezza con l'attivazione della crittografia, poiché il handshake TLS consuma risorse della CPU.

E nella parte superiore puoi vedere molte funzioni crittografiche che vengono eseguite durante l'ondata di connessioni in arrivo. Poiché il nostro primary può passare tra le zone di disponibilità, l'ondata di connessioni in arrivo è una situazione piuttosto tipica. Cioè, per qualche motivo il vecchio primary è stato non disponibile, e tutto il carico è stato inviato in un altro data center. Arriveranno tutti contemporaneamente a salutare con TLS.

E un grande numero di handshake TLS potrebbe non salutare già con Bouncer, ma strangolarlo. A causa del timeout, l'ondata di connessioni in arrivo potrebbe diventare non attenuabile. Se hai retry nel database senza exponential backoff, non arriveranno nuovamente e nuovamente come un'ondata coerente.

Ecco un esempio di 16 PgBouncer che caricano 16 core al 100%.

Siamo arrivati al PgBouncer a cascata. Questa è la configurazione migliore che possiamo ottenere con il nostro carico con Bouncer. I Bouncers esterni servono per il TCP handshake, mentre i Bouncers interni servono per il vero pooling, per non frammentare eccessivamente le connessioni esterne.

In questa configurazione è possibile un riavvio graduale. È possibile riavviare tutti questi 18 Bouncers uno alla volta. Ma mantenere tale configurazione è piuttosto complicato. Gli amministratori di sistema, DevOps e le persone che sono veramente responsabili di questo server non saranno molto felici di questo schema.

Potrebbe sembrare che possiamo promuovere tutte le nostre modifiche come open source, ma Bouncer non è molto ben supportato. Per esempio, la possibilità di avviare più PgBouncer sulla stessa porta è stata impegnata un mese fa. E la pull request con questa funzione è stata presentata qualche anno fa.

Oppure un altro esempio. In Postgres puoi annullare una query in esecuzione inviando un segreto su un altro collegamento senza necessità di autenticazione aggiuntiva. Ma alcuni client inviano semplicemente un TCP-reset, cioè interrompono la connessione di rete. Cosa farà quindi Bouncer? Non farà nulla. Continuerebbe ad eseguire la query. Se hai ricevuto un numero enorme di connessioni che hanno sovraccaricato il database con piccole query, semplicemente scollegare Bouncer non sarà sufficiente; dovrai anche terminare quelle query attive nel database.
Questo è stato corretto e il problema non è ancora stato integrato nell'upstream di Bouncer.

E così siamo arrivati al punto in cui abbiamo bisogno del nostro connection pooler, che si svilupperà, verrà patchato, e nel quale sarà possibile risolvere rapidamente i problemi, e che, ovviamente, deve essere multithreaded.

Abbiamo impostato il multithreading come obiettivo principale. Dobbiamo gestire bene l'ondata di connessioni TLS in arrivo.
Per questo abbiamo dovuto sviluppare una libreria separata chiamata Machinarium, progettata per descrivere gli stati della macchina della connessione di rete come codice sequenziale. Se guardi nel codice sorgente di libpq, vedrai chiamate piuttosto complesse che possono restituirti un risultato e dirti: "Chiamami più tardi. Adesso ho IO, ma quando l'IO sarà completato, avrò carico per il processore". Ed è uno schema multistrato. L'interazione di rete è di solito descritta come una macchina a stati. Con molte regole tipo "Se ho ricevuto prima l'intestazione di un pacchetto di dimensione N, allora ora sto aspettando N byte", "Se ho inviato un pacchetto SYNC, allora adesso aspetto un pacchetto di metadati del risultato". Risulta un codice piuttosto difficile e controintuitivo, come se un labirinto fosse stato trasformato in una srotolatura lineare. Abbiamo fatto in modo che, invece di una macchina a stati, il programmatore descriva il percorso principale di interazione in forma di codice imperativo ordinario. Semplicemente, in questo codice imperativo è necessario inserire punti in cui la sequenza di esecuzione deve essere interrotta per attendere dati dalla rete, passando il contesto di esecuzione a un'altra coroutine (green thread). Questo approccio è simile a quello di registrare consecutivamente il percorso più atteso in un labirinto, e poi aggiungere ramificazioni ad esso.

In definitiva, abbiamo un flusso che esegue l'accettazione TCP e trasmette in round robin una connessione TPC a numerosi workers.
Inoltre, ogni connessione client funziona sempre su un solo processore. Questo lo rende cache-friendly.
Inoltre, abbiamo migliorato un po' la raccolta di piccoli pacchetti in un grande pacchetto per alleggerire lo stack TCP di sistema.

In aggiunta, abbiamo migliorato il pooling transazionale in modo che Odyssey, con la configurazione corretta, possa inviare CANCEL e ROLLBACK in caso di interruzione della connessione di rete, cioè, se non c'è nessuno che attende la richiesta, Odyssey dirà al database di non sforzarsi di eseguire quella richiesta che potrebbe consumare risorse preziose.
E, se possibile, manteniamo le connessioni con lo stesso client. Questo evita la reinstallazione di application_name_add_host. Se possibile, non abbiamo reinstallazioni aggiuntive dei parametri necessari per la diagnosi.

Lavoriamo nell'interesse di Yandex.Cloud. E se state utilizzando PostgreSQL gestito e avete impostato un connection pooler, potete creare una replica logica verso l'esterno, cioè allontanarvi da noi, se lo desiderate, tramite replica logica. Bouncer non restituirà verso l'esterno il flusso di replica logica.

Questo è un esempio di configurazione della replica logica.

Inoltre, abbiamo il supporto per la replica fisica verso l'esterno. In Cloud, ovviamente, non è possibile, poiché allora il cluster vi fornirebbe troppe informazioni su di sé. Ma nelle vostre installazioni, se avete bisogno di replica fisica tramite connection pooler in Odyssey, è possibile.

In Odyssey, ci sono monitoraggi completamente compatibili con PgBouncer. Abbiamo la stessa console che esegue quasi tutti gli stessi comandi. Se manca qualcosa, inviateci una pull request, o almeno un problema su GitHub, e ci occuperemo di implementare i comandi necessari. Ma la funzionalità principale della console PgBouncer è già presente.

E, naturalmente, abbiamo il forwarding degli errori. Restituiremo l'errore segnalato dal database. Riceverete informazioni sul motivo per cui non riuscite a entrare nel database e non solo che non ci riuscite.

Questa funzionalità può essere disattivata nel caso in cui abbiate bisogno di una compatibilità 100% con PgBouncer. Possiamo comportarci come Bouncer, giusto per sicurezza.
Sviluppo
Qualche parola sul codice sorgente di Odyssey.

Ad esempio, ci sono i comandi «Pause / Resume». Di solito vengono utilizzati per aggiornare il database. Se hai bisogno di aggiornare Postgres, puoi metterlo in pausa nel connection pooler, eseguire pg_upgrade e poi riprendere. E dal punto di vista del client sembrerà che il database si stesse semplicemente bloccando. Questa funzionalità ci è stata portata da persone della comunità. Non è ancora stata fusa, ma presto tutto sarà. (Già fusa)

— già fusa
Inoltre, una delle nuove funzionalità in PgBouncer è il supporto per SCRAM Authentication, che ci è stata portata da una persona che non lavora in Yandex.Cloud. Entrambi sono funzionalità complesse e importanti.

Perciò, voglio raccontarvi come è fatto Odyssey, magari anche voi volete scrivere un po' di codice.
Hai il codice sorgente di Odyssey, che si basa su due librerie principali. La libreria Kiwi è l'implementazione del protocollo di messaggi di Postgres. Cioè, il proto nativo 3 di Postgres sono i messaggi standard con cui i frontend e i backend possono scambiarsi informazioni. Sono implementati nella libreria Kiwi.
La libreria Machinarium è una libreria per l'implementazione dei flussi. Un piccolo frammento di questo Machinarium è scritto in assembler. Ma, non spaventarti, sono solo 15 righe.

L'architettura di Odyssey. C'è una macchina principale in cui sono eseguite le coroutines. In questa macchina viene implementato l'accettare connessioni TCP in ingresso e distribuirle tra i workers.
All'interno di un worker può lavorare un elaboratore di diversi client. Inoltre, nel thread principale girano la console e l'elaborazione delle crone-task per rimuovere le connessioni che non sono più necessarie nel pool.

Per testare Odyssey viene utilizzato un set standard di test di Postgres. Semplicemente eseguiamo install-check tramite Bouncer e tramite Odyssey, otteniamo un div nullo. Ci sono diversi test relativi al formato delle date che non passano affatto allo stesso modo in Bouncer e in Odyssey.
Inoltre, ci sono molti driver che hanno i propri test. E utilizziamo i loro test per testare Odyssey.

Inoltre, a causa della nostra configurazione cascata, dobbiamo testare diverse combinazioni: Postgres + Odyssey, PgBouncer + Odyssey, Odyssey + Odyssey, per essere certi che, se Odyssey si trova in una delle parti della cascata, continui a funzionare come ci aspettiamo.
Grattacapo

Utilizziamo Odyssey in produzione. E non sarebbe giusto se dicessi che tutto funziona semplicemente. No, cioè, sì, ma non sempre. Ad esempio, in produzione tutto funzionava perfettamente, poi sono arrivati i nostri amici di PostgreSQL Professional e ci hanno detto che avevamo una memory leak. Loro avevano ragione, l'abbiamo corretta. Ma è stato davvero un colpo.

Poi abbiamo scoperto che nel connection pooler ci sono connessioni TLS in ingresso e connessioni TLS in uscita. E per le connessioni sono necessari certificati client e certificati server.
I certificati server di Bouncer e Odyssey leggono il loro pcache, ma non è necessario rileggere i certificati client dal pcache, perché il nostro Odyssey scalabile finisce per urtare le prestazioni di sistema nella lettura di quel certificato. Questo è stato per noi una sorpresa, perché si è manifestato ben dopo. All'inizio si era scalato linearmente, ma dopo 20.000 connessioni simultanee in ingresso, il problema si è presentato.

Il Pluggable Authentication Method è la possibilità di autenticarsi con i mezzi integrati di Linux. In PgBouncer è realizzato in modo tale che esiste un thread separato in attesa di una risposta da PAM e un thread principale di PgBouncer che gestisce la connessione attuale e può chiedere loro di rimanere nel thread PAM.
Non abbiamo deciso di implementare questo per una semplice ragione. Abbiamo molti thread. A cosa ci serve?
In effetti, questo può creare problemi, poiché se hai autenticazione PAM e autenticazione non PAM, una grande ondata di autenticazione PAM può ritardare significativamente l'autenticazione non PAM. Questa è una delle cose che non abbiamo risolto. Ma se vuoi sistemarlo, puoi occuparti di questo.

Un altro problema era che avevamo un thread che accettava tutte le connessioni in ingresso. E poi le trasmetteva al worker pool, dove si svolgerà il TLS handshake.
Di conseguenza, se hai un'ondata coerente di 20.000 connessioni di rete, verranno tutte accettate. E sul lato client, libpq inizierà a contare i timeout. Di default sembra che ci sia un'impostazione di 3 secondi.
Se non possono tutte accedere contemporaneamente al database, non possono entrare nel database, perché tutto ciò potrebbe essere coperto da un retry non esponenziale.
Siamo giunti al punto di copiare qui lo schema di PgBouncer, in cui abbiamo il throttling del numero di connessioni TCP a cui facciamo accept.
Se vediamo che accettiamo le connessioni, ma alla fine non riescono a completare il handshake, le mettiamo in coda per evitare che consumino risorse della CPU. Questo porta al fatto che il handshake simultaneo potrebbe non avvenire per tutte le connessioni ricevute. Ma almeno qualcuno entrerà nel database, anche se il carico è abbastanza elevato.
Roadmap
Cosa ci piacerebbe vedere in futuro in Odyssey? Cosa siamo pronti a sviluppare noi stessi e cosa ci aspettiamo dalla comunità?

A agosto 2019.
Ecco come si presentava la roadmap di Odyssey ad agosto:
- Volevamo l'autenticazione SCRAM e PAM.
- Volevamo l'inoltro delle query di lettura verso il standby.
- Ci piacerebbe un riavvio online.
- E la possibilità di mettere in pausa un server.

Metà di questa roadmap è stata completata, e non da noi. Ed è positivo. Pertanto, discutiamo di ciò che resta e aggiungiamo altro.

? У нас есть реплики, которые без выполнения запросов будут просто греть воздух. Они нам необходимы для обеспечения failover и switchover. В случае проблем в одном из дата-центре хотелось бы их занять какой-то полезной работой. Потому что те же самые центральные процессоры, ту же самую память мы не можем сконфигурировать по-другому, потому что иначе не будет работать репликация.

Fondamentalmente, in Postgres, a partire dalla versione 10 c'è la possibilità di specificare anche session_attrs durante la connessione. Nella connessione puoi elencare tutti gli host del database e dire perché ti connetti al database: per scrivere o solo per leggere. E il driver sceglierà automaticamente il primo host della lista che preferisce, che soddisfa i requisiti di session_attrs.

Ma il problema di questo approccio è che non controlla il ritardo di replica. Potresti avere una replica che è in ritardo di un tempo inaccettabile per il tuo servizio. Per garantire l'esecuzione funzionale delle query di lettura sulla replica, in sostanza, è necessario garantire in Odyssey la possibilità di non lavorare quando la lettura non è possibile.
Odyssey dovrebbe occasionalmente interrogare il database per verificare la distanza di replica dal primary. E se questa distanza ha raggiunto un valore limite, non consentire nuove query al database, informare il cliente che deve riavviare le connessioni e, possibilmente, scegliere un altro host per eseguire le query. Questo permetterà al database di ripristinare più rapidamente il ritardo di replica e tornare a rispondere alle query.
È difficile fornire una tempistica di implementazione, poiché si tratta di open source. Ma spero che non saranno 2,5 anni come per i colleghi di PgBouncer. Vorremmo vedere questa funzionalità in Odyssey.

. Ora puoi creare una prepared statement in due modi. Innanzitutto, puoi eseguire il comando SQL, ovvero "prepared". Per capire questo comando SQL, dobbiamo imparare a comprendere SQL dal lato di Bouncer. Sarebbe un eccesso, perché abbiamo bisogno di un parser completo. Non possiamo analizzare ogni comando SQL.
Ma esiste una prepared statement a livello del protocollo di messaggistica su proto3. Ed è in questo momento che l'informazione riguardante la creazione della prepared statement viene ricevuta in formato strutturato. E potremmo supportare la comprensione di ciò che, su qualche connessione server, il client ha richiesto per creare prepared statements. E anche se la transazione si è chiusa, dobbiamo comunque mantenere la coerenza tra server e client.
Ma qui sorge una discrepanza nel dialogo, perché qualcuno parla di dover comprendere quale specifica prepared statement ha creato il client e dividere la connessione server tra tutti i client che hanno creato quella connessione server, cioè che hanno creato quella prepared statement.
Andres Freund ha detto che se ti arriva un client che ha già creato una preparata statement in un'altra connessione server, creala per lui. Ma, sembra, sia un po' sbagliato eseguire le query sul database al posto del client, ma dal punto di vista dello sviluppatore che scrive il protocollo di interazione con il database, sarebbe comodo se gli venisse semplicemente fornita una connessione di rete che ha una tale query preparata.

E un'altra funzionalità che dobbiamo implementare. Attualmente abbiamo un monitoraggio compatibile con PgBouncer. Possiamo restituire il tempo medio di esecuzione della query. Ma il tempo medio è come la temperatura media in ospedale: qualcuno è freddo, qualcun altro è caldo – mediamente tutti sono sani. Non è vero.
Dobbiamo implementare il supporto per i percentili, che indicano che ci sono query lente che consumano risorse, rendendo il monitoraggio più accettabile.

Infine, desidero la versione 1.0 (è già uscita la versione 1.1). Il punto è che ora Odyssey si trova nella versione 1.0rc, cioè release candidate. E tutte le problematiche che ho elencato sono state risolte proprio con quella versione, eccetto il memory leak.
Cosa significherà per noi la versione 1.0? Stiamo lanciando Odyssey sui nostri database. Funziona già sui nostri database, ma quando raggiungerà il milione di richieste al secondo, potremo dire che questa è la versione stabile e che può essere chiamata 1.0.
Nel nostro gruppo, alcune persone hanno chiesto che nella versione 1.0 siano inclusi anche il pause e lo SCRAM. Ma ciò significherebbe che dovremmo rilasciare la prossima versione in produzione, perché né SCRAM né la pausa sono ancora stati fusi. Tuttavia, probabilmente questa questione sarà risolta abbastanza rapidamente.

Aspetto le vostre pull request. Vorrei anche sapere quali problemi avete riscontrato con Bouncer. Discutiamone. Forse possiamo implementare alcune funzionalità di cui avete bisogno.
Con questo la mia parte è finita, vorrei ascoltarvi. Grazie!
Domande
Se imposto il mio application_name, verrà correttamente propagato, anche nel transaction pooling in Odyssey?
In Odyssey o in Bouncer?
In Odyssey. In Bouncer viene propagato.
Faremo il set.
E se la mia connessione reale salta su altre connessioni, verrà trasferita?
Faremo il set di tutti i parametri elencati nella lista. Non posso dire se in questa lista ci sia application_name. Mi sembra di averlo visto. Imposteremo gli stessi parametri. Con una richiesta, il set farà tutto ciò che è stato impostato dal client all'avvio.
Grazie, Andrej, per la presentazione! È stata una buona presentazione! Sono felice che Odyssey stia evolvendo sempre più rapidamente. Spero che continui così. Abbiamo già contattato voi con la richiesta di avere una connessione multi data-source, affinché Odyssey possa connettersi contemporaneamente a diversi database, cioè master-slave, e poi automaticamente, dopo un failover, connettersi al nuovo master.
Sì, mi sembra di ricordare questa discussione. Attualmente ci sono diversi storage. Ma non ci sono passaggi tra di loro. Dobbiamo interrogare il server per verificare se è ancora attivo e capire che è avvenuto un failover, chi chiamerà pg_recovery. Ho un modo standard per capire che non siamo arrivati al master. E dobbiamo capire in qualche modo dagli errori o come? Cioè, l'idea è interessante, se ne sta discutendo. Scrivete più commenti. Se avete mani esperte che conoscono C, sarebbe davvero fantastico.
La questione della scalabilità delle repliche ci interessa anche, perché vogliamo rendere l'adozione dei cluster replicati il più semplice possibile per gli sviluppatori dell'applicazione. Ma qui ci piacerebbe avere più commenti, cioè come farlo e come farlo bene.
La domanda riguarda anche le repliche. Risulta che avete un master e diverse repliche. È chiaro che le chiamate alla replica avvengono meno frequentemente rispetto al master, poiché potrebbero esserci delle differenze. Avete detto che le differenze nei dati potrebbero essere tali da non soddisfare il vostro business e non le consulterete finché non saranno replicate. Inoltre, se non vi accedete per un lungo periodo e poi iniziate a farlo, i dati necessari non saranno immediatamente disponibili. Cioè, se accediamo continuamente al master, la cache è calda, mentre nella replica la cache è un po' indietro.
Sì, è vero. Nel pcache non ci saranno i blocchi di dati che desiderate, nel real cache non ci sarà informazione sulle tabelle che volete, nei piani non ci saranno le query parsate, insomma non ci sarà nulla.
E quando avete un cluster e aggiungete una nuova replica, finché si avvia, la situazione non è buona, cioè sta accumulando la sua cache.
Ho capito l'idea. L'approccio corretto sarebbe iniziare a inviare una piccola percentuale delle query inizialmente alla replica, per scaldare la cache. In breve, abbiamo la condizione che non dobbiamo essere indietro di oltre 10 secondi rispetto al master. E questa condizione deve essere attivata non in un colpo solo, ma gradualmente per alcuni clienti.
Sì, aumentare il peso.
È una buona idea. Ma prima dobbiamo implementare questo disattivazione. Dobbiamo prima disattivarci e poi penseremo a come riattivarci. È una grande caratteristica per attivarsi gradualmente.
In nginx c'è questa opzione slowly start per il server nel cluster. E aumenta gradualmente il carico.
Sì, ottima idea, proveremo quando ci arriveremo.
Fonte: habr.com
