配置mongodb复制集Replica Set详解

一、MongoDB入门

1.1 简介

  MongoDB是一个开源的,基于分布式的,面向文档存储的非关系型数据库。是非关系型数据库当中功能最丰富、最像关系数据库的。
  MongoDB由C++编写,其名字来源于”humongous”这个单词,其宗旨在于处理大量数据。
  MongoDB可以运行在Windows、unix、OSX、Solaris系统上,支持32位和64位应用,提供多种编程语言的驱动程序。
  MongoDB支持的数据结构非常松散,是类似json的BSON格式,通过键值对的形式存储数据,可以存储复杂的数据类型。
  MongoDB支持的数据类型有:null、boolean、String、objectId、32位整数、64位整数、64位浮点数、日期、正则表达式、js代码、二进制数据、数组、内嵌文档、最大值、最小值、未定义类型。
  MongoDB最大的特点是他支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。

1.2 Mongo的五大特性

1.2.1丰富的数据模型

  MongoDB是面向文档的数据库,不是关系型数据库.放弃关系模型的主要原因就是为了获得更加方便的扩展性,还有其他的好处.
  基本思路就是将原来”行”(row)的观念转化为更加灵活的”文档”(document)模型.面向文档的方式可以将文档或者数组内嵌进来,所以可以用一条记录表示非常复杂的层次关系.
  MongoDB没有模式:文档的键不会事先定义也不会固定不变.由于没有模式需要更改,通常不需要迁移大量数据,不比将所有数据都放在一个模子里面,应用层可以处理新增或者丢失的键

1.2.2容易扩展

  应用数据集的大小增长很快.传感器技术的发展,带宽的增加,连接internet手持设备的普及使得当下即便是很小的应用也要存储大量的数据,量大到数据库处理困难.T级别的数据库已司空见惯.
  由于开发者要存储的数据不断增长,就会面临选择:是升级数据库(买台更好的服务器),还是扩展数据库(将数据分散到很多的机器上).通常升级数据库是最省力气的做法,但价格不菲.但是扩展不但经济而且还能持续增加:想要增加存储空间或者提升性能,只需要买台一般的服务器加入到集群中.
  MongoDB最初的设计就考虑了扩展的问题,它所采用的面向文档的数据模型使其可以自动在多台服务器间分割数据.它还可以平衡集群的数据和负载,自动重排文档.这样开发者就可以专注于编写应用,而不是考虑如何扩展.要是需要更大的容量,只需在集群中添加新机器,然后让数据库来处理剩下的事.

1.2.3丰富的功能

  • 索引
      MongoDB支持通用辅助索引,能进行多种快速查询,也提供唯一的,复合的和地理空间索引能力
  • 存储JavaScript
      开发人员不必使用存储过程,可以直接在服务端存取JavaScript函数,值
  • 聚合
      MongoDB支持MapReduce和其他聚合工具
  • 固定集合
      集合的大小是有上限的,这对某些类型的数据(如日志)特别有用
  • 文件存储
      MongoDB支持用一种容易使用的协议存储大型文件和文件的元数据
      有些关系型数据库的常见功能,MongoDB不具备,如:join和复杂的多行事务.
      这个架构上考虑是为了提高扩展性,因为这两个功能实在很难在一个分布式系统上实现.

1.2.4高性能

  MongoDB使用MongoDB传输协议作为与服务器交互的主要方式(与之对应的协议需要更多的开销,如:http/Rest).
  它对文档进行动态填充,预分配数据文件,用空间换取性能的稳定.默认的存储引擎中使用了内存映射文件,将内存管理工作
  交给操作系统去处理.动态查询优化器会”记住”执行查询最高效的方式.
  虽然MongoDB功能强大,尽量保持关系型数据库的众多特性,它尽可能的将服务器处理逻辑交给客户端(由驱动程序或者用户的应用程序处理).这样精简的设计是的MongoDB获得了非常好的性能.

1.2.5简便的管理

  MongoDB尽量让服务器自治来简化数据库的管理,处理启动数据库服务器之外,几乎没有什么必要的管理操作.如果主服务器挂掉了,MongoDB会自动切换到备份服务器上,并且将备份服务器升级为活跃服务器.在分布式环境下,集群只需要知道有新增的节点,就会自动集成和配置新节点.
  MongoDB的管理理念就是尽可能的让服务器自动配置,让用户在需要的时候调整设置.
  MongoDB的愿景是对自身更好的诠释–建立一个灵活,高效,易于扩展,功能完备的数据库

1.3Mongo的集群方式

1.3.1Master-slave方式

这个是最简答的集群方式,不过准确说也不能算是集群,只能说是主备。并且官方已经不推荐这种方式,所以在这里只是简单的介绍下吧,搭建方式也相对简单,这里就不详细介绍了,如想了解,请看master-salve

1.3.2 replca set

复制集的成员

在MongoDB中一个复制集是一个mongod进程的一个组,其提供了冗余和高可用,复制集的成员是primary,secondary和Arbiter。

  • Primary
    Primary是复制集中接收写操作的唯一的成员,MongoDB接收写操作在primary然后记录操作到primary的oplog,secondary成员复制这个log然后追加到自己的数据集中。
    在下面三个成员的腹直肌中,primary接受所有的写操作,然后两个secondary复制oploog到自己的数据中。

    复制集中所有的成员都能接收读操作,然而默认情况下读操作也是在primary上执行。
    复制集至少有一个primary,如果当前的primary成为不可用,将会选举出一个新的primary。
  • secondary
    一个secondary维护着对primary数据集的复制工作,对于replicate数据,一个secondary复制primary上oplog的,通过asyncchronous到他自己的数据集中,一个复制集可以有一个或多个secondary。
    下面三个成员复制集有两个secondary成员,这两个secondary复制primary的oplog然后写数据到自己的数据集中。

    虽然客户端不能写数据到secondary中,但是客户端可以从secondary中读取数据。一个secondary可以成为primary,如果当前的primary是不可用的,复制及会发起一次投票选择一个secondary成为新的primary。
    特殊的secondary:
    正常情况下,复制集的Seconary会参与Primary选举(自身也可能会被选为Primary),并从Primary同步最新写入的数据,以保证与Primary存储相同的数据。
    Secondary可以提供读服务,增加Secondary节点可以提供复制集的读服务能力,同时提升复制集的可用性。另外,Mongodb支持对复制集的Secondary节点进行灵活的配置,以适应多种场景的需求。
  • Arbiter
    Arbiter不复制primary,也不会成为一个primary。复制集可能需要有Arbiter来实现对primary的投票选举。Arbiter有着1票正确的选举权,因为复制集需要有奇数个成员来作为进行投票选举,注意:不要在一个已经有primary或者secondary上去run一个arbiter。
    当复制集成员为偶数时,最好加入一个Arbiter节点,以提升复制集可用性。这个设置影响选举,后面会对如何添加部署arbiter进行说明。
  • Priority0
    Priority0节点的选举优先级为0,不会被选举为Primary
    比如你跨机房A、B部署了一个复制集,并且想指定Primary必须在A机房,这时可以将B机房的复制集成员Priority设置为0,这样Primary就一定会是A机房的成员。(注意:如果这样部署,最好将『大多数』节点部署在A机房,否则网络分区时可能无法选出Primary)
  • Vote0
    Mongodb 3.0里,复制集成员最多50个,参与Primary选举投票的成员最多7个,其他成员(Vote0)的vote属性必须设置为0,即不参与投票。
  • Hidden
    Hidden节点不能被选为主(Priority为0),并且对Driver不可见。
    因Hidden节点不会接受Driver的请求,可使用Hidden节点做一些数据备份、离线计算的任务,不会影响复制集的服务。
  • Delayed
    Delayed节点必须是Hidden节点,并且其数据落后与Primary一段时间(可配置,比如1个小时)。
    因Delayed节点的数据比Primary落后一段时间,当错误或者无效的数据写入Primary时,可通过Delayed节点的数据来恢复到之前的时间点。

replica set的oplog

Oplog是一个滚动记录数据库中所有指定数据的封闭的收集日志,MongoDB接收数据库操作在primary上然后记录操作到primary的oplog中,secondary成员复制并且执行操作通过asynchronous进程。所有的复制及成员包含了一个oplog的复制在local.oplog.rs收集中,允许他们维护当前数据库的状态。
为了存进复制,所有的复制及成员发送心跳给其他所有成员,任何一个成员能够导入其他成员的oplog。

  • Oplog size
    当你第一次启动一个复制集的时候,MongoDB会创建一个默认的oplog大小。

    默认的oplog大小是足够的,就给例子,如果oplog是剩余磁盘空间的5%,并且在24小时内的操作写满了,然后secondary就要停止从oplog复制,并且不会重复复制24小时内的陈旧数据。然而,大多数复制集合有较低的操作卷,他们的oplogs可以拥有非常高的操作。
    如果你预测你的复制集想下列情况,你可能需要创建oplog成为一个比默认值更大的数字。相反的,如果你的应用主要是读操作比较少的写操作,你可以设置oplpog为一个比较小的值。下列情况,你需要设置oplog为一个更大的值:
  • 查看oplog的状态
    使用下面的命令,可以查看oplog状态,包含大小,操作的时间范围。
  1. rs.printReplicationInfo()

Replica Set的Data Synchronization

为了维护分片数据集的最新copy,一个复制集的secondary成员或者replication都会数据同步其他的成员。MongoDB使用两个数据同步性的表格(initial)来对新成员植入所有数据集,并且持续复制接收改变写入到新成员的数据集中。

  • Initial Sync
    Initial Sync复制所有的数据从一个成员的复制集中达到另一个成员。这个成员可以使用Initial Sync当该成员没有数据的情况,例如新成员或者有数据的但是错过了一次历史复制的成员。
    具体方法如下图:

    init sync过程包含如下步骤
    1)T1时间,从Primary同步所有数据库的数据(local除外),通过listDatabases + listCollections + cloneCollection敏命令组合完成,假设T2时间完成所有操作。
    2)从Primary应用[T1-T2]时间段内的所有oplog,可能部分操作已经包含在步骤1,但由于oplog的幂等性,可重复应用。
    3)根据Primary各集合的index设置,在Secondary上为相应集合创建index。(每个集合_id的index已在步骤1中完成)。
    oplog集合的大小应根据DB规模及应用写入需求合理配置,配置得太大,会造成存储空间的浪费;配置得太小,可能造成Secondary的init sync一直无法成功。比如在步骤1里由于DB数据太多、并且oplog配置太小,导致oplog不足以存储[T1, T2]时间内的所有oplog,这就Secondary无法从Primary上同步完整的数据集。
  • Replication
    secondary成员可以在Initial Sync后开始复制,secondary成员从源地址复制oplog,然后通过asynchronous 进程执行这些操作,存储数据。
    大部分情况下,secondary是从primary来sync数据的。如果是基于ping时间和其他成员复制状态,secondary也可能自动的更改他们的源地址sync数据。
  • 多线程复制
    MongoDB applies write operations in batches using multiple threads to improve concurrency. MongoDB groups batches by namespace (MMAPv1) or by document id (WiredTiger) and simultaneously applies each group of operations using a different thread. MongoDB always applies write operations to a given document in their original write order.
    While applying a batch, MongoDB blocks all read operations. As a result, secondary read queries can never return data that reflect a state that never existed on the primary.

1.3.3分片Sharding

分片集群

一个完整个MongoDB分片集群有下面组件组成:

  • 每个分片包含了一个分片数据的子集,每个分片可能是作为一个复制及被部署。
  • mongos充当作为一个查询路由,在客户端应用和分片集群之间提供接口。
  • config servers为集群服务存储metadata和配置管理。在MongoDB3.2中config servers也可以使用replica set来部署.

分片keys

  • 对于分布式的集合,MongoDB分区集合使用分片keys。分片keys有一个或者多个不可变的域。其存在于每个目标集合。
  • 当你对一个集合分片时,你可以选择分片keys。在分片后,分片keys的选择就不能再改变了,一个分片的集合可以仅有一个分片keys。
  • 对于一个非空的集合,这个集合必须有一个分片keys开始的索引。对于一个空的集合,如果集合还没有一个适当的索引,MongoDB就会为在特定的分片keys创建一个索引。
  • 分片keys的选择会影响性能,效率和分片集群的可扩展性。通过分片keys的使用选择方式,最可能出现瓶颈的地方是硬件资源或者是基础设施。分片key的选择和他的backing索引也可能影响你集群所使用分片策略。

Chunks

  • MongoDB分区分片数据到chunks中,是基于分的片keys。
  • MongoDB迁移Chunk是通过在集群中使用分片集群平衡器。这个均衡器会在集群中尝试完成一个chunk之间的数据平衡。

分片的优势

  • 读or写
    MongoDB会在集群中分配读和写的任务,允许每个分片执行集群操作的一个子程序。读和写的任务可以通过在集群中加入更多的分片来进行水平扩展。
  • 存储策略
    分片分布式数据通过分片存储在集群中,每个分片包含统计群数据的一部分。随着数据量的增长,应有更多的分片增加集群的存储容量。

高可用

  • 当一个或者几个分片时不可用的情况。这个分片集群仍是可以进行读写操作的。downtime期间,不可用分片上的数据部分是不可以被访问的,读和写操作会定向到其他可用的分片上。、
  • MongoDB3.2版本允许你部署config servers作为复制集。配置了config server 复制集合分片集群可以继续操作读写只要大多数复制集是可用的。
  • 在生产环境中,单独的分片应该被部署成复制集,提供冗余性和可用性。

分片方式

二、复制集replica set部署环境准备

  • 三台机器

    注:关闭selinux,关闭iptables,使用replica set模式,Arbiter作为仲裁者
  • replica set图解
    正常工作状态primary接收读写操作,arbiter和secondary之间心跳,primary将操作写到oplogs,secondary复制primary的oplog,然后apply到自己的数据库中
  • 新primary切换图解
    当一个primary挂掉,会投票选择secondary为新的primary记性工作,arbiter在这里作为仲裁者时刻准备投票选举

三、replica set的部署

3.1学习mongod的配置文件

  • verbose
    日志信息冗余。默认false。提高内部报告标准输出或记录到logpath配置的日志文件中。要启用verbose或启用verbosity 用vvvv参数,如:
    1.verbose = true
    2.vvvv = true
    ps:启动verbose冗长信息,它的级别有 vv~vvvvv,v越多级别越高,在日志文件中记录的信息越详细。
  • port:端口
    默认27017,MongoDB的默认服务TCP端口,监听客户端连接。要是端口设置小于1024,比如1021,则需要root权限启动,不能用MongoDB帐号启动,(普通帐号即使是27017也起不来)否则报错:[mongo –port=1021 连接]
    1.ERROR: listen(): bind() failed errno:13 Permission denied for socket: 127.0.0.1:1021
  • bind_ip:绑定地址。
    默认127.0.0.1,只能通过本地连接。进程绑定和监听来自这个地址上的应用连接。要是需要给其他服务器连接,则需要注释掉这个或则把IP改成本机地址,如192.168.200.201[其他服务器用 mongo –host=192.168.200.201 连接] ,可以用一个逗号分隔的列表绑定多个IP地址。
  • maxConns:最大连接数。
    默认值:取决于系统(即的ulimit和文件描述符)限制。MongoDB中不会限制其自身的连接。当设置大于系统的限制,则无效,以系统限制为准。这对于客户端创建很多“表”,允许连接超时而不关闭“表”的时候很有用。设置该值的高于连接池和总连接数的大小,以防止尖峰时候的连接。注意:不能设置该值大于20000。
  • objcheck:强制验证客户端请求。
    2.4的默认设置为objcheck成为true,在早期版本objcheck默认为false。因为它强制验证客户端请求,确保客户端绝不插入无效文件到数据库中。对于嵌套文档的对象,会有一点性能影响。设置noobjcheck 关闭。
  • noobjcheck:同上,默认关闭false。
  • logpath:指定日志文件
    该文件将保存所有的日志记录、诊断信息。除非另有指定,mongod将所有的日志信息输出到标准输出。如果没有指定logappend,重启则日志会进行覆盖操作。
  • logappend:写日志的模式
    设置为true为追加。默认是覆盖。如果未指定此设置,启动时MongoDB的将覆盖现有的日志文件。
  • syslog:日志输出都发送到主机的syslog系统
    而不是标准输出到logpath指定日志文件。syslog和logpath不能一起用,会报错:
  • pidfilepath:进程ID
    没有指定则启动时候就没有PID文件。默认缺省。
  • keyFile:指定存储身份验证信息的密钥文件的路径。
  • nounixsocket:套接字文件
    默认为false,有生成socket文件。当设置为true时,不会生成socket文件。unixSocketPrefix:套接字文件路径,默认/tmp
  • fork:是否后台运行
    设置为true 启动 进程在后台运行的守护进程模式。默认false。
  • auth:用户认证,默认false。
    不需要认证。当设置为true时候,进入数据库需要auth验证,当数据库里没有用户,则不需要验证也可以操作。直到创建了第一个用户,之后操作都需要验证。比如:通过db.addUser(‘sa’,’sa’) 在admin库下面创建一个超级用户,只能在在admin库下面先认证完毕了:ab.auth(‘sa’,’sa’) ,才能去别的库操作,不能在其他库验证。这样连接数据库也需要指定库:
  • noauth:禁止用户认证,默认true。同上
  • cpu:设置为true会强制MongoDB每4s报告cpu利用率和io等待,把日志信息写到标准输出或日志文件。默认为false。
    开启日志会出现:
    1.Mon Jun 10 10:21:42.241 [snapshotthread] cpu: elapsed:4000 writelock: 0%
  • dbpath:数据存放目录。
  • diaglog:创建一个非常详细的故障排除和各种错误的诊断日志记录。
    默认0。设置为1,为在dbpath目录里生成一个diaglog.开头的日志文件,他的值如下:

3.2安装MongoDB

本文使用saltstack的安装MongoDB,具体数据库的replica set配置通过手动完成。有关saltstack的学习请移步自动化工具神器之SALTSTACK。本文saltstack的配置如下:

  • MongoDB的配置路径和相关文件
  1. [root@salt-master MongoDB]# tree
  2. .
  3. ├── files
  4. ├── MongoDB-linux-x86_64-rhel70-3.0.12.tar
  5. ├── 52devops_MongoDB.conf
  6. └── 52devops_MongoDB_keyfile
  7. └── 52devops_install.sls
  8. 1 directory, 4 files
  • 查看52devops_install.sls内容
  1. [root@salt-masterMongoDB]# cat 52devops_install.sls
  2. MongoDB-install:
  3. file.managed:
  4. - name: /usr/local/src/MongoDB-linux-x86_64-rhel70-3.0.12.tar
  5. - source: salt://MongoDB/files/MongoDB-linux-x86_64-rhel70-3.0.12.tar
  6. - user: root
  7. - group: root
  8. - mode: 644
  9. - backup: minion
  10. cmd.run:
  11. - name: cd /usr/local/src/ && tar xf MongoDB-linux-x86_64-rhel70-3.0.12.tar && mv MongoDB-linux-x86_64-rhel70-3.0.12 /usr/local/ && ln -sf /usr/local/MongoDB-linux-x86_64-rhel70-3.0.12 /usr/local/MongoDB && mkdir -p /data/bin/ && cp -a /usr/local/MongoDB-linux-x86_64-rhel70-3.0.12/bin/mongo /usr/bin/&& cp -a /usr/local/MongoDB-linux-x86_64-rhel70-3.0.12/bin/mongod /usr/bin/ && echo "never" > /sys/kernel/mm/transparent_hugepage/enabled && echo "never" > /sys/kernel/mm/transparent_hugepage/defrag
  12. - unless: test -d /usr/local/MongoDB-linux-x86_64-rhel70-3.0.12
  13. - require:
  14. - file: MongoDB-install
  15. vm.zone_reclaim_mode:
  16. sysctl.present:
  17. - value: 0
  18. MongoDB_bin_conf:
  19. file.managed:
  20. - name: /data/bin/devops.conf
  21. - source: salt://MongoDB/files/52devops_MongoDB.conf
  22. - user: root
  23. - group: root
  24. - mode: 644
  25. - backup: minion
  26. - template: jinja
  27. MongoDB_key_conf:
  28. file.managed:
  29. - name: /data/bin/52devops_MongoDB_keyfile
  30. - source: salt://MongoDB/files/52devops_MongoDB_keyfile
  31. - user: root
  32. - group: root
  33. - mode: 600
  34. - backup: minion
  • 查看启动配置文件
  1. [root@salt-master files]# cat 52devops_MongoDB.conf
  2. port=11111
  3. dbpath=/data/MongoDB-linux-x86_64-rhel70-3.0.12/52devops/{{pillar [ 'DIR' ]}} #提前写好pillar哦
  4. logpath=/data/MongoDB-linux-x86_64-rhel70-3.0.12/52devops/{{pillar [ 'DIR' ]}}/52devops.log
  5. logappend=true
  6. replSet=52devops
  7. fork=true
  8. auth=true
  9. keyFile=/data/bin/52devops_MongoDB_keyfile
  10. directoryperdb=true
  11. maxConns=8000
  12. cpu = true
  13. oplogSize = 8000
  • keyfile文件
    通过 openssl rand -base64 1024 > 52devops_MongoDB_keyfile生成
  • 执行saltstack高级状态highstate
    配置管理MongoDB,请使用salt的高级状态state.highstate完成部署,部署到三台节点机器。
  • 继续对MongoDB部署
    三台机器的本地配置
  1. [root@MongoDB-7 data]#
  2. mkdir /data/MongoDB-linux-x86_64-rhel70-3.0.12/52devops/r00 / -p
  3. [root@MongoDB-8 data]#
  4. mkdir /data/MongoDB-linux-x86_64-rhel70-3.0.12/52devops/r00 / -p
  5. [root@MongoDB-9 data]#
  6. mkdir /data/MongoDB-linux-x86_64-rhel70-3.0.12/52devops/r00 / -p
  • 启动三台MongoDB
  1. [root@MongoDB-7 bin]# pwd
  2. /data/bin
  3. [root@MongoDB-7 data]#
  4. mongod -f devops.conf
  5. [root@MongoDB-8 bin]# pwd
  6. /data/bin
  7. [root@MongoDB-8 data]#
  8. mongod -f devops.conf
  9. [root@MongoDB-7 bin]# pwd
  10. /data/bin
  11. [root@MongoDB-9 data]#
  12. mongod -f devops.conf

查看进程和端口启用情况

  1. [root@MongoDB-7 data]# ps -ef|grep mongo|grep -v grep
  2. root 15269 1 0 Aug15 ? 00:06:12 mongod -f devops.conf
  3. [root@MongoDB-7 data]# netstat -lntup|grep 11111
  4. tcp 0 0 0.0.0.0:11111 0.0.0.0:* LISTEN 15269/mongod
  5. [root@MongoDB-8 data]# ps -ef|grep mongo|grep -v grep
  6. root 15269 1 0 Aug15 ? 00:06:12 mongod -f devops.conf
  7. [root@MongoDB-8 data]# netstat -lntup|grep 11111
  8. tcp 0 0 0.0.0.0:11111 0.0.0.0:* LISTEN 15269/mongod
  9. [root@MongoDB-9 data]# ps -ef|grep mongo|grep -v grep
  10. root 15269 1 0 Aug15 ? 00:06:12 mongod -f devops.conf
  11. [root@MongoDB-9 data]# netstat -lntup|grep 11111
  12. tcp 0 0 0.0.0.0:11111 0.0.0.0:* LISTEN 15269/mongod
  • 在MongoDB-7上配置replica set的primary和secondary
    config replica set
  1. [root@MongoDB-7 bin]# mongo --port 11111
  2. config={_id : '52devops',members : [{_id : 0, host : '10.0.0.7:11111'},{_id : 1, host : '10.0.0.8:11111'}]}
  3. {
  4. "_id" : "52devops",
  5. "members" : [
  6. {
  7. "_id" : 0,
  8. "host" : "10.0.0.7:11111"
  9. },
  10. {
  11. "_id" : 1,
  12. "host" : "10.0.0.8:11111"
  13. }
  14. ]
  15. }

初始化replica set

  1. > rs.initiate(config)
  2. { "ok" : 1 }

查看replica状态,显示为10.0.0.7为primary,10.0.0.8位secondary

  1. 52devops:OTHER> rs.status()
  2. {
  3. "set" : "52devops",
  4. "date" : ISODate("2016-08-12T06:49:08.110Z"),
  5. "myState" : 1,
  6. "members" : [
  7. {
  8. "_id" : 0,
  9. "name" : "10.0.0.7:11111",
  10. "health" : 1,
  11. "state" : 1,
  12. "stateStr" : "PRIMARY", #角色为primary
  13. "uptime" : 2036,
  14. "optime" : Timestamp(1470984534, 1),
  15. "optimeDate" : ISODate("2016-08-12T06:48:54Z"),
  16. "electionTime" : Timestamp(1470984536, 1),
  17. "electionDate" : ISODate("2016-08-12T06:48:56Z"),
  18. "configVersion" : 1,
  19. "self" : true
  20. },
  21. {
  22. "_id" : 1,
  23. "name" : "10.0.0.8:11111",
  24. "health" : 1,
  25. "state" : 2,
  26. "stateStr" : "SECONDARY", #角色为secondary
  27. "uptime" : 14,
  28. "optime" : Timestamp(1470984534, 1),
  29. "optimeDate" : ISODate("2016-08-12T06:48:54Z"),
  30. "lastHeartbeat" : ISODate("2016-08-12T06:49:08.071Z"),
  31. "lastHeartbeatRecv" : ISODate("2016-08-12T06:49:06.110Z"),
  32. "pingMs" : 0,
  33. "configVersion" : 1
  34. }
  35. ],
  36. "ok" : 1
  37. }

在primary上添加用户,做登录验证,默认情况MongoDB是没有用户的,需要手动创建,现添加一个User用户,对任何库具有管理权限

  1. 52devops:PRIMARY> use admin #首先要切换到admin库
  2. switched to db admin
  3. 52devops:PRIMARY> db.createUser( {
  4. user: "User",#用户名
  5. pwd: "devopspwd", #密码
  6. roles: [ { role: "UserAnyDatabase", db: "admin" } ]
  7. }); #role对任何库有管理权限
  8. Successfully added user: {
  9. "user" : "User",
  10. "roles" : [
  11. {
  12. "role" : "UserAnyDatabase",
  13. "db" : "admin"
  14. }
  15. ]
  16. }

验证User用户,添加Root用户和业务对应用户

  1. 52devops:PRIMARY> use admin #切换到admin库
  2. switched to db admin
  3. 52devops:PRIMARY> db.auth("User","xxxx");
  4. 1 #1代表True

添加Root用户,root权限,包含所有权限

  1. 52devops:PRIMARY> db.createUser( {
  2. ... user: "Root",
  3. ... pwd: "devopspwd",
  4. ... roles: [ { role: "root", db: "admin" } ] #root权限,包含所有权限
  5. ... });
  6. Successfully added user: {
  7. "user" : "Root",
  8. "roles" : [
  9. {
  10. "role" : "root",
  11. "db" : "admin"
  12. }
  13. ]
  14. }

添加业务用户

  1. 52devops:PRIMARY> db.createUser(
  2. {
  3. user: "52devops",
  4. pwd: "52devops_pwd",
  5. roles:
  6. [
  7. {
  8. role: "dbOwner", #只对52devops库有管理权限
  9. db: "52devops"
  10. }
  11. ]
  12. }
  13. )
  14. Successfully added user: {
  15. "user" : "52devops",
  16. "roles" : [
  17. {
  18. "role" : "dbOwner",
  19. "db" : "52devops"
  20. }
  21. ]
  22. }

退出后,使用验证登录

  1. [root@MongoDB-7 bin]#mongo --port 11111 -uRoot -p devopspwd --authenticationDatabase admin

查看当前用户

  1. 52devops:PRIMARY> db.system.users.find();
  2. { "_id" : "admin.User", "user" : "User", "db" : "admin", "credentials" : { "SCRAM-SHA-1" : { "iterationCount" : 10000, "salt" : "TX+ZnQeDWWBGAaJosMs6Jw==", "storedKey" : "R/mL81gF+CnV2TeFA7eBqX6C1SI=", "serverKey" : "GxPxRqP9G9wFk9e4ryE0TwBNxDs=" } }, "roles" : [ { "role" : "UserAnyDatabase", "db" : "admin" } ] }
  3. { "_id" : "admin.Root", "user" : "Root", "db" : "admin", "credentials" : { "SCRAM-SHA-1" : { "iterationCount" : 10000, "salt" : "VA6WSQcCvSNbEea9lPL49g==", "storedKey" : "WUcilq2+Sgui2Ntlz0GkBi8vlJ8=", "serverKey" : "b4XWkjJcm9TVuZM0O1lHM19q/CM=" } }, "roles" : [ { "role" : "root", "db" : "admin" } ] }
  4. { "_id" : "admin.52devops", "user" : "52devops", "db" : "admin", "credentials" : { "SCRAM-SHA-1" : { "iterationCount" : 10000, "salt" : "EJIVVs8H3r+jaYVci8ljaQ==", "storedKey" : "ac86UQ0udpuimxfu/oOk8xN14w0=", "serverKey" : "yoEsiX0In94Mla2xVifmnXQ7daE=" } }, "roles" : [ { "role" : "dbOwner", "db" : "52devops" } ] }

添加arbiter节点

  1. rs.addArb("10.0.0.9:11111")

查看当前replica set状态

  1. 52devops:ARBITER> rs.status()
  2. {
  3. "set" : "52devops",
  4. "date" : ISODate("2016-08-15T02:15:15.197Z"),
  5. "myState" : 7,
  6. "members" : [
  7. {
  8. "_id" : 0,
  9. "name" : "10.0.0.7:11111",
  10. "health" : 1,
  11. "state" : 1,
  12. "stateStr" : "PRIMARY",
  13. "uptime" : 46,
  14. "optime" : Timestamp(1470994658, 1),
  15. "optimeDate" : ISODate("2016-08-12T09:37:38Z"),
  16. "lastHeartbeat" : ISODate("2016-08-15T02:15:14.480Z"),
  17. "lastHeartbeatRecv" : ISODate("2016-08-15T02:15:13.895Z"),
  18. "pingMs" : 1,
  19. "electionTime" : Timestamp(1471225831, 1),
  20. "electionDate" : ISODate("2016-08-15T01:50:31Z"),
  21. "configVersion" : 2
  22. },
  23. {
  24. "_id" : 1,
  25. "name" : "10.0.0.8:11111",
  26. "health" : 1,
  27. "state" : 2,
  28. "stateStr" : "SECONDARY",
  29. "uptime" : 46,
  30. "optime" : Timestamp(1470994658, 1),
  31. "optimeDate" : ISODate("2016-08-12T09:37:38Z"),
  32. "lastHeartbeat" : ISODate("2016-08-15T02:15:14.480Z"),
  33. "lastHeartbeatRecv" : ISODate("2016-08-15T02:15:14.998Z"),
  34. "pingMs" : 1,
  35. "configVersion" : 2
  36. },
  37. {
  38. "_id" : 2,
  39. "name" : "10.0.0.9:11111",
  40. "health" : 1,
  41. "state" : 7,
  42. "stateStr" : "ARBITER",
  43. "uptime" : 47,
  44. "configVersion" : 2,
  45. "self" : true
  46. }
  47. ],
  48. "ok" : 1
  49. }

到此replica set配置完毕。

四、生产环境注意情况

4.1不要使用root启动mongod

如果启动mongod时使用root用户,会出现警告
WARNING: You are running this process as the root user, which is not recommended.

4.2尽量使用numactl –interleave=all方式启动

4.2.1NUMA和SMP

NUMA和SMP是两种CPU相关的硬件架构。在SMP架构里面,所有的CPU争用一个总线来访问所有内存,优点是资源共享,而缺点是总线争用激烈。随着PC服务器上的CPU数量变多(不仅仅是CPU核数),总线争用的弊端慢慢越来越明显,于是Intel在Nehalem CPU上推出了NUMA架构,而AMD也推出了基于相同架构的Opteron CPU。
NUMA最大的特点是引入了node和distance的概念。对于CPU和内存这两种最宝贵的硬件资源,NUMA用近乎严格的方式划分了所属的资源组(node),而每个资源组内的CPU和内存是几乎相等。资源组的数量取决于物理CPU的个数(现有的PC server大多数有两个物理CPU,每个CPU有4个核);distance这个概念是用来定义各个node之间调用资源的开销,为资源调度优化算法提供数据支持。

4.2.2NUMA相关的策略

1)每个进程(或线程)都会从父进程继承NUMA策略,并分配有一个优先node。如果NUMA策略允许的话,进程可以调用其他node上的资源。
2)NUMA的CPU分配策略有cpunodebind、physcpubind。cpunodebind规定进程运行在某几个node之上,而physcpubind可以更加精细地规定运行在哪些核上。
3)NUMA的内存分配策略有localalloc、preferred、membind、interleave。
localalloc规定进程从当前node上请求分配内存;
而preferred比较宽松地指定了一个推荐的node来获取内存,如果被推荐的node上没有足够内存,进程可以尝试别的node。
membind可以指定若干个node,进程只能从这些指定的node上请求分配内存。
interleave规定进程从指定的若干个node上以RR(Round Robin 轮询调度)算法交织地请求分配内存。

4.2.3NUMA和swap的关系

可能大家已经发现了,NUMA的内存分配策略对于进程(或线程)之间来说,并不是公平的。在现有的RedhatLinux中,localalloc是默认的NUMA内存分配策略,这个配置选项导致资源独占程序很容易将某个node的内存用尽。而当某个node的内存耗尽时,Linux又刚好将这个node分配给了某个需要消耗大量内存的进程(或线程),swap就妥妥地产生了。尽管此时还有很多page cache可以释放,甚至还有很多的free内存。

4.2.4解决swap问题

虽然NUMA的原理相对复杂,实际上解决swap却很简单:只要在启动MySQL之前使用numactl –interleave来修改NUMA策略即可。
值得注意的是,numactl这个命令不仅仅可以调整NUMA策略,也可以用来查看当前各个node的资源使用情况,是一个很值得研究的命令。

  • 注:建议使用以下方式启动mongo
    numactl –interleave=all mongod -f devops.conf

4.3调整hugepage,关闭hupepage,不开启hugepage整理

一般而言,内存管理的最小块级单位叫做page,一个page是4096bytes,1M的内存会有256个page,1GB的话就会有256,000个page。CPU通过内置的内存管理单元维护着page表记录。
正常来说,有两种方式来增加内存可以管理的内存大小:
1)增大硬件内存管理单元的大小。
2)增大page的大小。
第一个方法不是很现实,现代的硬件内存管理单元最多只支持数百到上千的page表记录,并且,对于数百万page表记录的维护算法必将与目前的数百条记录的维护算法大不相同才能保证性能,目前的解决办法是,如果一个程序所需内存page数量超过了内存管理单元的处理大小,操作系统会采用软件管理的内存管理单元,但这会使程序运行的速度变慢。
从redhat 6(centos,sl,ol)开始,操作系统开始支持 Huge Pages,也就是大页。
简单来说, Huge Pages就是大小为2M到1GB的内存page,主要用于管理数千兆的内存,比如1GB的page对于1TB的内存来说是相对比较合适的。
THP(Transparent Huge Pages)是一个使管理Huge Pages自动化的抽象层。
目前需要注意的是,由于实现方式问题,THP会造成内存锁影响性能,尤其是在程序不是专门为大内内存页开发的时候,简单介绍如下:
操作系统后台有一个叫做khugepaged的进程,它会一直扫描所有进程占用的内存,在可能的情况下会把4kpage交换为Huge Pages,在这个过程中,对于操作的内存的各种分配活动都需要各种内存锁,直接影响程序的内存访问性能,并且,这个过程对于应用是透明的,在应用层面不可控制,对于专门为4k page优化的程序来说,可能会造成随机的性能下降现象。
注:启动前要关闭huge page

  1. echo "never" > /sys/kernel/mm/transparent_hugepage/enabled
  2. echo "never" > /sys/kernel/mm/transparent_hugepage/defrag
2
未经许可,不得转载,否则将受到作者追究,博主联系方式见首页右上角

该文章由 发布

这货来去如风,什么鬼都没留下!!!
发表我的评论
取消评论
代码 贴图 加粗 链接 删除线 签到