我有一个使用 Pyramid/SQLAlchemy/Postgresql 构建的 Web 应用程序,允许用户管理一些数据,并且这些数据对于不同的用户几乎是完全独立的。比如说,Alice 访问alice.domain.com
并能够上传图片和文档,Bob 访问bob.domain.com
并且也能够上传图片和文档。Alice 永远不会看到 Bob 创建的任何东西,反之亦然(这是一个简化的示例,多个表中可能确实有很多数据,但想法是一样的)。
现在,在 DB 后端组织数据最直接的选择是使用单个数据库,其中每个表 (pictures
和documents
) 都有user_id
字段,因此,基本上,要获取 Alice 的所有图片,我可以执行类似的操作
user_id = _figure_out_user_id_from_domain_name(request)
pictures = session.query(Picture).filter(Picture.user_id==user_id).all()
这一切都很容易和简单,但是有一些缺点
- 我需要记住在进行查询时始终使用附加过滤条件,否则 Alice 可能会看到 Bob 的图片;
- 如果有很多用户,表格可能会变得很大
- 在多台机器之间拆分 Web 应用程序可能会很棘手
所以我认为以某种方式拆分每个用户的数据会非常好。我可以想到两种方法:
在同一个数据库中为 Alice 和 Bob 的图片和文档设置单独的表(在这种情况下,Postgres 的模式似乎是一种正确的方法):
documents_alice documents_bob pictures_alice pictures_bob
然后,使用一些黑魔法,根据当前请求的域将所有查询“路由”到一个或另一个表:
_use_dark_magic_to_configure_sqlalchemy('alice.domain.com') pictures = session.query(Picture).all() # selects all Alice's pictures from "pictures_alice" table ... _use_dark_magic_to_configure_sqlalchemy('bob.domain.com') pictures = session.query(Picture).all() # selects all Bob's pictures from "pictures_bob" table
为每个用户使用单独的数据库:
- database_alice - pictures - documents - database_bob - pictures - documents
这似乎是最干净的解决方案,但我不确定多个数据库连接是否需要更多的 RAM 和其他资源,从而限制可能的“租户”数量。
所以,问题是,这一切都有意义吗?如果是,如何配置 SQLAlchemy 以在每个 HTTP 请求上动态修改表名(对于选项 1)或维护到不同数据库的连接池并为每个请求使用正确的连接(对于选项 2)?