MongoDB复制集简介
Mongodb复制集由一组Mongod实例(进程)组成,包含一个Primary节点和多个Secondary节点,Mongodb Driver(客户端)的所有数据都写入Primary,Secondary从Primary同步写入的数据,以保持复制集内所有成员存储相同的数据集,提供数据的高可用。
MongoDB C Driver
mongoc 是官方的mongo驱动,用于通过程序来控制mongo数据库。
目前所有MongoDB复制集的配置都是通过mongo客户端进行配置的,无法实现自动配置。
#传统的老方法,需要手动配置,无法自动化配置
mongo --port=28017
use admin
config = {_id: 'my_repl', members: [
{_id: 0, host: '10.0.0.134:28017'},
{_id: 1, host: '10.0.0.134:28018'},
{_id: 2, host: '10.0.0.134:28019'}]
}
rs.initiate(config)
use test;
db.movies.insert([ { "title" : "Jaws", "year" : 1975, "imdb_rating" : 8.1 },{ "title" : "Batman", "year" : 1989, "imdb_rating" : 7.6 },
] );
现在新解决方法是通过编写后台程序MongoControlServer通过mongoc向mongo数据发送创建配置复制集命令。
MongoC编写Command接口
//头文件
class mongodb_api
{
public:
static mongodb_api& instance();
/*MongoDB数据库初始化*/
int mongodb_init(const char* url);
/*清理数据库*/
int mongodb_cleanup();
int mongodb_do_command(const char* databasename, std::string command,std::string& replys);
private:
mongodb_api();
static mongodb_api* s_instance;
void* m_mongodb_ptr=nullptr;
};
class mango_db
{
public:
int mongodb_init(const char* url);
int create_client_pool();
int destory_client_pool();
//mongodb有一系列的自有的命令,包括管理类命令、地理信息命令等
int do_command(const char*databasename, const bson_t *command, bson_t &reply);
private:
int m_ulthreads = 10;
void * m_pool=nullptr;
void * m_url = nullptr;
std::string m_strurl;
};
//mongoc的接口用于与mongo通信
#include <mongoc.h>
mongodb_api* mongodb_api::s_instance = nullptr;
mongodb_api& mongodb_api::instance()
{
if (s_instance == nullptr)
{
s_instance = new mongodb_api;
}
return *s_instance;
}
int mango_db::mongodb_init(const char* url)
{
int ulret = 0;
m_strurl = url;
mongoc_init();
return ulret;
}
int mongodb_api::mongodb_cleanup()
{
int ulret = 0;
mango_db* dbapi = static_cast<h3c_cloud_mango_db*>(m_mongodb_ptr);
if (dbapi == nullptr){ return ulret;}
dbapi->destory_client_pool();
}
int mango_db::create_client_pool()
{
int ulret = 0;
mongoc_client_pool_t * client_pool=nullptr;
mongoc_uri_t *uri=nullptr;
uri = mongoc_uri_new(m_strurl.c_str());//url指定ip地址,没有指定
client_pool = mongoc_client_pool_new(uri);
m_pool = static_cast<void*>(client_pool);
m_url = static_cast<void*>(uri);
return ulret;
}
int mango_db::destory_client_pool()
{
int ulret = ERROR_COMMON_SUCCEED;
if (m_url == nullptr || m_pool == nullptr)
{
return 1;
}
mongoc_client_pool_destroy(static_cast<mongoc_client_pool_t*>(m_pool));
mongoc_uri_destroy(static_cast<mongoc_uri_t*>(m_url));
mongoc_cleanup();
return ulret;
}
int mongodb_api::mongodb_do_command(const char* databasename, std::string command, std::string& replys)
{
int ulret = 0;
mango_db* dbapi = static_cast<mango_db*>(m_mongodb_ptr);
if (dbapi == nullptr){ return ERROR_COMMON_FALT; }
bson_error_t errorinfo;
bson_t reply;
bson_t* cond = bson_new_from_json((const unsigned char*)command.c_str(), command.length(), &errorinfo);
ulret = dbapi->do_command(databasename, cond, reply);
char *condStr = bson_as_json(&reply, NULL);
replys = condStr;
bson_free(condStr);
bson_destroy(&reply);
return ulret;
}
int mango_db::do_command(const char*databasename,const bson_t *command, bson_t &reply)
{
int ulret = 0;
mongoc_client_pool_t *pool = static_cast<mongoc_client_pool_t*>(m_pool);
mongoc_client_t *client;
bson_error_t error;
client = mongoc_client_pool_pop(pool);//从连接池中获取连接对象
if (client == nullptr){
H3C_CLOUD_MONGODB_LOG1(H3C_LOG_ERROR, "fail get client ptr url:[%s] database name:[%s]", databasename);
return 1;
}
//删除指定的行
if (!mongoc_client_command_simple(client, databasename, command, NULL, &reply, &error))
{
char *commandStr = bson_as_json(command, NULL);
H3C_CLOUD_MONGODB_LOG4(H3C_LOG_ERROR, "fail do command url:[%s] database name:[%s] command [%s] error [%s]", m_strurl.c_str(), databasename, commandStr, error.message);
bson_free(commandStr);
mongoc_client_pool_push(pool, client);
return 1;
}
mongoc_client_pool_push(pool, client);
return 0;
}
通过MongoC编写复制集的配置
以下是编写的测试代码,用于添加复制集节点。生产环境下可以编写一个后台程序自动检测mongo后台服务,自己检查mongo ip 自动生成**"{“replSetInitiate”:{"_id":“COOL”,“members”:[{"_id":0,“host”:“10.90.15.198:27017”},{"_id":1,“host”:“10.90.15.199:27017”},{"_id":2,“arbiterOnly”:true,“host”:“10.90.15.200:27017”}]}}"**; 配置文件,可以实现mongo数据库的自动更新,创建复制集(replSet)
//通过mongoc进行复制集配置(例子)
ULONG_32 h3c_cloud_manager_db::h3c_cloud_command()
{
ULONG_32 ulret = ERROR_COMMON_SUCCEED;
//检查复制集
std::string command = "{\"replSetGetStatus\":1}";
std::string reply;
ulret = h3c_cloud_mongodb_api::instance().mongodb_do_command("admin", command,reply);
if (ulret != ERROR_COMMON_SUCCEED){
H3C_CLOUD_MAN_LOG2(H3C_LOG_ERROR, "fail create json info [%s] [%s]", command.c_str(),reply.c_str());
}
//添加复制节点
std::string command = "{\"replSetInitiate\":{\"_id\":\"COOL\",\"members\":[{\"_id\":0,\"host\":\"10.90.15.198:27017\"},{\"_id\":1,\"host\":\"10.90.15.199:27017\"},{\"_id\":2,\"arbiterOnly\":true,\"host\":\"10.90.15.200:27017\"}]}}";
std::string reply;
ulret = h3c_cloud_mongodb_api::instance().mongodb_do_command("admin", command, reply);
if (ulret != ERROR_COMMON_SUCCEED){
H3C_CLOUD_MAN_LOG2(H3C_LOG_ERROR, "fail create json info [%s] [%s]", command.c_str(), reply1.c_str());
}
//再次检查
command = "{\"replSetGetStatus\":1}";
reply;
ulret = h3c_cloud_mongodb_api::instance().mongodb_do_command("admin", command, reply);
if (ulret != ERROR_COMMON_SUCCEED){
H3C_CLOUD_MAN_LOG2(H3C_LOG_ERROR, "fail create json info [%s] [%s]", command.c_str(), reply2.c_str());
}
return ulret;
}
#上面测试接口三个命令返回的参数
{ "info" : "run rs.initiate(...) if not yet done for the set", "ok" : 0.0, "errmsg" : "no replset config has been received", "code" : 94, "codeName" : "NotYetInitialized" }
{ "ok" : 1.0 }
{ "set" : "COOL", "date" : { "$date" : 1573528438228 }, "myState" : 2, "term" : 0, "heartbeatIntervalMillis" : 2000, "optimes" : { "lastCommittedOpTime" : { "ts" : { "$timestamp" : { "t" : 0, "i" : 0 } }, "t" : -1 }, "appliedOpTime" : { "ts" : { "$timestamp" : { "t" : 1573528434, "i" : 1 } }, "t" : -1 }, "durableOpTime" : { "ts" : { "$timestamp" : { "t" : 1573528434, "i" : 1 } }, "t" : -1 } }, "members" : [ { "_id" : 0, "name" : "10.90.15.198:27017", "health" : 1.0, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 73, "optime" : { "ts" : { "$timestamp" : { "t" : 1573528434, "i" : 1 } }, "t" : -1 }, "optimeDate" : { "$date" : 1573528434000 }, "infoMessage" : "could not find member to sync from", "configVersion" : 1, "self" : true }, { "_id" : 1, "name" : "10.90.15.199:27017", "health" : 1.0, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 4, "optime" : { "ts" : { "$timestamp" : { "t" : 1573528434, "i" : 1 } }, "t" : -1 }, "optimeDurable" : { "ts" : { "$timestamp" : { "t" : 1573528434, "i" : 1 } }, "t" : -1 }, "optimeDate" : { "$date" : 1573528434000 }, "optimeDurableDate" : { "$date" : 1573528434000 }, "lastHeartbeat" : { "$date" : 1573528438080 }, "lastHeartbeatRecv" : { "$date" : 1573528437780 }, "pingMs" : 1, "configVersion" : 1 }, { "_id" : 2, "name" : "10.90.15.200:27017", "health" : 1.0, "state" : 7, "stateStr" : "ARBITER", "uptime" : 4, "lastHeartbeat" : { "$date" : 1573528438080 }, "lastHeartbeatRecv" : { "$date" : 1573528438173 }, "pingMs" : 0, "configVersion" : 1 } ], "ok" : 1.0 }
注:接口配置的详细参数
//std::string command 的详细配置-->用于这个命令的cfg参数{\"replSetInitiate\":\"cfg\"}
{
"_id" : "COOL",
"version" : 1,
"protocolVersion" : NumberLong(1),
"members" : [
{
"_id" : 0,
"host" : "10.90.15.198:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 1,
"host" : "10.90.15.199:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 2,
"host" : "10.90.15.200:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
}
],
}
mongodb.conf配置文件
#mongodb.conf mongo数据库配置文件
# 是否启用认证
auth= true
# 集群的私钥的完整路径,只对于Replica Set 架构有效(noauth = true时不用配置此项)
#在一台服务器上生成私钥
# openssl rand -base64 745 > mongodb-keyfile
#修改私钥的权限为可读写
#chmod 600 mongodb-keyfile
#将私钥拷贝到其余的服务器上
#scp mongodb-keyfile root@xxx.xxx.xxx.xxx:/xxxx/configdb
keyFile = /data/configdb/mongodb-keyfile
# 设置oplog的大小(MB)
oplogSize=2048
# 设置副本集名称
replSet=COOL
# 绑定ip
bind_ip = 0.0.0.0
# 监听端口
port=27017
mongo docker-compose 模板文件,这里使用docker 安装mongo
# Use root/example as user/password credentials
version: '3.1'
services:
mongo:
image: mongo
restart: always
privileged: true
ports:
- 27017:27017
volumes:
- ../data:/data/db
- ../config:/data/configdb
command: mongod -maxConns=4000 --config /data/configdb/mongodb.conf
mongo-express:
image: mongo-express
networks:
#- default
- cloudface_net
restart: always
ports:
- 27109:8081