4、mongoDB副本集
冗余和数据可用性
复制提供冗余并增加数据可用性。在不同数据库服务器上具有多个数据副本时,复制提供了一个级别的容错性,从而避免了单个数据库服务器的丢失;
在某些情况下,复制可以提供增加读取效率,因为客户端可以向不同的服务器发送读取操作。维护不同数据中心的数据副本可以增加分布式应用程序的数据位置和可用性。我们还可以为了专用的目的维护其他副本,例如灾难恢复,报告或备份。
MongoDB中的复制
副本集是MongoDB保持相同数据集的一组实例。副本集包含几个数据承载节点和可选的一个仲裁节点。在数据中心,只有一个成员是主节点,其他节点是次节点
主节点接收所有的读写操作,一个副本集只有一个主节点,尽管某些情况下,另一MongoDB实例可能会短暂地认为自己也是主,主节点对数据集的所有更改记录在oplog日志中
次节点复制主的oplog并将操作应用于数据集,这样次节点的数据集就和主机点一致。如果主节点不可用,那么合格的次节点就进行一次选举,选择出新的主节点
我们可以添加一个额外的MongoDB实例作为仲裁者。仲裁者不存储数据集。仲裁者的目的是通过响应其他成员的心跳和选举请求。如果副本集的成员是偶数个,添加一个仲裁者可以是的获得多数选票的次节点成为主节点,仲裁者永远是仲裁者,主节点可能会成为次节点,次节点可能在选举中成为主节点的候选,注意:不要在主节点或次节点的系统上运行仲裁器
异步复制
次节点应用主节点的异步操作,通过主节点的应用操作后,即使一个或多个成员发生故障,也可以继续运行
自动故障切换
当主节点不与该组其他成员交流超过10秒时,一个合格的次节点将被选举为新的主节点(获得多数选票的次节点),故障转移通常在1分钟内完成
读操作
默认情况下,客户端从主节点读取,客户端可以指定读取首选项,以便将读操作发送到次节点,对次节点的异步复制意味着来自次节点的读取可能不是主节点状态的数据
优先级0副本集成员
优先级为0 的成员不能被选为主节点,一个优先级为0 的成员作为次节点维护数据集副本,接受读取操作,并在选举中投票。配置优先级为0的成员以防止其为主节点
隐藏副本集成员
隐藏的成员维护主节点的副本,但客户端应用程序不可见。隐藏的成员必须始终是优先级0的成员,因此不能成为主节点,db.isMater()方法不显示隐藏的成员。然后隐藏的成员可以在选举中投票。客户端不会将读取操作发给隐藏成员。因此,除了基本复制外,这些成员不会接收到流量。使用隐藏的成员进行专门的任务,如报告和备份。
延迟副本集成员
延迟成员包含数据集的副本,但是,延迟成员的数据集反映了该集合的较早或延迟的状态。由于延迟成员是数据集的滚动备份或正在运行的历史快照,因此可能帮助我们从各种任务错误中恢复。
注意:延迟成员必须优先级为0,防止成为主节点,应该是隐藏成员,防止应用程序查询
OPLOG
Oplog(操作日志)是一个特殊的上限集合,它将修改存储在数据库中的数据的所有操作记录,MongoDB在主节点上应用数据库操作,然后在主节点的oplog上记录操作,次节点然后复制并异步处理应用这些操作。所有副本集成员都包含local.oplog.rs集合中oplog的副本,允许它们维护数据库的当前状态。
为了方便复制,所有副本集成员向其他所欲成员发送心跳(ping),任何成员都可以从任何其他成员导入oplog条目
当首次启动副本成员时,MongoDB会创建一个默认大小的oplog,默认的大小取决于存储引擎
在大多数情况下,默认的oplog大小就足够用了
在mongod创建oplog之前,我们可以使用opologSizeMB选项指定其大小
禁用访问控制运行的三个现有实例中 创建三个成员副本集
概述
三个成员的副本集提供足够的冗余,以维持大多数的网络分区和其他故障。这些集合对于许多分布式读取操作也具有足够的容量,副本应该始终有奇数个成员。这样可以使选举顺利进行
要求:
对于生产部署,我们应该将mongod实例运行在不同的计算机上来保持成员之前尽可能多的隔离;
在部署副本集之前,我们必须将成为副本集的每个系统上安装MongoDB
在创建副本集之前,确保所有成员之间的网络可以进行通信
注意事项
尽量使用标准端口27017
配置访问控制以防止从未知客户端到副本集的连接
配置网络防护墙规则
确保副本集的每个成员可通过解析的DNS或主机名的方式访问
-----------------------------------------------------------------------------
主机名 ip
-----------------------------------------------------------------------------
c1.heboan.com 192.168.88.1
-----------------------------------------------------------------------------
c2.heboan.com 192.168.88.2
--------------------------------------------------------全部绑定hosts
c3.heboan.com 192.168.88.3
-----------------------------------------------------------------------------
在以上3台机器上安装mongoDB,以下是安装脚本
安装包在/data/tools
监听地址需要加上各自的IP,其他都一样
#! /bin/bash # create run mongodb user groupadd mongo useradd -g mongo mongo # install mkdir /application cd /data/tools tar zxf mongodb-linux-x86_64-rhel70-3.4.5.tgz -C /application/ cd /application ln -s mongodb-linux-x86_64-rhel70-3.4.5 mongodb mkdir mongodb/conf mkdir mongodb/log mkdir mongodb/pid # create config file cat >/application/mongodb/conf/mongod.conf<<EOF systemLog: destination: file logAppend: true path: /application/mongodb/log/mongod.log storage: dbPath: /data/mongodb_data journal: enabled: true processManagement: fork: true pidFilePath: /application/mongodb/pid/mongod.pid replication: #配置副本集 replSetName: "rs0" #副本集名称设置为"rs0" net: port: 27017 bindIp: 127.0.0.1 EOF chown -R mongo.mongo mongodb-linux-x86_64-rhel70-3.4.5 chown -R mongo.mongo mongodb mkdir /data/mongodb_data -p chown -R mongo.mongo /data/mongodb_data cat >/etc/profile.d/mongodb.sh<<EOF export PATH=/application/mongodb/bin:$PATH EOF source /etc/profile.d/mongodb.sh
这里我们把c1.heboan.com(192.168.88.1)作为主节点
进入c1.heboan.com上的mongodb shell执行命令
rs.initiate( { _id : "rs0", members: [ { _id : 0, host : "c1.heboan.com:27017" } ] })
执行完之后我们发现,变成了这样的
rs0:PRIMARY>
我们执行rs.conf()可以显示副本集对象
rs0:PRIMARY> rs.conf()
把c2.heboan.com,c3.heboan.com添加到副本集
rs0:PRIMARY> rs.add("c2.heboan.com") rs0:PRIMARY> rs.add("c3.heboan.com")
执行rs.status()可以检查副本集的状态
rs0:PRIMARY> rs.status()
然后我们进入c2.heboan.com,c3.heboan.com上的mongodb shell发现
rs0:SECONDARY> #这表明他们是次节点
默认情况下,次节点是无法进行读操作的,我们来试下:
插入一条数据 rs0:PRIMARY> use test switched to db test rs0:PRIMARY> db.person.insert({"name":"heboan", "age":26}) WriteResult({ "nInserted" : 1 }) 然后我们在其中一台主节点来查询读取 rs0:SECONDARY> db.test.find() Error: error: { "ok" : 0, "errmsg" : "not master and slaveOk=false", "code" : 13435, "codeName" : "NotMasterNoSlaveOk" } 默认情况下读写的操作都是在主节点,如果想然后客户端读取次节点,也是可以的,可以通过修改读取首选项做到 但是官方非常不建议这样做,理由如下: 1、副本的所有成员具有大致相当的写入流量;因此次节点的读取速度与主节点的读取速度大致相同 2、复制是异步的,并且在成功的写入操作与其复制到次节点之前有一些延迟 3、如果集合中的任何成员变得不可用,则将其读取操作分发可能会损害可用性 4、对于分片集合的查询,对于平衡器活动的集群,由于不完整或已终止的组块迁移,辅助节点 可能会丢失或重复的数据返回陈旧的结果 官方建议通过【分片】在一组计算机上分发读取和写入操作来增加读写能力,并且通常是增加容量的更好的策略
对现有副本集执行密钥文件访问控制
执行以下过程需要停机
1、创建密钥文件
openssl rand -base64 756 > <path-to-keyfile> chmod 400 <path-to-keyfile>
2、将密钥文件复制到每个副本集成员
将密钥文件复制到托管副本集成员的每个服务器。为每个服务器使用一致的位置
确保运行mongod实例的用户可以访问密钥文件
3、关闭副本集的所有成员
关闭mongod副本集中的每一个,从次节点开始。然后继续,直到副本集的所有成员都离线,包括仲裁者。主节点必须是最后关闭,以避免潜在的回滚成员 连接到mongo shell执行关闭 use admin db.shutdownServer()
4、修改配置文件,然后启动
security: keyFile: <path-to-keyfile> replication: replSetName: <replicaSetName>
5、通过localhost接口将mongo shell
6、创建用户管理员(主节点)
以下示例创建fred具有 数据库userAdminAnyDatabase角色的用户heboan admin = db.getSiblingDB("admin") admin.createUser( { user: "heboan", pwd: "123.com", roles: [ { role: "userAdminAnyDatabase", db: "admin" } ] } )
7、认证为用户管理员
方法一:在mongo shell中认证 db.getSiblingDB("admin").auth("heboan", "123.com" ) 方法二:连接的时候加参数 mongo -u "heboan" -p "123.com" --authenticationDatabase "admin"
8、创建集群管理员(可选)
集群管理员用户具有clusterAdmin角色,它允许对复制操作的访问 创建集群管理员用户并clusterAdmin在admin数据库中分配 角色 db.getSiblingDB("admin").createUser( { "user" : "ravi", "pwd" : "changeme2", roles: [ { "role" : "clusterAdmin", "db" : "admin" } ] } )
9、创建其他用户(可选)
创建用户以允许客户端连接并与副本集进行交互 比如创建一个用户(sellsa),为数据库love授权read write rs0:PRIMARY> use admin rs0:PRIMARY> db.auth("heboan", "123.com") rs0:PRIMARY> use love switched to db love rs0:PRIMARY> db.createUser( ... { ... user: "sellsa", ... pwd: "123.com", ... roles: [ {role: "readWrite", db: "love"} ] ... } ... )