Як найкраще використовувати об’єднання з'єднань у SQLAlchemy для об'єднання на рівні транзакцій PgBouncer?


15

Використання SQLAlchemy для запиту бази даних PostgreSQL позаду PgBouncer, використовуючи об'єднання рівня транзакцій.

Який найкращий зразок використовувати для такого типу налаштування? Чи повинен я мати один двигун на процес, використовуючи a ConnectionPoolчи я повинен створювати двигун на запит і використовувати NullPoolдля кожного з них? Чи існує взагалі інша картина, яку я повинен використовувати?

Дуже дякую! Повідомте мене, чи потрібно більше інформації, і я оновлю якнайшвидше.

Відповіді:


9

з PGBouncer, ви, ймовірно, хочете просто дотримуватися NullPool. У такому випадку ви можете мати спільний доступ до одного двигуна на підпроцесах, оскільки жодне з'єднання сокетів не буде здійснюватися через межу підпроцесу. Але ви не можете поділитися будь-яким посиланням на об’єкт З'єднання, як-от Сесія з активною транзакцією, через цей кордон. Ви, безумовно, не хочете робити "двигун за запитом", хоча, Двигун - це дорогий об'єкт, який накопичує багато інформації про певну URL-адресу бази даних у перший раз, коли вона це бачить.


4

Встановіть назву програми

Якщо ви очікуєте запуску багатьох процесів, вам потрібно знати, звідки вони з'єднуються. PGBouncer зробить це невидимим для pg_stat_activity. Вирішіть це, обережно встановивши application_nameпотрібну інформацію:

# 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)

Віддавайте перевагу сесіям

Використовуйте сеанси, оскільки запити від об'єкта Engine можуть нереститися та утримувати декілька з'єднань. Підключення до Postgres не дуже дороге, з PGBouncer це ще менше. Я завжди використовував би NullPoolтак, що єдині з'єднання, які ви побачите в Postgres, - це з'єднання, які фактично використовуються.

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

Усуньте непрацюючі транзакції

Якщо ваш намір полягає в тому, щоб використовувати PGBouncer для масштабування, необхідно обов'язково уникати транзакцій, які залишаються відкритими. Для цього вам необхідно звернутися autocommit в . З SQLAlchemy це не просто ... Є три місця, де можна встановити щось, що називається "автокомісія":

psycopg2 автокомісія

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

Вважається небезпечним, оскільки SQLAlchemy повинен знати, що відбувається внизу.

Сеанс автокомісії

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

Це вимагає обережного, чіткого вручення:

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

Функція виклику і виключення вручаючи надзвичайно важко , тому що begin()і commit()не може бути вкладеним:

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

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

У цьому режимі, як autocommitвидається, є psycopg2 False(за замовчуванням)

Автокомісія двигуна

Встановлення режиму ізоляції двигуна "AUTOCOMMIT"при створенні двигуна встановлює нову поведінку за замовчуванням, яка може не вимагати змін до існуючого коду.

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

У такому режимі, схоже, autocommitє psycopg2True

Найголовніша проблема тут полягає в тому, що єдиний спосіб гарантувати, що блок коду вкладено в транзакцію, - це випромінювати оператори вручну:

session.execute("BEGIN")
#...
session.execute("COMMIT")
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.