mongoose副本集事务实践
背景
最近因公司的CRM项目用的mongodb,浏览了所有旧代码,看到特别多多表原子操作的问题。借此机会就来看看mongodb4.0后出来的副本集事务的能力。
问题还原
多表操作场景
涉及异常回滚的原子性问题,
1 | // 创建流水号(流水号表自增) |
问题:当异常中断时候,实际流水号表已经成功自增1,但是创建订单失败。当下一次进行操作的时候,实际流水号缺失了1位的订单流水号。
这里其实还隐藏着一个问题,高并发未加锁,会导致流水号异常。
这就是事务的原子性,实际应该当异常中断,启动事务回滚,回滚流水号的自增创建。
问题还原2
redis版本异常
1 |
|
问题:当异常redis中断导致发送消息失败,应该启动事务回滚
正确操作:启动事务,进行异常回滚,如下
app/extend/context.js
1 | module.exports = { |
1 |
|
错误或不建议的操作:人工删除
1 | try { |
mongodb副本集环境搭建
bash 脚本
1 | #!/bin/bash |
出现如下错误:
1 | configsvr01 | {"t":{"$date":"2021-05-29T17:38:02.750+00:00"},"s":"I", "c":"ACCESS", "id":20254, "ctx":"main","msg":"Read security file failed","attr":{"error":{"code":30,"codeName":"InvalidPath","errmsg":"error opening file: /data/mongo.key: bad file"}}} |
解决办法: 变更mongoReplSet-keyfile 所属用户chown 999 mongoReplSet-keyfile
启动 Docker
docker-compose -f docker-compose.yml up -d
docker-compose
1 | version: '3.1' |
容器名 | ip | 备注 |
---|---|---|
mongo1 | 10.8.99.44:27011 | Primary(主, 读写) |
mongo2 | 10.8.99.44:27012 | Secondary1(从,读) |
mongo3 | 10.8.99.44:27013 | Secondary2(从, 读) |
配置副本集
1 | docker exec -it <container> mongo |
相关副本集命令
重置
1 | rs.reconfig( |
1 | rs.config() |
强制修改副本集host
1 | rs.reconfig( |
修改优先级
必须在primary节点上执行此操作,副本集中通过设置priority的值来决定优先权的大小。这个值的范围是0–100,值越大,优先权越高. 如果值是0,那么不能成为primay。适用于做冷备。
1 | PRIMARY> config=rs.conf() |
1 | 查看副本集状态 |
事务实践
如何通过mongoose连接副本集
1 | config.mongoose = { |
readPreference
默认情况下,读写都指定到副本集中的 Primary 节点。对于读多写少的情况我们可以使用读写分离来减轻 DB 的压力。MongoDB 驱动程序支持五种读取首选项(Read Preference) 模式。
Read Preference | 描述 |
---|---|
primary | 默认模式。 所有操作都从当前副本集 primary 读取。 |
primaryPreferred | 在大多数情况下,从 primary 读取,但如果不可用,则从 secondary 读取。 |
secondary | 所有操作都从 secondary 中读取。 |
secondaryPreferred | 在大多数情况下,从 secondary 读取,但如果没有 secondary 可用,则从 primary 读取。 |
nearest | 无论成员的类型如何,操作都从具有最小网络延迟的副本集成员读取 |
mongoose事务回滚
app/extend/context.js
1 | module.exports = { |
app/service/test.js
1 | async transaction() { |
可以看看res1 是不是回滚创建,在数据库中找不到了
相关链接
https://www.jianshu.com/p/8d7dea5c067b
https://www.zhangshengrong.com/p/Ap1ZeQ2PX0/