如何实现Postgres RDS实例的查询路由?求推荐数据库代理
Postgres RDS 多实例Schema路由实现方案
推荐工具
pgpool-II
- 原生适配PostgreSQL,内置连接池、路由与负载均衡能力,无需额外依赖
- 支持基于SQL中的
SCHEMA关键字、连接search_path参数或自定义规则路由 - 可通过配置或自定义函数结合rds_master的映射表实现动态路由
ProxySQL
- 跨数据库协议支持,Lua脚本扩展能力极强,适合复杂路由逻辑
- 能在Lua脚本中完成:子域名解析→rds_master查询schema→RDS实例匹配→请求转发的全流程
- 自带连接池与结果缓存,有效降低RDS连接压力
pgbouncer(轻量静态路由)
- 轻量级连接池工具,适合规则固定的场景(如1-10→rds1)
- 通过配置文件
route_list预定义schema与RDS的映射关系,配置简单
路由核心逻辑
无论使用哪种工具,核心流程一致:
- 提取子域名:从请求元数据(如Postgres连接
application_name、代理层获取的主机头)中提取子域名(例:10.abc.com中的10) - 查询Schema映射:连接rds_master执行查询,获取子域名对应的schema(SQL示例:
SELECT schema_name FROM domain_schema_map WHERE sub_domain = '10') - 匹配目标RDS:根据预设规则跳转:
- Schema 1-10 →
rds1.abc.com - Schema 11-20 →
rds2.abc.com - Schema 21-30 →
rds3.abc.com
- Schema 1-10 →
- 转发并保持会话一致性:将请求转发至目标实例,确保同一会话的多请求路由至同一实例(避免事务异常)
实战示例(ProxySQL + Lua)
在ProxySQL中编写Lua路由脚本:
function route_query(username, password, hostname, port, dbname, query) -- 提取子域名 local sub_domain = string.match(hostname, "^([^.]+)%.abc%.com$") if not sub_domain then return proxy.MYSQL_PROXY_SEND_QUERY end -- 查询rds_master获取对应schema local map_query = string.format("SELECT schema_name FROM domain_schema_map WHERE sub_domain = '%s'", sub_domain) local res = proxy.connection:query(map_query) if not res.resultset or #res.resultset == 0 then return proxy.MYSQL_PROXY_SEND_QUERY end local schema = res.resultset[1][1] local schema_num = tonumber(schema) -- 匹配目标RDS local target_host if schema_num >=1 and schema_num <=10 then target_host = "rds1.abc.com" elseif schema_num >=11 and schema_num <=20 then target_host = "rds2.abc.com" elseif schema_num >=21 and schema_num <=30 then target_host = "rds3.abc.com" else return proxy.MYSQL_PROXY_SEND_QUERY end -- 路由到目标后端 proxy.connection.backend_ndx = proxy.backend_ndx_by_hostname(target_host) return proxy.MYSQL_PROXY_SEND_QUERY end
关键注意事项
- 给代理工具配置rds_master的只读权限,防止映射表被误操作
- 在代理层缓存子域名-schema映射,减少对rds_master的查询频次
- 测试会话一致性,确保事务请求全程路由至同一实例
内容的提问来源于stack exchange,提问作者Kabilan Ravi
相关产品推荐
相关产品推荐

