Come utilizzare al meglio il pool di connessioni in SQLAlchemy per il pooling a livello di transazione PgBouncer?


15

Utilizzo di SQLAlchemy per eseguire una query su un database PostgreSQL dietro PgBouncer, utilizzando il pooling a livello di transazione.

Qual è il modello migliore da utilizzare per questo tipo di installazione? Dovrei avere un motore per processo, usando un ConnectionPool, o dovrei creare un motore per richiesta, e usarlo NullPoolper ognuno di essi? C'è un modello completamente diverso che dovrei usare?

Grazie mille! Fammi sapere se sono necessarie ulteriori informazioni e aggiornerò al più presto.

Risposte:


9

con PGBouncer, probabilmente vorresti semplicemente restare con NullPool. In tal caso, potresti essere in grado di condividere un singolo motore tra sottoprocessi poiché nessuna connessione socket verrà trasferita oltre il limite del sottoprocesso. Ma non puoi condividere nulla che faccia riferimento a un oggetto Connection, come una Sessione con una transazione attiva, oltre questo limite. Sicuramente non vorrai fare "engine-per-request", un Engine è un oggetto costoso che accumula molte informazioni su un particolare URL del database la prima volta che lo vede.


4

Imposta il nome dell'applicazione

Se si prevede di eseguire molti processi, è necessario sapere da dove si connettono. PGBouncer lo renderà invisibile a pg_stat_activity. Risolvilo impostando application_namecon cura le informazioni necessarie:

# Sets the application name for this connection in the form of
#   application-name:user@host
prog = os.path.basename(sys.argv[0]) or 'desjob'
username = pwd.getpwuid (os.getuid ()).pw_name
hostname = socket.gethostname().split(".")[0
args.setdefault('connect_args', {'application_name': "%s:%s@%s" %
    (prog, username, hostname)})
args.setdefault('isolation_level', "AUTOCOMMIT")
engine = create_engine(url, **args)

Preferisci sessioni

Utilizzare le sessioni poiché le richieste da un oggetto Engine possono essere generate e trattenute su più connessioni. La connessione a Postgres non è molto costosa, con PGBouncer lo è ancora di meno. Userei sempre in NullPoolmodo che le uniche connessioni che vedrai in Postgres siano le connessioni effettivamente utilizzate.

from sqlalchemy.pool import Pool, NullPool
engine = create_engine(uri, poolclass=NullPool)

Elimina le transazioni inattive

Se il tuo intento è utilizzare PGBouncer per ridimensionare, è indispensabile evitare di lasciare aperte le transazioni. Per fare questo è necessario attivare autocommit su . Questo non è semplice con SQLAlchemy ... ci sono tre posti in cui è possibile impostare qualcosa chiamato "autocommit":

psycopg2 autocommit

conn = psycopg2.connect(uri)
conn.autocommit = True

Si presume che non sia sicuro, poiché SQLAlchemy deve sapere cosa sta accadendo sotto.

Sessione autocommit

Session = sessionmaker(bind=engine, autocommit=True)
session = Session()

Ciò richiede una consegna attenta ed esplicita:

session.begin()
session.execute(...)
session.rollback()

La chiamata di funzione e la gestione delle eccezioni sono estremamente difficili perché begin()e commit()non possono essere nidificate:

def A():
  session.begin()
  ...
  session.rollback()

def B():
  session.begin()
  try:
      A() # error, already open

In questa modalità psycopg2 autocommitsembra essere False(impostazione predefinita)

Autocommit motore

L'impostazione della modalità di isolamento del motore su "AUTOCOMMIT"quando si crea il motore stabilisce un nuovo comportamento predefinito che potrebbe non richiedere modifiche al codice esistente.

engine = create_engine(uri, isolation_level="AUTOCOMMIT")

In questa modalità autocommitsembra essere psycopg2True

Il problema principale qui è che l'unico modo per garantire che un blocco di codice sia racchiuso in una transazione è di emettere le istruzioni manualmente:

session.execute("BEGIN")
#...
session.execute("COMMIT")
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.