使用 Sequelize 的副本读取数据库的竞争条件
Race condition with replica read database with Sequelize
我们将 Sequelize 与具有读写数据库的 AWS Aurora Postgresql 数据库一起使用。 Sequelize 配置为使用读取副本和写入数据库。
我们有 users
table 和 follows
table。 User
对象类型具有子查询字段,例如用户的 followingCount 字段:
...
followingCount: {
type: new GraphQLNonNull(GraphQLInt),
resolve(user) {
return db.Follower.count({
where: { followerId: user.id, status: "Approved" }
});
}
},
当我们为某个用户向 follows
table 添加记录时,然后 return 该用户实例,followingCount
不会更新。我有 99% 的信心这是因为它是从没有数据的 replica/read 数据库中读取的。我已通过禁用副本并看到问题消失来验证了这一点。
我犹豫是否要向这些字段添加 useMaster
选项,因为它否定了我们的并发策略。
这是我调用的确切代码:
const followingUser = await db.User.findOne({
where: {
id
}
});
await db.Follower.create({
followerId: getCurrentUserId(context),
followingId: id,
status: followingUser.privateProfile ? "Pending" : "Approved"
});
return followingUser.reload();
用户实例 (followingUser
) 上的 followingCount
字段不是 return 最新计数,即使它存在于 master/write 数据库中。
有哪些选择?有什么办法可以将我的突变包装在一个块中,以便在其中执行的任何操作都使用 Master/Write 数据库?将其包装在交易帮助中,如果是这样,我如何将交易传递给我的
感谢任何帮助
psql 9.6.8
sequelize 4.38.0
在 PostgreSQL 中可以通过多种方式进行复制:
- 同步
- 异步
如果您是运行 异步复制,数据可能会在主服务器(主服务器)上提交事务后到达从服务器。通常会有一个小的复制延迟。
您可以将同步复制到任意数量的从站,以确保提交仅在所需数量的 PostgreSQL 服务器确认后才有效。
同步事务可以return 只有当足够数量的从属确认了写入。
所以我认为您正在使用异步复制,您需要转向同步复制。
为了设置同步复制,您需要在postgresql.conf文件中配置synchronous_standby_name和synchronous_commit参数。 synchronous_commit 参数可以有以下值:off、on、remote_write、remote_apply(Postgres 9.6 的一个特性)和 local.
我能够通过在返回的数据库对象上调用 reload()
并传递它来解决这个问题 useMaster: true
followingUser.reload({ useMaster: true });
我用 sequelize 创建了一张票据,如果它对任何人有帮助的话,它有更多的上下文:https://github.com/sequelize/sequelize/issues/9971
我们将 Sequelize 与具有读写数据库的 AWS Aurora Postgresql 数据库一起使用。 Sequelize 配置为使用读取副本和写入数据库。
我们有 users
table 和 follows
table。 User
对象类型具有子查询字段,例如用户的 followingCount 字段:
...
followingCount: {
type: new GraphQLNonNull(GraphQLInt),
resolve(user) {
return db.Follower.count({
where: { followerId: user.id, status: "Approved" }
});
}
},
当我们为某个用户向 follows
table 添加记录时,然后 return 该用户实例,followingCount
不会更新。我有 99% 的信心这是因为它是从没有数据的 replica/read 数据库中读取的。我已通过禁用副本并看到问题消失来验证了这一点。
我犹豫是否要向这些字段添加 useMaster
选项,因为它否定了我们的并发策略。
这是我调用的确切代码:
const followingUser = await db.User.findOne({
where: {
id
}
});
await db.Follower.create({
followerId: getCurrentUserId(context),
followingId: id,
status: followingUser.privateProfile ? "Pending" : "Approved"
});
return followingUser.reload();
用户实例 (followingUser
) 上的 followingCount
字段不是 return 最新计数,即使它存在于 master/write 数据库中。
有哪些选择?有什么办法可以将我的突变包装在一个块中,以便在其中执行的任何操作都使用 Master/Write 数据库?将其包装在交易帮助中,如果是这样,我如何将交易传递给我的
感谢任何帮助
psql 9.6.8
sequelize 4.38.0
在 PostgreSQL 中可以通过多种方式进行复制:
- 同步
- 异步
如果您是运行 异步复制,数据可能会在主服务器(主服务器)上提交事务后到达从服务器。通常会有一个小的复制延迟。
您可以将同步复制到任意数量的从站,以确保提交仅在所需数量的 PostgreSQL 服务器确认后才有效。
同步事务可以return 只有当足够数量的从属确认了写入。
所以我认为您正在使用异步复制,您需要转向同步复制。
为了设置同步复制,您需要在postgresql.conf文件中配置synchronous_standby_name和synchronous_commit参数。 synchronous_commit 参数可以有以下值:off、on、remote_write、remote_apply(Postgres 9.6 的一个特性)和 local.
我能够通过在返回的数据库对象上调用 reload()
并传递它来解决这个问题 useMaster: true
followingUser.reload({ useMaster: true });
我用 sequelize 创建了一张票据,如果它对任何人有帮助的话,它有更多的上下文:https://github.com/sequelize/sequelize/issues/9971