文章目录

  • 创建MongoDB副本集
  • 安装
  • 配置
  • 生成key
  • 启动MongoDB
  • 创建集群
  • 使用Springboot Mongotemplate连接副本集操作


创建MongoDB副本集

MongoDB副本集实现故障自动切换至少需要以下配置为:
1.一个主节点,两个从节点
2.一个主节点,一个从节点一个仲裁节点。
如果只有一主一从节点,故障时无法选举出主节点从而实现切换。

安装

在三台服务器上安装MongoDB,同时在主节点数据库上提前创建好有副本集权限的用户。
当然你也可以选择安装在同一台服务器上(除了测试用,不然意义不大)。
安装部分请自行搜索网上资料,在此不再赘述。

配置

修改三个Mongo配置文件,都加入以下配置
第一个参数是指定副本集
第二个参数是使用key进行安全认证

replSet=test_resplset
keyFile=/usr/local/mongodb/conf/mongodb_key

如果配置中有auth=on项,请删除,否则会造成节点没有权限连接。副本集使用key文件进行安全认证。

生成key

> openssl rand -base64 102 /usr/local/mongodb/conf/mongodb_key

生成key文件

> chmod 600 /usr/local/mongodb/conf/mongodb_key

赋600权限

启动MongoDB

正常启动三个Mongo服务即可

> /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/conf/mongodb.conf

然后连接一台你想使其成为主节点的数据库。

创建集群

连接主节点后,输入:

> config = {
           "_id" : "test_resplset",
           "members" : [
                   {
                           "_id" : 0,
                           "host" : "192.168.1.123:27020",
                           "priority" : 99
                   },
                   {
                           "_id" : 1,
                           "host" : "192.168.1.124:27021"
                   },
                   {
                           "_id" : 2,
                           "host" : "192.168.1.125:27022",
                           "arbiterOnly" : true
                   }
           ] }

arbiterOnly: true指这个节点为仲裁节点。
这里无论你的三个服务是否在同一个服务器上,都不要使用127.0.0.1地址,否则稍后连接数据库的时候会连接不上(域名我没测试过,各位可以自己尝试)。

> rs.initiate(config)

初始化集群。这两步只需要在主节点上操作一次即可。
出现{"ok":1}代表配置成功。
如果此处报没有权限认证的错误,请先使用有副本集权限的用户进行权限认证。

> use admin
> db.auth("user","pwd")

如果提示本节点不是主节点,请关闭主节点数据库,注释掉指定副本集参数后单机启动,然后进行操作。操作完成后重新以副本集启动。

> rs.status() // 查看集群状态
{
        "set" : "test_resplset",
        "date" : ISODate("2019-04-19T08:39:05.420Z"),
        "myState" : 1,
        "term" : NumberLong(1),
        "syncingTo" : "",
        "syncSourceHost" : "",
        "syncSourceId" : -1,
        "heartbeatIntervalMillis" : NumberLong(2000),
        "optimes" : {
                "lastCommittedOpTime" : {
                        "ts" : Timestamp(1555663135, 1),
                        "t" : NumberLong(1)
                },
                "readConcernMajorityOpTime" : {
                        "ts" : Timestamp(1555663135, 1),
                        "t" : NumberLong(1)
                },
                "appliedOpTime" : {
                        "ts" : Timestamp(1555663135, 1),
                        "t" : NumberLong(1)
                },
                "durableOpTime" : {
                        "ts" : Timestamp(1555663135, 1),
                        "t" : NumberLong(1)
                }
        },
        "lastStableCheckpointTimestamp" : Timestamp(1555663085, 1),
        "members" : [
                {
                        "_id" : 0,
                        "name" : "192.168.1.123:27020",
                        "health" : 1,
                        "state" : 1,
                        "stateStr" : "PRIMARY",
                        "uptime" : 795,
                        "optime" : {
                                "ts" : Timestamp(1555663135, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDate" : ISODate("2019-04-19T08:38:55Z"),
                        "syncingTo" : "",
                        "syncSourceHost" : "",
                        "syncSourceId" : -1,
                        "infoMessage" : "could not find member to sync from",
                        "electionTime" : Timestamp(1555663083, 1),
                        "electionDate" : ISODate("2019-04-19T08:38:03Z"),
                        "configVersion" : 1,
                        "self" : true,
                        "lastHeartbeatMessage" : ""
                },
                {
                        "_id" : 1,
                        "name" : "192.168.1.124:27021",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",
                        "uptime" : 71,
                        "optime" : {
                                "ts" : Timestamp(1555663135, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDurable" : {
                                "ts" : Timestamp(1555663135, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDate" : ISODate("2019-04-19T08:38:55Z"),
                        "optimeDurableDate" : ISODate("2019-04-19T08:38:55Z"),
                        "lastHeartbeat" : ISODate("2019-04-19T08:39:03.693Z"),
                        "lastHeartbeatRecv" : ISODate("2019-04-19T08:39:04.714Z"),
                        "pingMs" : NumberLong(0),
                        "lastHeartbeatMessage" : "",
                        "syncingTo" : "192.168.1.123:27020",
                        "syncSourceHost" : "192.168.1.123:27020",
                        "syncSourceId" : 0,
                        "infoMessage" : "",
                        "configVersion" : 1
                },
                {
                        "_id" : 2,
                        "name" : "192.168.1.125:27022",
                        "health" : 1,
                        "state" : 7,
                        "stateStr" : "ARBITER",
                        "uptime" : 71,
                        "lastHeartbeat" : ISODate("2019-04-19T08:39:03.691Z"),
                        "lastHeartbeatRecv" : ISODate("2019-04-19T08:39:03.615Z"),
                        "pingMs" : NumberLong(0),
                        "lastHeartbeatMessage" : "",
                        "syncingTo" : "",
                        "syncSourceHost" : "",
                        "syncSourceId" : -1,
                        "infoMessage" : "",
                        "configVersion" : 1
                }
        ],
        "ok" : 1,
        "operationTime" : Timestamp(1555663135, 1),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1555663135, 1),
                "signature" : {
                        "hash" : BinData(0,"KMcQWa4w+xlc02Atf6a/uv6DH9I="),
                        "keyId" : NumberLong("6681522073669468161")
                }
        }
}

可以看到一个主节点,一个仲裁节点,一个从节点。

使用Springboot Mongotemplate连接副本集操作

人懒,此处就简单使用单元测试做个例子吧。上代码:

@Data
@Document(collection = "test")
class Author {
    private String name;
}
@Test
    public void testReadMongoReplSet() {
        MongoClientURI mongoClientURI = new MongoClientURI("mongodb://user:pwd@192.168.1.123:27020,192.168.1.124:27021/test_resplset?replicaSet=test_resplset&authSource=test_resplset&readPreference=secondaryPreferred&safe=true&authMechanism=SCRAM-SHA-1&maxPoolSize=500&minPoolSize=10");
        SimpleMongoDbFactory mongoDbFactory = new SimpleMongoDbFactory(mongoClientURI);
        MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory);
        System.out.println(mongoTemplate.find(new Query(),Author.class));
        try {
            mongoDbFactory.destroy();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testWriteMongoReplSet() {
        MongoClientURI mongoClientURI = new MongoClientURI("mongodb://user:pwd@192.168.1.123:27020,192.168.1.124:27021/test_resplset?replicaSet=test_resplset&authSource=test_resplset&readPreference=secondaryPreferred&safe=true&authMechanism=SCRAM-SHA-1&maxPoolSize=500&minPoolSize=10");
        SimpleMongoDbFactory mongoDbFactory = new SimpleMongoDbFactory(mongoClientURI);
        MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory);
        Author a=  new Author();
        a.setName("testWrite");
        mongoTemplate.insert(a);
        try {
            mongoDbFactory.destroy();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

mongodb://user:pwd@192.168.1.123:27020,192.168.1.124:27021/test_resplset?replicaSet=test_resplset&authSource=test_resplset&readPreference=secondaryPreferred&safe=true&authMechanism=SCRAM-SHA-1&maxPoolSize=500&minPoolSize=10 我们来看下这链接地址。
首先整体格式应该满足:

mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]
  • username:password用户名密码没啥好说的。
  • 192.168.1.123:27020,192.168.1.124:27021这一段填的是主从节点的地址,仲裁节点不需要填写。
  • /test_resplset这里是指的数据库名
  • replicaSet=test_resplset指定副本集(这里是因为我数据库名和副本集名建的一样,实际并不一样,自己注意)
  • authSource=test_resplset认证的数据库
  • readPreference=secondaryPreferred读走从节点
  • safe=true在执行更新操作之后,驱动都会发送getLastError命令来确保更新成功

执行成功时,会在控制台打印相应日志,能够看到读写走的哪个服务。
192.168.1.123:27020为主节点,写服务走它。
192.168.1.124:27021为从节点,读服务走它。
192.168.1.125:27022为仲裁节点,连接时不需要写上。

如果是Springboot 直接使用@Autowired注入MongoTemplate,同时在配置文件中加入那串地址就行,没上面这么麻烦。