如何最好地将 SQLAlchemy 中的连接池用于 PgBouncer 事务级池?

Jua*_*oto 18 postgresql python

使用 SQLAlchemy 查询 PgBouncer 后面的 PostgreSQL 数据库,使用事务级池。

用于这种设置的最佳模式是什么?我应该每个进程有一个引擎,使用ConnectionPool,还是应该NullPool为每个请求创建一个引擎,并为每个请求使用?我应该使用完全不同的模式吗?

非常感谢!如果需要更多信息,请告诉我,我会尽快更新。

小智 10

使用 PGBouncer,您可能只想坚持使用 NullPool。在这种情况下,您可能能够跨子进程共享单个引擎,因为没有套接字连接将通过子进程边界进行。但是您不能在此边界上共享任何引用 Connection 对象的内容,例如具有活动事务的 Session。但是,您绝对不想执行“每个请求的引擎”,引擎是一个昂贵的对象,它在第一次看到特定数据库 URL 时会积累大量有关特定数据库 URL 的信息。


era*_*man 10

设置应用程序名称

\n\n

如果您希望运行许多进程,您需要知道它们\n从哪里连接。PGBouncer 将使pg_stat_activity. application_name通过仔细设置您需要的信息来解决此问题:

\n\n
# Sets the application name for this connection in the form of\n#   application-name:user@host\nprog = os.path.basename(sys.argv[0]) or \'desjob\'\nusername = pwd.getpwuid (os.getuid ()).pw_name\nhostname = socket.gethostname().split(".")[0]\xc2\xb7\nargs.setdefault(\'connect_args\', {\'application_name\': "%s:%s@%s" %\n    (prog, username, hostname)})\nargs.setdefault(\'isolation_level\', "AUTOCOMMIT")\nengine = create_engine(url, **args)\n
Run Code Online (Sandbox Code Playgroud)\n\n

首选会话

\n\n

使用会话,因为来自引擎对象的请求可以产生并保持多个连接。连接到 Postgres 并不是很昂贵,使用 PGBouncer 甚至更便宜。我总是会NullPool这样使用,以便您在 Postgres 中看到的唯一连接是实际正在使用的连接。

\n\n
from sqlalchemy.pool import Pool, NullPool\nengine = create_engine(uri, poolclass=NullPool)\n
Run Code Online (Sandbox Code Playgroud)\n\n

消除闲置交易

\n\n

如果您的目的是使用 PGBouncer 进行扩展,那么您必须避免\n让事务保持开放状态。为此,您需要autocommit 打开. 这对于 SQLAlchemy 来说并不简单...可以在三个地方设置“自动提交”:

\n\n

psycopg2 自动提交

\n\n
conn = psycopg2.connect(uri)\nconn.autocommit = True\n
Run Code Online (Sandbox Code Playgroud)\n\n

假定不安全不安全,因为 SQLAlchemy 需要知道下面发生了什么。

\n\n

会话自动提交

\n\n
Session = sessionmaker(bind=engine, autocommit=True)\nsession = Session()\n
Run Code Online (Sandbox Code Playgroud)\n\n

这需要仔细、明确的处理:

\n\n
session.begin()\nsession.execute(...)\nsession.rollback()\n
Run Code Online (Sandbox Code Playgroud)\n\n

函数调用和异常处理非常困难,因为\nbegin()commit()不能嵌套:

\n\n
def A():\n  session.begin()\n  ...\n  session.rollback()\n\ndef B():\n  session.begin()\n  try:\n      A() # error, already open\n
Run Code Online (Sandbox Code Playgroud)\n\n

在这种模式下 psycopg2autocommit似乎是False(默认)

\n\n

引擎自动提交

\n\n

在创建引擎时将引擎隔离模式设置为"AUTOCOMMIT"\n会建立新的默认行为,\n可能不需要更改现有代码。

\n\n
engine = create_engine(uri, isolation_level="AUTOCOMMIT")\n
Run Code Online (Sandbox Code Playgroud)\n\n

在这种模式下 psycopg2autocommit似乎是True

\n\n

这里的主要问题是保证代码块包含在事务中的唯一方法是手动发出语句:

\n\n
session.execute("BEGIN")\n#...\nsession.execute("COMMIT")\n
Run Code Online (Sandbox Code Playgroud)\n