Làm cách nào để sử dụng tốt nhất nhóm kết nối trong SQLAlchemy cho nhóm tổng hợp cấp độ giao dịch của PGBouncer?


15

Sử dụng SQLAlchemy để truy vấn cơ sở dữ liệu PostgreQuery đằng sau PGBouncer, sử dụng nhóm mức giao dịch.

Mẫu tốt nhất để sử dụng cho loại thiết lập này là gì? Tôi nên có một động cơ cho mỗi quá trình, sử dụng một ConnectionPoolhoặc tôi nên tạo một động cơ cho mỗi yêu cầu và sử dụng NullPoolcho mỗi một trong số chúng? Có một mô hình khác nhau mà tôi nên sử dụng không?

Cảm ơn rất nhiều! Hãy cho tôi biết nếu cần thêm thông tin và tôi sẽ cập nhật càng sớm càng tốt.

Câu trả lời:


9

với PGBouncer, có lẽ bạn muốn gắn bó với NullPool. Trong trường hợp đó, bạn có thể chia sẻ một Động cơ duy nhất trên các quy trình con do không có kết nối ổ cắm nào được đưa qua ranh giới quy trình con. Nhưng bạn không thể chia sẻ bất cứ điều gì đề cập đến một đối tượng Kết nối, như Phiên với giao dịch đang hoạt động, qua ranh giới này. Bạn chắc chắn sẽ không muốn thực hiện "engine-per-request", Engine là một đối tượng đắt tiền tích lũy nhiều thông tin về một URL cơ sở dữ liệu cụ thể vào lần đầu tiên nhìn thấy nó.


4

Đặt tên ứng dụng

Nếu bạn muốn chạy nhiều tiến trình, bạn cần biết chúng đang kết nối từ đâu. PGBouncer sẽ làm cho điều này vô hình pg_stat_activity. Giải quyết vấn đề này bằng cách cẩn thận thiết lập application_namethông tin bạn cần:

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

Phiên thích

Sử dụng Phiên vì các yêu cầu từ một đối tượng Động cơ có thể sinh ra và giữ nhiều kết nối. Kết nối với Postgres không tốn kém lắm, với PGBouncer, nó thậm chí còn ít hơn thế. Tôi sẽ luôn luôn sử dụngNullPool để các kết nối duy nhất bạn sẽ thấy trong Postgres là các kết nối đang thực sự được sử dụng.

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

Loại bỏ các giao dịch nhàn rỗi

Nếu mục đích của bạn là sử dụng PGBouncer để mở rộng quy mô thì bắt buộc bạn phải tránh để các giao dịch bị kẹt mở. Để làm điều này bạn cần phải biếnautocommit về . Điều này không đơn giản với SQLAlchemy ... có ba nơi có thể đặt một cái gì đó gọi là "autocommit":

tự động psycopg2

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

Được coi là không an toàn không an toàn vì SQLAlchemy cần biết những gì đang xảy ra bên dưới.

Phiên tự động

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

Điều này đòi hỏi phải cẩn thận, bàn giao rõ ràng:

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

Chức năng gọi và xử lý ngoại lệ là cực kỳ khó khăn vì begin()commit()không thể lồng nhau:

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

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

Trong chế độ này, psycopg2 autocommitdường nhưFalse (mặc định)

Động cơ tự động

Đặt chế độ cách ly Động cơ thành "AUTOCOMMIT"khi tạo động cơ sẽ thiết lập hành vi mặc định mới có thể không yêu cầu thay đổi mã hiện có.

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

Trong chế độ này psycopg2 autocommitdường nhưTrue

Vấn đề chính ở đây là cách duy nhất để đảm bảo rằng một khối mã được gói trong một giao dịch là phát ra các câu lệnh theo cách thủ công:

session.execute("BEGIN")
#...
session.execute("COMMIT")
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.