You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flask应用HAProxy负载AWS RDS MySQL时写API报错,需分读写URI

嘿,我来帮你搞定这个问题!你遇到的写入API频繁报错,核心原因肯定是HAProxy把写请求分发到AWS RDS的只读副本上了——毕竟RDS只读实例是拒绝写操作的。你想分读写两个URL的思路完全正确,下面给你一步步拆解实现方案:

一、先搞定HAProxy的读写分流配置

首先得确保HAProxy能把读写请求分别路由到RDS主实例(写)和只读副本池(读),修改你的HAProxy.cfg:

# 写请求专属前端(绑定3307端口)
frontend mysql-write
    bind *:3307
    default_backend mysql-write-backend

# 读请求专属前端(绑定3308端口)
frontend mysql-read
    bind *:3308
    default_backend mysql-read-backend

# 写后端:只关联RDS主实例
backend mysql-write-backend
    mode tcp
    balance roundrobin
    server rds-main 你的主RDS端点:3306 check

# 读后端:关联所有只读副本
backend mysql-read-backend
    mode tcp
    balance roundrobin
    server rds-replica1 你的只读副本1端点:3306 check
    server rds-replica2 你的只读副本2端点:3306 check

这样写请求走3307端口只会到主实例,读请求走3308会被均衡到副本上,从根源避免写请求落到只读实例。

二、在Flask+SQLAlchemy中配置双连接

接下来在你的Flask应用里配置两个数据库连接URI,分别对应读写:

# 配置类
class Config:
    # 写连接:指向HAProxy的写端口
    SQLALCHEMY_DATABASE_URI_WRITE = "mysql+pymysql://用户名:密码@HAProxy地址:3307/数据库名"
    # 读连接:指向HAProxy的读端口
    SQLALCHEMY_DATABASE_URI_READ = "mysql+pymysql://用户名:密码@HAProxy地址:3308/数据库名"
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    # 可选:配置连接池参数,优化并发
    SQLALCHEMY_POOL_SIZE = 10
    SQLALCHEMY_MAX_OVERFLOW = 20

然后初始化两个SQLAlchemy实例(或者用绑定功能,看你习惯):

方式1:双实例方案(简单直观)

from flask import Flask, jsonify, request
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config.from_object(Config)

# 初始化写数据库实例
db_write = SQLAlchemy(app)
# 切换配置为读URI,初始化读数据库实例
app.config['SQLALCHEMY_DATABASE_URI'] = app.config['SQLALCHEMY_DATABASE_URI_READ']
db_read = SQLAlchemy(app)

# 你的模型类(用哪个实例定义都可以,因为结构一致)
class YourModel(db_write.Model):
    id = db_write.Column(db_write.Integer, primary_key=True)
    content = db_write.Column(db_write.String(255))

    def to_dict(self):
        return {"id": self.id, "content": self.content}

方式2:SQLAlchemy绑定方案(更优雅)

如果不想维护两个实例,用SQLAlchemy的多绑定功能:

app.config['SQLALCHEMY_BINDS'] = {
    'write': Config.SQLALCHEMY_DATABASE_URI_WRITE,
    'read': Config.SQLALCHEMY_DATABASE_URI_READ
}
db = SQLAlchemy(app)

# 模型类可以指定默认绑定,或者操作时指定
class YourModel(db.Model):
    __bind_key__ = 'write'  # 默认用写绑定,写操作不用额外指定
    id = db.Column(db.Integer, primary_key=True)
    content = db.Column(db.String(255))

    def to_dict(self):
        return {"id": self.id, "content": self.content}
三、在API路由中区分读写操作

现在就可以在不同API里用对应的连接了:

只读API(用读连接)

@app.route('/api/data', methods=['GET'])
def get_data():
    # 双实例方案:用db_read的会话
    data = db_read.session.query(YourModel).all()
    # 绑定方案:指定用read绑定
    # data = db.session.query(YourModel).bind('read').all()
    return jsonify([item.to_dict() for item in data])

写入API(用写连接)

@app.route('/api/data', methods=['POST'])
def add_data():
    new_item = YourModel(content=request.json.get('content'))
    # 双实例方案:用db_write的会话
    db_write.session.add(new_item)
    db_write.session.commit()
    # 绑定方案:默认用write绑定,直接操作即可
    # db.session.add(new_item)
    # db.session.commit()
    return jsonify(new_item.to_dict()), 201
四、额外优化小技巧
  • 可以封装一个装饰器,自动给路由分配读写会话,减少重复代码
  • 给写操作加上错误捕获,如果遇到只读实例的报错,可以自动重试到写端点
  • 定期检查HAProxy的后端状态,确保主实例和副本都正常在线

内容的提问来源于stack exchange,提问作者Stew

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 10:10:56