上一篇中介绍了mongo的基本使用。本篇将继续介绍mongo集群。
Mongodb的集群搭建方式主要有三种,主从模式,Replica set模式,sharding模式。其中副本集模式Replica set应用最为广泛,主从模式使用较少,sharding模式即分片存储,配置较为复杂。
Replica Set即副本集方式主要有两个目的,一个是数据冗余做故障恢复使用,当发生硬件故障或其他原因造成的宕机时,可以使用副本进行恢复。另一个是读写分离,读请求分流到副本上,减轻主库的读压力。
Replica Set是mongod的实例集合,有相同的数据内容。其中包含三类角色:
(1)主节点(Primary)
主节点接收所有写请求,并将修改同步到所有从节点。当主节点挂掉后,其他从节点和仲裁者会重新选举出一个主节点。默认读请求也是发到主节点处理的,如果要转发到从节点需要修改连接配置。
(2)从节点(Secondary)
与主节点保持同样的数据集。当主节点挂掉时,参与选举。
(3)仲裁者(Arbiter)
不保有数据,不参与选举,只进行选举投票。
集群搭建
分别以副本集方式启动三台服务器(其中副本集名称应相同):
mongod --port 27017 --dbpath /data/db --replSet mserver (不指定其他参数情况下均使用默认配置参数)
mongod --port 27018 --dbpath /data/db2 --replSet mserver
mongod --port 27019 --dbpath /data/db3 --replSet mserver
不同版本的启动参数略有不同。每个服务节点均要使用自己的数据文件。
连接上默认服务器,即端口为27017的:
./mongo --host 127.0.0.1 --port 27017
此时执行任何操作都会提示:not master and slaveOk=false。需要先进行初始化:
rs.initiate()
初始化后查看服务器状态:
rs.status()
可看到”stateStr”: “PRIMARY”,说明此服务器为主服务器。
接下来,在此服务器中添加副本集:
rs.add('127.0.0.1:27018')
rs.add('127.0.0.1:27019')
完成后,就生成了mongodb副本集了。其中一台为主节点,两台为从节点。通过rs.status()可以查看状态。
如果添加副本集的时候,使用
rs.addArb("ip:port")
则可以将该节点设置为仲裁节点。
以配置方式启动
在实际生产上,一般通过配置文件的方式来启动mongo集群。默认的mongo配置文件为:mongod.conf。假设现在有一个目录mongo_conf,用于存放不同节点的配置文件。其中,端口号为27017的mongo配置文件~/mongo_conf/mongo_27017/mongod.conf修改以下几个点:
dbPath: /data/db1 # 数据库文件地址
port: 27017 # 端口号
path: ~/mongo_conf/mongo_27017.log # 日志文件
在processManagement节点下,新增一行:fork: true
,表示以fork方式来开启进程。
打开replication节点,设置复制集名称:
replSetName: mserver
同理,修改端口号为27018和27019的mongo节点配置文件。
修改完成后,启动mongo集群的方式如下:
mongod -f ~/mongo_conf/mongo_27017/mongod.conf
mongod -f ~/mongo_conf/mongo_27018/mongod.conf
mongod -f ~/mongo_conf/mongo_27018/mongod.conf
登录主节点通过rs.status()查看集群状态,可以看到27017端口的节点为PRIMARY,另外两个节点为SENCODARY。这是因为最开始配置集群节点角色时,通过add方法添加了从节点,而没有添加仲裁者节点。事实上,当副本集节点个数为奇数节点时,仲裁者节点不是必须的。节点数为偶数时,则需要仲裁者节点。仲裁者节点不存储数据,不需要太好的硬件条件,其作用仅仅在于当选举出现平票时,参与其中选出一个新的主节点。
如果通过rs.status()查看发现集群状态无效,提示:“Our replica set config is invalid or we are not a member of it”, 这是因为前面设置集群所用的配置文件和当前的配置文件不一样所致。可以先通过原来的方式启动mongo服务,然后通过:
use local
db.dropDatabase()
来删除副本集配置。此时再以fork方式启动mongo服务,登录主节点执行以下命令:
config = { _id:"mserver", members:[ {_id:0,host:"127.0.0.1:27017"}]}
rs.initiate(config)
rs.add('127.0.0.1:27018')
rs.add('127.0.0.1:27019')
就可以重新设置新的副本集了。
现在kill掉主节点进程,会发现剩下的两台从节点中,有一个变成了主节点。查看新的主节点日志:
可以看出,经过选举,27019这个节点竞选成功,变成了新的主节点。
此时,集群中27107这个节点状态是挂掉的:
重新开启27017节点的mongo服务,此时27017变成了新的SECONDARY节点。
python访问mongo集群
在上一篇blog中介绍过mongo单机环境的使用,这里介绍在集群环境下使用。同样需要引入pymongo库,版本为:3.5.1。
先通过pymongo库的MongoClient连接上mongoDB:
import pymongo
import settings
client = pymongo.MongoClient
mongo_mytest = client(settings.get('mongo_mytest', 'host'),
replicaSet=settings.get('mongo_mytest', 'replica'),
read_preference=pymongo.read_preferences.ReadPreference.SECONDARY_PREFERRED,
maxPoolSize=3,
w=2)
mongo_mytest_primary = client(settings.get('mongo_mytest', 'host'),
replicaSet=settings.get('mongo_mytest', 'replica'),
read_preference=pymongo.read_preferences.ReadPreference.PRIMARY,
maxPoolSize=3,
w=2)
与单机环境不同的是,这里传入的host是集群的全部host:
[mongo_mytest]
host = mongodb://127.0.0.1:27017,127.0.0.1:27018,127.0.0.1:27019
replica = mserver
创建好连接mongo的客户端client后,使用方式与单机环境client使用方式一致。如:
from base.mongo_base import mongo_mytest
collection = mongo_mytest.mytest['person']
collection.insert_one({"_id": 2})
data = collection.find()
for d in data:
print d
Read Preference参数
注意到在上文创建mongo客户端时创建了两个,一个是mongo_mytest,一个是mongo_mytest_primary。两者创建时唯一不同的是read_preference参数。
MongoDB提供5种Read Preference Mode:
不写则默认为PRIMARY模式,只路由到主节点。PRIMARY_PREFERRED优先路由到主节点,主节点不可用时则路由到从节点。SECONDARY和SECONDARY_PREFERRED则是路由到从节点和优先路由到从节点。NEAREST从延时最小的节点读取数据,不管是PRIMARY还是SECONDARY,对于分布式应用且MongoDB是多数据中心部署的,NEARSET能保证最好的data locality。
不同的Read Preference Mode适合不同的应用场景,如果数据的一致性很重要,把么就需要从PRIMARY读,因为从节点的数据有一定的延迟。如果能接收这点延迟,则从SECONDARY读数据可以减轻主节点的压力。如果对延时敏感,则可用NEAREST模式。
开启登录密码验证
上文的集群环境未开启登录密码,存在这一定的安全隐患。
可以通过keyfile文件来让副本集成员互相认证。生成keyfile:
openssl rand -base64 741 > ~/mongo_conf/mongo-keyfile
chmod 400 ~/mongo_conf/mongo-keyfile # 权限要小一点,如400和600都可以
在开启密码登录之前,先创建管理员账号。
登录到mongo主节点,切换到admin库。创建超级用户:
db.createUser({
user:"root",
pwd:"root",
roles: [ { role: "root",db:"admin"}]
})
接下来,在mongo节点的配置文件中开启密码登录。添加security节点:
#security Options
security:
authorization: 'enabled'
keyFile: ~/mongo_conf/mongo-keyfile
# transitionToAuth: true # 如果开启,则无需密码登录
clusterAuthMode: "keyFile"
本文中有3个节点,都需要设置,认证文件使用同一个。
启动mongo集群。此时不指定用户名和密码的情况下就无法登录了。需要指定用户名和密码才可以:
mongo 127.0.0.1:27017 -uroot -proot -authenticationDatabase admin
如果在已经开启密码登录的情况下忘记了用户名和密码,可以设置
# transitionToAuth: true # 如果开启,则无需密码登录
以此配置方式启动mongoDB,用空密码登录root账号, 在admin库中通过show users查看账户。