MySQL Aurora写入后主节点立即读取数据不一致问题排查
我有一个包含1个主实例(writer)和1个只读实例(reader)的Aurora MySQL集群。使用NodeJS的mysql2包操作数据库时,执行写入查询(如INSERT/UPDATE)并收到响应后,立即在主实例上执行SELECT查询,却读取到旧数据;但在写入与读取之间添加约1秒延迟就能正常获取新数据。示例代码如下:
await db.execute("UPDATE mytable SET emotion = 'frustrated' WHERE user = 'me'") const result = await db.execute("SELECT emotion FROM mytable WHERE user = 'me'") // result返回更新前的值,而非'frustrated'
可能的原因
1. 连接池路由错误,SELECT被转发到只读实例
你以为SELECT是在主实例执行,但mysql2连接池可能被配置了读写分离路由——写入请求走主实例,后续SELECT被自动路由到只读实例。Aurora只读实例同步主数据存在延迟(通常毫秒级,高负载下可能到1秒),因此会读到旧数据。
检查连接池配置,是否用了读写分离中间件、AWS RDS数据客户端,或者手动设置了路由规则,导致SELECT请求没绑定到主实例连接。
2. 事务隔离级别与自动提交配置问题
如果mysql2连接关闭了自动提交(autocommit),UPDATE执行后事务未立即提交:
- 若SELECT用了当前连接,能看到未提交的修改;但如果SELECT用了连接池里的其他连接(未参与当前事务),就会读到旧数据。
- 加上MySQL默认隔离级别是
REPEATABLE READ,如果SELECT在新事务中执行,且事务快照是UPDATE提交前生成的,也会读到旧数据。
可以执行以下语句检查当前连接的autocommit状态:
const [rows] = await db.execute("SELECT @@autocommit"); console.log(rows);
3. Aurora主实例的一致性配置问题
Aurora MySQL默认提供会话级写后读一致性——同一会话中写入后立即读能看到最新数据,但如果写入和读取用了不同会话(连接池的不同连接),可能触发全局一致性延迟。
可以尝试在SELECT前加SQL提示强制读已提交隔离级别,或者在连接初始化时设置会话隔离级别:
/*+ READ_COMMITTED */ SELECT emotion FROM mytable WHERE user = 'me' -- 或者连接初始化时执行 SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED
4. mysql2的execute方法与连接复用问题
mysql2的execute方法会预编译SQL,连接池可能复用了状态未刷新的连接;如果连接存在未提交事务或会话状态不一致,也会导致读旧数据。
可以尝试用query方法替代execute测试,或者在UPDATE后显式提交事务(若autocommit关闭):
await db.query("UPDATE mytable SET emotion = 'frustrated' WHERE user = 'me'") const result = await db.query("SELECT emotion FROM mytable WHERE user = 'me'")
5. Aurora存储层同步延迟(罕见)
Aurora的存储层是共享的,但主实例写入后,存储日志同步到查询层可能存在极短暂延迟(高负载下可能出现)。这种情况可以用FLUSH TABLES mytable;测试,但不建议生产环境使用,会影响性能。
内容的提问来源于stack exchange,提问作者leed

