前文我们聊到了mongodb的索引的相关作用和介绍以及索引的管理,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/13950287.html;今天我们来聊下mongodb的副本集;
1、什么是副本集?主要作用是什么?它是怎么工作的呢?
所谓副本集是指服务于同一数据集的多个mongodb实例;这意味着在mongodb中数据集副本的数量可以是多个,每个副本的数据都是一样的;副本的存在主要作用是对mongodb数据库中的数据做冗余备份和提高数据服务的可用性;在mongodb中对数据做冗余的方式有两种,一种是主从架构(master/slave),这种架构和mysql中的主从架构没有什么不同,但是在mongodb中,主从架构的方式几乎没有人用,处于废弃的状态。。另外一种是副本集(replica set),副本集本质上也是主从架构的一种,它和我们刚才说的主从架构,有一个显著的区别,副本集支持故障自动转移,不需要人工手动干预;所谓的故障自动转移是指当一个副本集中主节点因各种原因宕机或者从节点在一定时间内没有收到主节点发送到心跳信息,此时就会触发从节点重新选举主节点的操作;在多个从节点中选举出来一个主节点以后,其他从节点能够自动指向新选举的主节点同步数据,从而完成这次故障转移;
2、mongodb副本集架构
提示:对于mongodb中的副本集来说,为了保证数据的一致性,一个副本集中只能有一个主节点,并且只有主节点才拥有读写权限,其他从节点都只有读权限;在mongodb的副本集中,主节点我们叫做primary,从节点叫做secondary;
3、副本集是通过什么来复制数据的呢?
我知道mysql的主从复制是通过主节点记录写操作到binlog中,从节点通过同步主节点的binlog,然后把同步的binlog在本地进行重放,从而实现数据同步;在mongodb中也是类似的操作,不同的是在mongodb中主节点将写操作记录到oplog(操作日志),各从节点通过复制主节点的oplog,在本地重放实现数据同步;oplog的作用和mysql中的binlog的作用很类似,都是用来记录写操作事件,都是用来同步数据;mongodb中的oplog是一个定容集合,所谓定容是指它的大小是固定的,它不会像binlog随日志的增多而逐渐变大;通常oplog我们不人为指定其大小,默认就是占用所在文件系统空闲磁盘的5%;除了大小是不变的,它还有一个幂等的特点;所谓幂等就是不管在monogdb中执行多少次oplog中的操作,其最终的结果都是一样的;如果写操作日志把oplog写满了,它会从头覆盖之前的oplog,依次循环写oplog;
4、副本集是怎么完成故障转移的?
在前边我们聊zookeeper时,聊到过分布式场景中的选举过程;mongodb的主节点故障以后,也是通过这种机制来完成选举;在mongodb的副本集中,主节点每隔两秒向各从节点发送心跳信息,各从节点通过检测主节点的心跳信息来判定主节点是否存活;如果在一定的时间范围内,从节点没有收到主节点发送到心跳信息,此时从节点会认为主节点挂了,从而触发主节点选举的操作;这个选举和zookeeper里的选举很类似,通常情况都是大于集群总票的一半一方可以代表集群正常工作;所以通常情况mongodb副本集都是基数个节点组成;当然mongodb中也可以是偶数节点(正常提供服务的节点),如果是偶数节点,通常会借助一个仲裁节点来完成选举;仲裁节点拥有选票,但不被选举成为主节点,也不拥有副本数据,同时它必须要能够检测主节点心跳;简单总结就是mongodb副本集是通过从节点检测主节点心跳来判断主节点是否存活,如果在一定时间范围内,没有检测到主节点的心跳信息,此时就会触发主节点选举操作,如果集群节点数量为偶数个,通常会借助仲裁节点来完成选举;从而实现完成故障自动转移;
5、mongodb副本集中特殊类型节点分类
0优先级节点:这种节点的特点是优先级为0,可参与选举,拥有副本数据,但不被选举成为主节点,可读不可写;这种节点我们也叫冷备节点;通常用于异地容灾使用;
被隐藏的从节点:这种节点的特点是,可参与选举,拥有副本数据,但不被选举成为主节点,对客户端不可读写也不可见;通常用于同步同一副本集中的其他节点的不同工作流的场景中;
延迟复制的从节点:这种节点的特点是,副本数据落后主节点一个时间窗口,也就说这种节点上的副本数据总是过期的;除此它可参与选举,不可被选举为主节点;主要用于特殊功用;比如在主节点上执行了一个删除操作,我们可以在延迟复制的从节点上把数据找回;
arbiter节点:这种就是我们说的仲裁节点,它可参与选举,不拥有副本数据,不被选举成为主节点,不可读写;主要作用是辅助判定主节点是否存活,辅助从节点完成选举,实现故障转移;
6、创建mongodb的副本集合
环境准备
主机名 | ip地址 |
node01 | 192.168.0.41 |
node02 | 192.168.0.42 |
node03 | 192.168.0.43 |
在三个节点上分别做好时间同步,关闭selinux,关闭防火墙,主机名解析,有必要还可以做ssh互信。准备好基础环境以后,在三台server上配置mongodb的yum源
[root@node01 ~]# cat /etc/yum.repos.d/mongodb.repo
[mongodb-org]
name = MongoDB Repository
baseurl = https://mirrors.aliyun.com/mongodb/yum/redhat/7/mongodb-org/4.4/x86_64/
gpgcheck = 1
enabled = 1
gpgkey = https://www.mongodb.org/static/pgp/server-4.4.asc
[root@node01 ~]# scp /etc/yum.repos.d/mongodb.repo node02:/etc/yum.repos.d/
mongodb.repo 100% 206 80.4KB/s 00:00
[root@node01 ~]# scp /etc/yum.repos.d/mongodb.repo node03:/etc/yum.repos.d/
mongodb.repo 100% 206 88.9KB/s 00:00
[root@node01 ~]#
安装mongodb-org
yum install -y mongodb-org
准备数据目录和存放日志的目录,并将其属主和属组更改为mongod用户
[root@node01 ~]# mkdir -pv /mongodb/{data,log}
mkdir: created directory ‘/mongodb’
mkdir: created directory ‘/mongodb/data’
mkdir: created directory ‘/mongodb/log’
[root@node01 ~]# chown -R mongod.mongod /mongodb/
[root@node01 ~]# ll -d /mongodb/
drwxr-xr-x 4 mongod mongod 29 Nov 10 19:36 /mongodb/
[root@node01 ~]#
提示:以上需在三个节点都要做一遍;
配置mongodb
提示:主要配置replication,其中oplogSizeMB用来指定oplog的大小,默认不指定,其大小就是所在文件系统空闲磁盘的%5;replSetName用来指定副本集的名称,这个名称非常重要,主要用来标识不同副本集;enableMajorityReadConcern用来指定是否开启mongodb周期性的做快照,并记录oplog的时间戳;
完整配置
[root@node01 ~]# cat /etc/mongod.conf
systemLog:
destination: file
logAppend: true
path: /mongodb/log/mongod.log storage:
dbPath: /mongodb/data/
journal:
enabled: true processManagement:
fork: true
pidFilePath: /var/run/mongodb/mongod.pid
timeZoneInfo: /usr/share/zoneinfo net:
port: 27017
bindIp: 0.0.0.0 replication:
oplogSizeMB: 2048
replSetName: test_replset
enableMajorityReadConcern: false #security: #operationProfiling: #sharding: ## Enterprise-Only Options #auditLog: #snmp:
[root@node01 ~]#
复制配置文件到node02,node03
[root@node01 ~]# scp /etc/mongod.conf node02:/etc/
mongod.conf 100% 494 315.1KB/s 00:00
[root@node01 ~]# scp /etc/mongod.conf node03:/etc/
mongod.conf 100% 494 351.6KB/s 00:00
[root@node01 ~]#
启动服务
提示:请确保对应节点上的mongodb所监听的端口正常即可;
连接三个节点任意一个节点查看副本集状态
> rs.help()
rs.status() { replSetGetStatus : 1 } checks repl set status
rs.initiate() { replSetInitiate : null } initiates set with default settings
rs.initiate(cfg) { replSetInitiate : cfg } initiates set with configuration cfg
rs.conf() get the current configuration object from local.system.replset
rs.reconfig(cfg) updates the configuration of a running replica set with cfg (disconnects)
rs.add(hostportstr) add a new member to the set with default attributes (disconnects)
rs.add(membercfgobj) add a new member to the set with extra attributes (disconnects)
rs.addArb(hostportstr) add a new member which is arbiterOnly:true (disconnects)
rs.stepDown([stepdownSecs, catchUpSecs]) step down as primary (disconnects)
rs.syncFrom(hostportstr) make a secondary sync from the given member
rs.freeze(secs) make a node ineligible to become primary for the time specified
rs.remove(hostportstr) remove a host from the replica set (disconnects)
rs.secondaryOk() allow queries on secondary nodes rs.printReplicationInfo() check oplog size and time range
rs.printSecondaryReplicationInfo() check replica set members and replication lag
db.isMaster() check who is primary reconfiguration helpers disconnect from the database so the shell will display
an error, even if the command succeeds.
> rs.status()
{
"operationTime" : Timestamp(0, 0),
"ok" : 0,
"errmsg" : "no replset config has been received",
"code" : 94,
"codeName" : "NotYetInitialized",
"$clusterTime" : {
"clusterTime" : Timestamp(0, 0),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
>
提示:所有关于副本集的操作命令都可以使用rs.help()方法去查看帮助;其中rs.status()是用来查看副本集状态;这里显示没有副本集配置,其原因是没有初始化副本集;
初始化副本集
> rs.initiate()
{
"info2" : "no configuration specified. Using a default configuration for the set",
"me" : "node01.test.org:27017",
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1605010821, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
},
"operationTime" : Timestamp(1605010821, 1)
}
test_replset:SECONDARY> rs.status()
{
"set" : "test_replset",
"date" : ISODate("2020-11-10T12:20:32.079Z"),
"myState" : 1,
"term" : NumberLong(1),
"syncSourceHost" : "",
"syncSourceId" : -1,
"heartbeatIntervalMillis" : NumberLong(2000),
"majorityVoteCount" : 1,
"writeMajorityCount" : 1,
"votingMembersCount" : 1,
"writableVotingMembersCount" : 1,
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(1605010821, 8),
"t" : NumberLong(1)
},
"lastCommittedWallTime" : ISODate("2020-11-10T12:20:21.720Z"),
"readConcernMajorityOpTime" : {
"ts" : Timestamp(1605010821, 8),
"t" : NumberLong(1)
},
"readConcernMajorityWallTime" : ISODate("2020-11-10T12:20:21.720Z"),
"appliedOpTime" : {
"ts" : Timestamp(1605010821, 8),
"t" : NumberLong(1)
},
"durableOpTime" : {
"ts" : Timestamp(1605010821, 8),
"t" : NumberLong(1)
},
"lastAppliedWallTime" : ISODate("2020-11-10T12:20:21.720Z"),
"lastDurableWallTime" : ISODate("2020-11-10T12:20:21.720Z")
},
"electionCandidateMetrics" : {
"lastElectionReason" : "electionTimeout",
"lastElectionDate" : ISODate("2020-11-10T12:20:21.632Z"),
"electionTerm" : NumberLong(1),
"lastCommittedOpTimeAtElection" : {
"ts" : Timestamp(0, 0),
"t" : NumberLong(-1)
},
"lastSeenOpTimeAtElection" : {
"ts" : Timestamp(1605010821, 1),
"t" : NumberLong(-1)
},
"numVotesNeeded" : 1,
"priorityAtElection" : 1,
"electionTimeoutMillis" : NumberLong(10000),
"newTermStartDate" : ISODate("2020-11-10T12:20:21.694Z"),
"wMajorityWriteAvailabilityDate" : ISODate("2020-11-10T12:20:21.719Z")
},
"members" : [
{
"_id" : 0,
"name" : "node01.test.org:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 674,
"optime" : {
"ts" : Timestamp(1605010821, 8),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2020-11-10T12:20:21Z"),
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "Could not find member to sync from",
"electionTime" : Timestamp(1605010821, 2),
"electionDate" : ISODate("2020-11-10T12:20:21Z"),
"configVersion" : 1,
"configTerm" : 1,
"self" : true,
"lastHeartbeatMessage" : ""
}
],
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1605010821, 8),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
},
"operationTime" : Timestamp(1605010821, 8)
}
test_replset:PRIMARY>
提示:初始化副本集以后,再次查看副本集状态,它告诉我们有一个成员,其主机名为node01.test.org:27017,其health状态为1,stateStr为PRIMARY等等一堆信息;
查看副本集配置
test_replset:PRIMARY> rs.conf()
{
"_id" : "test_replset",
"version" : 1,
"term" : 1,
"protocolVersion" : NumberLong(1),
"writeConcernMajorityJournalDefault" : true,
"members" : [
{
"_id" : 0,
"host" : "node01.test.org:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : { },
"slaveDelay" : NumberLong(0),
"votes" : 1
}
],
"settings" : {
"chainingAllowed" : true,
"heartbeatIntervalMillis" : 2000,
"heartbeatTimeoutSecs" : 10,
"electionTimeoutMillis" : 10000,
"catchUpTimeoutMillis" : -1,
"catchUpTakeoverDelayMillis" : 30000,
"getLastErrorModes" : { },
"getLastErrorDefaults" : {
"w" : 1,
"wtimeout" : 0
},
"replicaSetId" : ObjectId("5faa85853d5a2d8fdf8af85e")
}
}
test_replset:PRIMARY>
提示:可以看到心跳时间间隔为2s,超时为10s,选举超时时长为10等等信息;
添加node02,node03节点到副本集成员
test_replset:PRIMARY> rs.add("node02")
{
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1605011243, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
},
"operationTime" : Timestamp(1605011243, 1)
}
test_replset:PRIMARY> rs.add("node03")
{
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1605011250, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
},
"operationTime" : Timestamp(1605011250, 1)
}
test_replset:PRIMARY> rs.status()
{
"set" : "test_replset",
"date" : ISODate("2020-11-10T12:27:45.849Z"),
"myState" : 1,
"term" : NumberLong(1),
"syncSourceHost" : "",
"syncSourceId" : -1,
"heartbeatIntervalMillis" : NumberLong(2000),
"majorityVoteCount" : 2,
"writeMajorityCount" : 2,
"votingMembersCount" : 3,
"writableVotingMembersCount" : 3,
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(1605011261, 1),
"t" : NumberLong(1)
},
"lastCommittedWallTime" : ISODate("2020-11-10T12:27:41.873Z"),
"readConcernMajorityOpTime" : {
"ts" : Timestamp(1605011261, 1),
"t" : NumberLong(1)
},
"readConcernMajorityWallTime" : ISODate("2020-11-10T12:27:41.873Z"),
"appliedOpTime" : {
"ts" : Timestamp(1605011261, 1),
"t" : NumberLong(1)
},
"durableOpTime" : {
"ts" : Timestamp(1605011261, 1),
"t" : NumberLong(1)
},
"lastAppliedWallTime" : ISODate("2020-11-10T12:27:41.873Z"),
"lastDurableWallTime" : ISODate("2020-11-10T12:27:41.873Z")
},
"electionCandidateMetrics" : {
"lastElectionReason" : "electionTimeout",
"lastElectionDate" : ISODate("2020-11-10T12:20:21.632Z"),
"electionTerm" : NumberLong(1),
"lastCommittedOpTimeAtElection" : {
"ts" : Timestamp(0, 0),
"t" : NumberLong(-1)
},
"lastSeenOpTimeAtElection" : {
"ts" : Timestamp(1605010821, 1),
"t" : NumberLong(-1)
},
"numVotesNeeded" : 1,
"priorityAtElection" : 1,
"electionTimeoutMillis" : NumberLong(10000),
"newTermStartDate" : ISODate("2020-11-10T12:20:21.694Z"),
"wMajorityWriteAvailabilityDate" : ISODate("2020-11-10T12:20:21.719Z")
},
"members" : [
{
"_id" : 0,
"name" : "node01.test.org:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 1107,
"optime" : {
"ts" : Timestamp(1605011261, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2020-11-10T12:27:41Z"),
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "",
"electionTime" : Timestamp(1605010821, 2),
"electionDate" : ISODate("2020-11-10T12:20:21Z"),
"configVersion" : 3,
"configTerm" : 1,
"self" : true,
"lastHeartbeatMessage" : ""
},
{
"_id" : 1,
"name" : "node02:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 21,
"optime" : {
"ts" : Timestamp(1605011261, 1),
"t" : NumberLong(1)
},
"optimeDurable" : {
"ts" : Timestamp(1605011261, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2020-11-10T12:27:41Z"),
"optimeDurableDate" : ISODate("2020-11-10T12:27:41Z"),
"lastHeartbeat" : ISODate("2020-11-10T12:27:44.967Z"),
"lastHeartbeatRecv" : ISODate("2020-11-10T12:27:43.983Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncSourceHost" : "node01.test.org:27017",
"syncSourceId" : 0,
"infoMessage" : "",
"configVersion" : 3,
"configTerm" : 1
},
{
"_id" : 2,
"name" : "node03:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 14,
"optime" : {
"ts" : Timestamp(1605011261, 1),
"t" : NumberLong(1)
},
"optimeDurable" : {
"ts" : Timestamp(1605011261, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2020-11-10T12:27:41Z"),
"optimeDurableDate" : ISODate("2020-11-10T12:27:41Z"),
"lastHeartbeat" : ISODate("2020-11-10T12:27:44.967Z"),
"lastHeartbeatRecv" : ISODate("2020-11-10T12:27:44.571Z"),
"pingMs" : NumberLong(1),
"lastHeartbeatMessage" : "",
"syncSourceHost" : "node02:27017",
"syncSourceId" : 1,
"infoMessage" : "",
"configVersion" : 3,
"configTerm" : 1
}
],
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1605011261, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
},
"operationTime" : Timestamp(1605011261, 1)
}
test_replset:PRIMARY>
提示:添加节点到副本成员使用rs.add(),括号里面写主机名,或者ip地址,如果对应节点监听端口不是27017,还需要写明端口;除此我们也可以直接用一个子文档的形式,手动指定节点的各属性信息来添加节点到副本集成员;
到此副本集的配置就完成了,三个节点都添加到副本集;
验证:在主库上插入数据,看看从库是否都可以正常同步其数据呢?
在主节点插入数据
test_replset:PRIMARY> use students
switched to db students
test_replset:PRIMARY> db.student_info.insert({name:"tom",age:18,gender:"M"})
WriteResult({ "nInserted" : 1 })
test_replset:PRIMARY> db.student_info.find()
{ "_id" : ObjectId("5faa89297077300f4fc31d1c"), "name" : "tom", "age" : 18, "gender" : "M" }
test_replset:PRIMARY>
在从节点查看数据
test_replset:SECONDARY> show dbs
uncaught exception: Error: listDatabases failed:{
"topologyVersion" : {
"processId" : ObjectId("5faa83025f9218c5d19ea91b"),
"counter" : NumberLong(4)
},
"operationTime" : Timestamp(1605011801, 1),
"ok" : 0,
"errmsg" : "not master and slaveOk=false",
"code" : 13435,
"codeName" : "NotMasterNoSlaveOk",
"$clusterTime" : {
"clusterTime" : Timestamp(1605011801, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
Mongo.prototype.getDBs/<@src/mongo/shell/mongo.js:147:19
Mongo.prototype.getDBs@src/mongo/shell/mongo.js:99:12
shellHelper.show@src/mongo/shell/utils.js:937:13
shellHelper@src/mongo/shell/utils.js:819:15
@(shellhelp2):1:1
test_replset:SECONDARY>
提示:这里在从节点上没法查看数据,原因是默认情况副本集配置好以后,要在从节点运行rs.secondaryOk()来告诉从节点已经配置好了,否则它会不允许我们读,有点类似从节点为就绪的感觉;
在从节点上运行rs.secondaryOk(),然后再次查看数据
test_replset:SECONDARY> rs.secondaryOk()
test_replset:SECONDARY> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
students 0.000GB
test_replset:SECONDARY> use students
switched to db students
test_replset:SECONDARY> show collections
student_info
test_replset:SECONDARY> db.student_info.find().pretty()
{
"_id" : ObjectId("5faa89297077300f4fc31d1c"),
"name" : "tom",
"age" : 18,
"gender" : "M"
}
test_replset:SECONDARY>
提示:可以看到在secondary节点上能够查询到对应数据库中的对应collection中插入的数据;
验证:在从节点上插入数据,看看是否能插入成功?
test_replset:SECONDARY> db.student_info.insert({name:"jerry",age:19,gender:"M"})
WriteCommandError({
"topologyVersion" : {
"processId" : ObjectId("5faa831bde03c4ae108f0be4"),
"counter" : NumberLong(3)
},
"operationTime" : Timestamp(1605012904, 1),
"ok" : 0,
"errmsg" : "not master",
"code" : 10107,
"codeName" : "NotMaster",
"$clusterTime" : {
"clusterTime" : Timestamp(1605012904, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
})
test_replset:SECONDARY>
提示:我们在从节点上插入数据,它提示我们不是主节点,不允许插入数据;这说明副本集的从节点是不允许写;
验证:将主节点上的mongodb服务停掉,然后在其他两个节点上查看副本集状态,看看两个节点是否重新选举了master?
[root@node01 ~]# systemctl stop mongod.service
[root@node01 ~]# ss -tnl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:22 *:*
LISTEN 0 100 127.0.0.1:25 *:*
LISTEN 0 128 :::22 :::*
LISTEN 0 100 ::1:25 :::*
[root@node01 ~]# mongo --host node02
MongoDB shell version v4.4.1
connecting to: mongodb://node02:27017/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("90d60f76-fc95-44a8-bbf7-d927d5947331") }
MongoDB server version: 4.4.1
---
The server generated these startup warnings when booting:
2020-11-10T20:09:39.555+08:00: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted
2020-11-10T20:09:39.555+08:00: /sys/kernel/mm/transparent_hugepage/enabled is 'always'. We suggest setting it to 'never'
2020-11-10T20:09:39.555+08:00: /sys/kernel/mm/transparent_hugepage/defrag is 'always'. We suggest setting it to 'never'
---
---
Enable MongoDB's free cloud-based monitoring service, which will then receive and display
metrics about your deployment (disk utilization, CPU, operation statistics, etc). The monitoring data will be available on a MongoDB website with a unique URL accessible to you
and anyone you share the URL with. MongoDB may use this information to make product
improvements and to suggest MongoDB products and deployment options to you. To enable free monitoring, run the following command: db.enableFreeMonitoring()
To permanently disable this reminder, run the following command: db.disableFreeMonitoring()
---
test_replset:PRIMARY> rs.status()
{
"set" : "test_replset",
"date" : ISODate("2020-11-10T12:59:25.775Z"),
"myState" : 1,
"term" : NumberLong(2),
"syncSourceHost" : "",
"syncSourceId" : -1,
"heartbeatIntervalMillis" : NumberLong(2000),
"majorityVoteCount" : 2,
"writeMajorityCount" : 2,
"votingMembersCount" : 3,
"writableVotingMembersCount" : 3,
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(1605013164, 1),
"t" : NumberLong(2)
},
"lastCommittedWallTime" : ISODate("2020-11-10T12:59:24.417Z"),
"readConcernMajorityOpTime" : {
"ts" : Timestamp(1605013164, 1),
"t" : NumberLong(2)
},
"readConcernMajorityWallTime" : ISODate("2020-11-10T12:59:24.417Z"),
"appliedOpTime" : {
"ts" : Timestamp(1605013164, 1),
"t" : NumberLong(2)
},
"durableOpTime" : {
"ts" : Timestamp(1605013164, 1),
"t" : NumberLong(2)
},
"lastAppliedWallTime" : ISODate("2020-11-10T12:59:24.417Z"),
"lastDurableWallTime" : ISODate("2020-11-10T12:59:24.417Z")
},
"electionCandidateMetrics" : {
"lastElectionReason" : "stepUpRequestSkipDryRun",
"lastElectionDate" : ISODate("2020-11-10T12:58:34.398Z"),
"electionTerm" : NumberLong(2),
"lastCommittedOpTimeAtElection" : {
"ts" : Timestamp(1605013112, 1),
"t" : NumberLong(1)
},
"lastSeenOpTimeAtElection" : {
"ts" : Timestamp(1605013112, 1),
"t" : NumberLong(1)
},
"numVotesNeeded" : 2,
"priorityAtElection" : 1,
"electionTimeoutMillis" : NumberLong(10000),
"priorPrimaryMemberId" : 0,
"numCatchUpOps" : NumberLong(0),
"newTermStartDate" : ISODate("2020-11-10T12:58:34.410Z"),
"wMajorityWriteAvailabilityDate" : ISODate("2020-11-10T12:58:34.506Z")
},
"members" : [
{
"_id" : 0,
"name" : "node01.test.org:27017",
"health" : 0,
"state" : 8,
"stateStr" : "(not reachable/healthy)",
"uptime" : 0,
"optime" : {
"ts" : Timestamp(0, 0),
"t" : NumberLong(-1)
},
"optimeDurable" : {
"ts" : Timestamp(0, 0),
"t" : NumberLong(-1)
},
"optimeDate" : ISODate("1970-01-01T00:00:00Z"),
"optimeDurableDate" : ISODate("1970-01-01T00:00:00Z"),
"lastHeartbeat" : ISODate("2020-11-10T12:59:24.558Z"),
"lastHeartbeatRecv" : ISODate("2020-11-10T12:58:35.045Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "Error connecting to node01.test.org:27017 (192.168.0.41:27017) :: caused by :: Connection refused",
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "",
"configVersion" : 3,
"configTerm" : 1
},
{
"_id" : 1,
"name" : "node02:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 2987,
"optime" : {
"ts" : Timestamp(1605013164, 1),
"t" : NumberLong(2)
},
"optimeDate" : ISODate("2020-11-10T12:59:24Z"),
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "",
"electionTime" : Timestamp(1605013114, 1),
"electionDate" : ISODate("2020-11-10T12:58:34Z"),
"configVersion" : 3,
"configTerm" : 2,
"self" : true,
"lastHeartbeatMessage" : ""
},
{
"_id" : 2,
"name" : "node03:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 1914,
"optime" : {
"ts" : Timestamp(1605013164, 1),
"t" : NumberLong(2)
},
"optimeDurable" : {
"ts" : Timestamp(1605013164, 1),
"t" : NumberLong(2)
},
"optimeDate" : ISODate("2020-11-10T12:59:24Z"),
"optimeDurableDate" : ISODate("2020-11-10T12:59:24Z"),
"lastHeartbeat" : ISODate("2020-11-10T12:59:24.459Z"),
"lastHeartbeatRecv" : ISODate("2020-11-10T12:59:25.506Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncSourceHost" : "node02:27017",
"syncSourceId" : 1,
"infoMessage" : "",
"configVersion" : 3,
"configTerm" : 2
}
],
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1605013164, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
},
"operationTime" : Timestamp(1605013164, 1)
}
test_replset:PRIMARY>
提示:可以看到当node01上的mongodb服务停掉以后,对应的主节点也就不能够正常的向从节点发送心跳,所以剩下的两个从节点都认为主节点挂了,此时他俩就开始重新选举主节点;我们再次连接到node02上的mongodb查看副本集状态时,此时node02上的mongodb就成为了主节点;同时我们也能看到node01的健康状态为0,表示不健康;
查看从节点的复制信息
test_replset:PRIMARY> rs.printSecondaryReplicationInfo()
source: node01.test.org:27017
syncedTo: Thu Jan 01 1970 08:00:00 GMT+0800 (CST)
1605013534 secs (445837.09 hrs) behind the primary
source: node03:27017
syncedTo: Tue Nov 10 2020 21:05:34 GMT+0800 (CST)
0 secs (0 hrs) behind the primary
test_replset:PRIMARY>
提示:这里可以看到node01落后主节点很长时间,node03不落后主节点;
查看同步信息时间窗口,以及oplog大小
test_replset:PRIMARY> rs.printReplicationInfo()
configured oplog size: 2048MB
log length start to end: 2291secs (0.64hrs)
oplog first event time: Tue Nov 10 2020 20:27:23 GMT+0800 (CST)
oplog last event time: Tue Nov 10 2020 21:05:34 GMT+0800 (CST)
now: Tue Nov 10 2020 21:05:35 GMT+0800 (CST)
test_replset:PRIMARY>
提示:可以看到oplog的小为2048MB,日志开始到结束的时间窗口为2291秒,意思是说当前启动副本集到查询复制信息是的时长为2291秒;第一个oplog时间时间和最后oplog事件时间以及现在的时间都可查看得到;
移除节点(从副本集中,将node01节点移除)
test_replset:PRIMARY> rs.remove("node01.test.org:27017")
{
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1605014063, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
},
"operationTime" : Timestamp(1605014063, 1)
}
test_replset:PRIMARY> rs.status()
{
"set" : "test_replset",
"date" : ISODate("2020-11-10T13:14:35.362Z"),
"myState" : 1,
"term" : NumberLong(2),
"syncSourceHost" : "",
"syncSourceId" : -1,
"heartbeatIntervalMillis" : NumberLong(2000),
"majorityVoteCount" : 2,
"writeMajorityCount" : 2,
"votingMembersCount" : 2,
"writableVotingMembersCount" : 2,
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(1605014074, 1),
"t" : NumberLong(2)
},
"lastCommittedWallTime" : ISODate("2020-11-10T13:14:34.514Z"),
"readConcernMajorityOpTime" : {
"ts" : Timestamp(1605014074, 1),
"t" : NumberLong(2)
},
"readConcernMajorityWallTime" : ISODate("2020-11-10T13:14:34.514Z"),
"appliedOpTime" : {
"ts" : Timestamp(1605014074, 1),
"t" : NumberLong(2)
},
"durableOpTime" : {
"ts" : Timestamp(1605014074, 1),
"t" : NumberLong(2)
},
"lastAppliedWallTime" : ISODate("2020-11-10T13:14:34.514Z"),
"lastDurableWallTime" : ISODate("2020-11-10T13:14:34.514Z")
},
"electionCandidateMetrics" : {
"lastElectionReason" : "stepUpRequestSkipDryRun",
"lastElectionDate" : ISODate("2020-11-10T12:58:34.398Z"),
"electionTerm" : NumberLong(2),
"lastCommittedOpTimeAtElection" : {
"ts" : Timestamp(1605013112, 1),
"t" : NumberLong(1)
},
"lastSeenOpTimeAtElection" : {
"ts" : Timestamp(1605013112, 1),
"t" : NumberLong(1)
},
"numVotesNeeded" : 2,
"priorityAtElection" : 1,
"electionTimeoutMillis" : NumberLong(10000),
"priorPrimaryMemberId" : 0,
"numCatchUpOps" : NumberLong(0),
"newTermStartDate" : ISODate("2020-11-10T12:58:34.410Z"),
"wMajorityWriteAvailabilityDate" : ISODate("2020-11-10T12:58:34.506Z")
},
"members" : [
{
"_id" : 1,
"name" : "node02:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 3897,
"optime" : {
"ts" : Timestamp(1605014074, 1),
"t" : NumberLong(2)
},
"optimeDate" : ISODate("2020-11-10T13:14:34Z"),
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "",
"electionTime" : Timestamp(1605013114, 1),
"electionDate" : ISODate("2020-11-10T12:58:34Z"),
"configVersion" : 4,
"configTerm" : 2,
"self" : true,
"lastHeartbeatMessage" : ""
},
{
"_id" : 2,
"name" : "node03:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 2824,
"optime" : {
"ts" : Timestamp(1605014063, 1),
"t" : NumberLong(2)
},
"optimeDurable" : {
"ts" : Timestamp(1605014063, 1),
"t" : NumberLong(2)
},
"optimeDate" : ISODate("2020-11-10T13:14:23Z"),
"optimeDurableDate" : ISODate("2020-11-10T13:14:23Z"),
"lastHeartbeat" : ISODate("2020-11-10T13:14:33.958Z"),
"lastHeartbeatRecv" : ISODate("2020-11-10T13:14:33.970Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncSourceHost" : "node02:27017",
"syncSourceId" : 1,
"infoMessage" : "",
"configVersion" : 4,
"configTerm" : 2
}
],
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1605014074, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
},
"operationTime" : Timestamp(1605014074, 1)
}
test_replset:PRIMARY>
提示:移除节点需要写明对应节点的主机名地址和端口,或者是ip地址端口;这个字串必须是同加入到副本集中的名字相同才可移除,否则它会提示我们给定主机字符串找不到;
设置node03的优先级为10
test_replset:PRIMARY> cfg = rs.conf()
{
"_id" : "test_replset",
"version" : 4,
"term" : 2,
"protocolVersion" : NumberLong(1),
"writeConcernMajorityJournalDefault" : true,
"members" : [
{
"_id" : 1,
"host" : "node02:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : { },
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 2,
"host" : "node03:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : { },
"slaveDelay" : NumberLong(0),
"votes" : 1
}
],
"settings" : {
"chainingAllowed" : true,
"heartbeatIntervalMillis" : 2000,
"heartbeatTimeoutSecs" : 10,
"electionTimeoutMillis" : 10000,
"catchUpTimeoutMillis" : -1,
"catchUpTakeoverDelayMillis" : 30000,
"getLastErrorModes" : { },
"getLastErrorDefaults" : {
"w" : 1,
"wtimeout" : 0
},
"replicaSetId" : ObjectId("5faa85853d5a2d8fdf8af85e")
}
}
test_replset:PRIMARY> cfg.members[1].priority = 10
10
test_replset:PRIMARY> rs.reconfig(cfg)
{
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1605015945, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
},
"operationTime" : Timestamp(1605015945, 1)
}
test_replset:PRIMARY> rs.config()
{
"_id" : "test_replset",
"version" : 5,
"term" : 3,
"protocolVersion" : NumberLong(1),
"writeConcernMajorityJournalDefault" : true,
"members" : [
{
"_id" : 1,
"host" : "node02:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : { },
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 2,
"host" : "node03:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 10,
"tags" : { },
"slaveDelay" : NumberLong(0),
"votes" : 1
}
],
"settings" : {
"chainingAllowed" : true,
"heartbeatIntervalMillis" : 2000,
"heartbeatTimeoutSecs" : 10,
"electionTimeoutMillis" : 10000,
"catchUpTimeoutMillis" : -1,
"catchUpTakeoverDelayMillis" : 30000,
"getLastErrorModes" : { },
"getLastErrorDefaults" : {
"w" : 1,
"wtimeout" : 0
},
"replicaSetId" : ObjectId("5faa85853d5a2d8fdf8af85e")
}
}
test_replset:SECONDARY>
提示:设置某个成员的优先级,首先要把当前配置用一个变量保存,然后通过修改保存的配置变量来修改优先级以后,再使用rs.reconfig()来读取修改后的配置即可生效;这里需要注意我在修改配置文件时指定成员,是指定对应成员在members列表的下标,而非id;所以修改前要先确定对应成员的下标是多少;我们修改了node03的优先级以后,心细的你一定会发现node02此时就变成了secondary;这意味着,只要在副本集中有更高优先级的成员加入,会触发一次选举,当然选举成为主节点,影响最大的就是各节点的优先级,优先级越高,当选主节点的几率就越大;默认情况每个成员的优先级都为1,优先级设定的取值范围是0-1000;
将node01上的mongodb服务启动起来,然后在主节点上将其添加为仲裁节点
启动node01上的mongodb服务
[root@node01 ~]# systemctl start mongod.service
[root@node01 ~]# ss -tnl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:22 *:*
LISTEN 0 100 127.0.0.1:25 *:*
LISTEN 0 128 *:27017 *:*
LISTEN 0 128 :::22 :::*
LISTEN 0 100 ::1:25 :::*
[root@node01 ~]#
在主节点上将node01添加为仲裁节点
test_replset:PRIMARY> rs.addArb("node01")
{
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1605016848, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
},
"operationTime" : Timestamp(1605016848, 1)
}
test_replset:PRIMARY>
查看配置信息,看看node01上的arbiterOnly是否变成了true?
test_replset:PRIMARY> rs.config()
{
"_id" : "test_replset",
"version" : 8,
"term" : 3,
"protocolVersion" : NumberLong(1),
"writeConcernMajorityJournalDefault" : true,
"members" : [
{
"_id" : 1,
"host" : "node02:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : { },
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 2,
"host" : "node03:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 10,
"tags" : { },
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 3,
"host" : "node01:27017",
"arbiterOnly" : true,
"buildIndexes" : true,
"hidden" : false,
"priority" : 0,
"tags" : { },
"slaveDelay" : NumberLong(0),
"votes" : 1
}
],
"settings" : {
"chainingAllowed" : true,
"heartbeatIntervalMillis" : 2000,
"heartbeatTimeoutSecs" : 10,
"electionTimeoutMillis" : 10000,
"catchUpTimeoutMillis" : -1,
"catchUpTakeoverDelayMillis" : 30000,
"getLastErrorModes" : { },
"getLastErrorDefaults" : {
"w" : 1,
"wtimeout" : 0
},
"replicaSetId" : ObjectId("5faa85853d5a2d8fdf8af85e")
}
}
test_replset:PRIMARY>
提示:可以看到node01节点上的arbiterOnly属性已经启用,说明这就是一个仲裁节点;我们说过仲裁节点上没有保存副本,我们到node01上看看是否保存的有副本集数据呢?
test_replset:ARBITER> show databases
uncaught exception: Error: listDatabases failed:{
"topologyVersion" : {
"processId" : ObjectId("5faa9d87e504fa222c4a584d"),
"counter" : NumberLong(1)
},
"ok" : 0,
"errmsg" : "not master and slaveOk=false",
"code" : 13435,
"codeName" : "NotMasterNoSlaveOk"
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
Mongo.prototype.getDBs/<@src/mongo/shell/mongo.js:147:19
Mongo.prototype.getDBs@src/mongo/shell/mongo.js:99:12
shellHelper.show@src/mongo/shell/utils.js:937:13
shellHelper@src/mongo/shell/utils.js:819:15
@(shellhelp2):1:1
test_replset:ARBITER> rs.secondaryOk()
test_replset:ARBITER> show databases
uncaught exception: Error: listDatabases failed:{
"topologyVersion" : {
"processId" : ObjectId("5faa9d87e504fa222c4a584d"),
"counter" : NumberLong(1)
},
"ok" : 0,
"errmsg" : "node is not in primary or recovering state",
"code" : 13436,
"codeName" : "NotMasterOrSecondary"
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
Mongo.prototype.getDBs/<@src/mongo/shell/mongo.js:147:19
Mongo.prototype.getDBs@src/mongo/shell/mongo.js:99:12
shellHelper.show@src/mongo/shell/utils.js:937:13
shellHelper@src/mongo/shell/utils.js:819:15
@(shellhelp2):1:1
test_replset:ARBITER>
提示:我们在仲裁节点上查看数据库列表,它提示我们不是主节点和从节点,不允许读;既然都不允许读,写肯定是没有办法进行;
ok,到此mongodb的副本集的配置、测试就到此为止;
分布式文档存储数据库之MongoDB副本集的更多相关文章
-
分布式文档存储数据库之MongoDB分片集群
前文我们聊到了mongodb的副本集以及配置副本集,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/13953598.html:今天我们来聊下mongodb的分片 ...
-
分布式文档存储数据库之MongoDB基础入门
一.MongoDB简介 MongoDB是用c++语言开发的一款易扩展,易伸缩,高性能,开源的,schema free 的基于文档的nosql数据库:所谓nosql是指不仅仅是sql的意思,它拥有部分s ...
-
分布式文档存储数据库之MongoDB索引管理
前文我们聊到了MongoDB的简介.安装和对collection的CRUD操作,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/13941797.html:今天我 ...
-
分布式文档存储数据库之MongoDB备份与恢复
前文我们聊了下mongodb的访问控制以及用户创建和角色分配,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/13974656.html:今天我们来了解下mong ...
-
分布式文档存储数据库之MongoDB访问控制
上一篇博客主要聊了下mongodb的分片机制以及分片集群的搭建,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/13958295.html:今天我们来了解下mon ...
-
分布式文档存储数据库(MongoDB)副本集配置
副本集特征: N 个节点的集群 任何节点可作为主节点 所有写入操作都在主节点上 自动故障转移 自动恢复 相关文章: http://www.cnblogs.com/huangxincheng/archi ...
-
分布式文档存储数据库 MongoDB
MongoDB 详细介绍 MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的.他支持的数据结构非常松散,是类似json的bjson格式,因此可以 ...
-
ElasticSearch 学习记录之 分布式文档存储往ES中存数据和取数据的原理
分布式文档存储 ES分布式特性 屏蔽了分布式系统的复杂性 集群内的原理 垂直扩容和水平扩容 真正的扩容能力是来自于水平扩容–为集群添加更多的节点,并且将负载压力和稳定性分散到这些节点中 ES集群特点 ...
-
ElasticSearch 5学习(8)——分布式文档存储(wait_for_active_shards新参数分析)
学完ES分布式集群的工作原理以及一些基本的将数据放入索引然后检索它们的所有方法,我们可以继续学习在分布式系统中,每个分片的文档是被如何索引和查询的. 路由 首先,我们需要明白,文档和分片之间是如何匹配 ...
随机推荐
-
Ubuntu 14.10 下查看系统硬件信息(实例详解)
linux查看系统的硬件信息,并不像windows那么直观,这里我罗列了查看系统信息的实用命令,并做了分类,实例解说. cpu lscpu命令,查看的是cpu的统计信息. blue@blue-pc:~ ...
-
Java序列化,serializable
Java 串行化技术可以使你将一个对象的状态写入一个Byte 流里,并且可以从其它地方把该Byte 流里的数据读出来,重新构造一个相同的对象.这种机制允许你将对象通过网络进行传播,并可以随时把对象持久 ...
-
(5/18)重学Standford_iOS7开发_视图控制器生命周期_课程笔记
第五课: 1.UITextView @property (nonatomic, readonly) NSTextStorage *textStorage;//注意为只读属性,因此不能直接更改内容,NS ...
-
如何备份及恢复Linux文件权限
你可能听说或碰到过这样的事情:一个系统管理员菜鸟不小心输入"chmod -R 777 /"从而导致了巨大的悲剧,使得整个系统遭到了严重的破坏.在日常管理中,我们有许多工具可以用来备 ...
-
BZOJ 2761 不重复数字 (Hash)
题解:直接使用STL中的hash去重即可 #include <cstdio> #include <map> using namespace std; int ans[50010 ...
-
jstack
简介 jstack用于打印出给定的java进程ID的Java堆栈信息,一般用于检查应用的线程问题,死锁问题 常用命令 jstack 输出 $ jstack 11376 2014-01-21 20:36 ...
-
webstorm ps
2018WebStorm注册码 2018-10-10 2018年08月22日 17:36:58 阳光明媚的味道 阅读数:6325 8月21日 http://webstorm.autoseasy ...
-
Luogu P2403 [SDOI2010]所驼门王的宝藏
比较显然的缩点+拓扑排序题,只不过要建虚点优化建边. 首先我们发现在一个SCC里的点都是可以一起对答案产生贡献的,因此先缩成DAG,然后拓扑找最长链. 但是我们发现这题最坏情况下边数会达到恐怖的\(O ...
-
php删除文件夹和其下的内容
原文地址:http://www.cnblogs.com/xiaochaohuashengmi/archive/2011/05/13/2045158.html <?php function del ...
-
UnicodeDammit
UnicodeDammit 是BS内置库, 主要用来猜测文档编码. 编码自动检测 功能可以在Beautiful Soup以外使用,检测某段未知编码时,可以使用这个方法: from bs4 import ...