Bagaimana cara terbaik menggunakan pooling koneksi di SQLAlchemy untuk pooling tingkat transaksi PgBouncer?


15

Menggunakan SQLAlchemy untuk query database PostgreSQL di belakang PgBouncer, menggunakan pooling tingkat transaksi.

Apa pola terbaik untuk digunakan untuk pengaturan semacam ini? Haruskah saya memiliki satu mesin per proses, menggunakan ConnectionPool, atau haruskah saya membuat mesin per permintaan, dan menggunakannya NullPooluntuk masing-masing? Apakah ada pola yang berbeda yang harus saya gunakan?

Terima kasih banyak! Beri tahu saya jika diperlukan lebih banyak informasi dan saya akan memperbarui ASAP.

Jawaban:


9

dengan PGBouncer, Anda mungkin ingin tetap menggunakan NullPool. Dalam hal ini, Anda mungkin dapat berbagi Mesin tunggal di seluruh subproses karena tidak ada koneksi soket yang akan dilakukan melewati batas subproses. Tetapi Anda tidak dapat membagikan apa pun yang merujuk ke objek Koneksi, seperti Sesi dengan transaksi aktif, melebihi batas ini. Anda pasti tidak ingin melakukan "engine-per-request", sebuah Engine adalah objek mahal yang mengumpulkan banyak informasi tentang URL basis data tertentu saat pertama kali melihatnya.


4

Tetapkan Nama Aplikasi

Jika Anda berharap menjalankan banyak proses, Anda perlu tahu dari mana mereka terhubung. PGBouncer akan membuat ini tidak terlihat pg_stat_activity. Selesaikan ini dengan hati-hati mengatur application_nameinformasi yang Anda perlukan:

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

Lebih suka Sesi

Gunakan Sesi karena permintaan dari objek Engine dapat memunculkan dan mempertahankan beberapa koneksi. Menghubungkan ke Postgres tidak terlalu mahal, dengan PGBouncer bahkan lebih murah. Saya akan selalu menggunakan NullPoolsatu-satunya koneksi yang akan Anda lihat di Postgres adalah koneksi yang benar-benar digunakan.

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

Hapuskan Transaksi Idle

Jika maksud Anda adalah menggunakan PGBouncer untuk mengukur, maka sangat penting bagi Anda untuk tidak membiarkan transaksi macet. Untuk melakukan ini, Anda perlu mengaktifkan autocommit di . Ini tidak sederhana dengan SQLAlchemy ... ada tiga tempat di mana sesuatu yang disebut "autocommit" dapat diatur:

psycopg2 autocommit

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

Dianggap tidak aman tidak aman karena SQLAlchemy perlu tahu apa yang terjadi di bawahnya.

Sesi autocommit

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

Ini membutuhkan penyerahan yang cermat dan eksplisit:

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

Panggilan fungsi dan penyerahan pengecualian sangat sulit karena begin()dan commit()tidak dapat disarangkan:

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

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

Dalam mode ini psycopg2 autocommittampaknya False(default)

Mesin autocommit

Mengatur mode isolasi Engine "AUTOCOMMIT"ketika membuat mesin menetapkan perilaku default baru yang mungkin tidak memerlukan perubahan kode yang ada.

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

Dalam mode ini autocommittampaknya psycopg2True

Masalah utama di sini adalah bahwa satu-satunya cara untuk menjamin bahwa satu blok kode dibungkus dalam transaksi adalah dengan memancarkan pernyataan secara manual:

session.execute("BEGIN")
#...
session.execute("COMMIT")
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.