文章目录
Mongodb写入安全
- 客户端保存数据到MongoDB,对于数据写入安全有不同的级别,比如Mongodb集群要全部收到,或者只有部分节点收到之类的,这个和Kafka类似,其他的分布式组件估计也会有类似的配置。
一、分类
1.1 Unacknowledged
- 非确认式写入。客户端发出请求丢到socket的时候就收到响应,客户端不需等待服务器的应答,不能收到服务端的异常响应 。
1.2 Acknowledged
- 确认式写入。客户端会等待服务器给的确认,这种方式一定能确保服务器收到了客户端的请求,并且服务器异常时能够响应客户端。
1.3 Journaled
- 日志写入。Journaled方式相比Acknowledged的方式是要保证服务器端已经写入Journaled文件了。Acknowledged方式有可能收到请求后的一瞬间宕机导致数据丢失,但Journaled方式服务器保证写入到磁盘后再响应客户端,即使宕机了也不会数据丢失。
1.4 Replica Acknowledged
-
副本集确认式写入。适用于Replicasets模式,可以要求有多台机器收到写入请求后再响应客户端,或者直接指定大多数收到后再响应。更安全但是导致了客户端耗时增加,所以要结合自己的场景设置合适的策略。
-
按照参考文章[2],我们知道journal日志保存到磁盘默认的频率是100ms一次,在没有开启journal的情况下,MongoDB落盘频率是1min每次。
二、设置方式
2.1 服务端
- 查看MongoDB服务端设置默认的策略。
//副本集
//获取,再设置,再读取
cfg = rs.conf()
rs_shard_server1:PRIMARY> cfg.settings.getLastErrorDefaults
{ "w" : 1, "wtimeout" : 0 }
rs_shard_server1:PRIMARY>
rs_shard_server1:PRIMARY> cfg.settings.getLastErrorDefaults={ w: "majority",j:true, wtimeout: 5000 }
{ "w" : "majority", "j" : true, "wtimeout" : 5000 }
rs_shard_server1:PRIMARY> cfg.settings.getLastErrorDefaults
{ "w" : "majority", "j" : true, "wtimeout" : 5000 }
rs_shard_server1:PRIMARY>
//单机
//获取,再设置,再读取
> db.getWriteConcern()
> db.setWriteConcern({w:1,j:true,wtimeout:3000})
> db.getWriteConcern()
WriteConcern({ "w" : 1, "j" : true, "wtimeout" : 3000 })
- writeConcern函数参数。writeConcern有三个配置,下面给出解析。
参数 | 类型 | 取值范围 | 含义 |
---|---|---|---|
w | 整数 | 0/1/大于等于2/majority | 0表示非确认写入,1表示确认写入,大于等于2表示2个(或者更多)节点写入,majority表示大多数(副本集模式) |
j | 布尔 | true/false | 是否写入journal日志 |
wtimeout | 整型 | 整数 | 超时时间 |
W选项:
0:非确认式写入 {writeConcern:{w:0 } }
1:确认式写入;{writeConcern:{w:1 } }说明:这个级别下,对副本集只对主库做确认写入
2:副本级确认式写入;{writeConcern:{w:2 } }说明:这个级别下,副本级第一个slave写入成功后就响应给client
majority:复制级多数节点写入成功后,再响应给client {writeConcern:{w:majority} }
j选项
true/false:表示是否使用Journaled日志写入
{writeConcern:{w:1,j:true,wtimeout:5}}
wtimeout选项
超时设置,超时时间内未响应则返回错误
2.2 客户端
- MongoDB客户端
db.wirte_concern.insert(doc1,{writeConcern:{w:1,j:true,wtimeout:5}})
2.3 Java客户端
- Java客户端在初始化MongodbClient的时候通过参数传入,如下:
MongoClientOptions options = MongoClientOptions.builder()
.writeConcern(WriteConcern.UNACKNOWLEDGED)
.build();
MongoClient client = new MongoClient(serverAddresses, Collections.singletonList(createCredential), options);
public static final WriteConcern UNACKNOWLEDGED = new WriteConcern(0); //Unacknowledged
public static final WriteConcern ACKNOWLEDGED = new WriteConcern((Object) null, null, null, null);//Acknowledged
public static final WriteConcern JOURNALED = ACKNOWLEDGED.withJournal(true); //Journaled
public static final WriteConcern REPLICA_ACKNOWLEDGED = new WriteConcern(2); //副本级确认式写入
public static final WriteConcern MAJORITY = new WriteConcern("majority"); //大多数确认
模式 | Java客户端 | MongoDB客户端 |
---|---|---|
非确认式写入(Unacknowledged) | UNACKNOWLEDGED = new WriteConcern(0) | {writeConcern:{w:0 } } |
确认式写入(Acknowledged) | ACKNOWLEDGED = new WriteConcern((Object) null, null, null, null) | {writeConcern:{w:1 } } |
日志写入(Journaled) | JOURNALED = ACKNOWLEDGED.withJournal(true) | {writeConcern:{w:1,j:true,wtimeout:5}} |
Replica Acknowledged(指定节点) | REPLICA_ACKNOWLEDGED = new WriteConcern(2) | {writeConcern:{w:2 }} |
Replica Acknowledged(多数节点) | MAJORITY = new WriteConcern(“majority”) | {writeConcern:{w:majority }} |
Replica Acknowledged多数节且日志写入 | WriteConcern.MAJORITY.withJournal(true) | {writeConcern:{w:majority,j:true,wtimeout:5}} |
- 在Replica Acknowledged模式下,可同时指定确认的节点数量和日志写入,比如{writeConcern:{w:3,j:true,wtimeout:5}就表示需要3个节点确认且需要写入Journale日志。Java中表示如下(fsync表示暴力将数据刷到磁盘):
WriteConcern writeConcern = new WriteConcern(3);
System.out.println(writeConcern.toString());
WriteConcern writeConcern1 = writeConcern.withJournal(true);
System.out.println(writeConcern1.toString());
//打印
WriteConcern{w=3, wTimeout=null ms, fsync=null, journal=null
WriteConcern{w=3, wTimeout=null ms, fsync=null, journal=true
//多数节点,并且开启Journal
WriteConcern.MAJORITY.withJournal(true)
三、小结
- WriteConcern用于控制写入安全的级别,可以分为应答式写入以及非应答式写入,它是一个性能和数据强一致性的权衡,应根据业务场景进行设定,对于强一致性场景,建议w>1或者等于majority以及journal为true,否则w=0
- 在副本集的情形下,建议通过配置文件来修改w以及设置wtimeout,以避免由于某个节点挂起导致无法应答
四、参考
- [1] 写入策略(WriteConcern)
- [2] 12-Mongodb日志
- [3] MongoDB写入安全级别