MongoDB集群篇

745 阅读38分钟

MongoDB集群和安全

6. 副本集-Replica Sets(*)

6.1 简介

  • MongoDB中的副本集(Replica Set)是一组维护相同数据集的mongod服务。 副本集可提供冗余和高

    可用性,是所有生产部署的基础

    也可以说,副本集类似于有自动故障恢复功能的主从集群。通俗的讲就是用多台机器进行同一数据的异

    步同步,从而使多台机器拥有同一数据的多个副本,并且当主库当掉时在不需要用户干预的情况下自动

    切换其他备份服务器做主库。而且还可以利用副本服务器做只读服务器,实现读写分离,提高负载

    • 冗余和数据可用性

      复制提供冗余并提高数据可用性。 通过在不同数据库服务器上提供多个数据副本,复制可提供一定级别

      的容错功能,以防止丢失单个数据库服务器

      在某些情况下,复制可以提供增加的读取性能,因为客户端可以将读取操作发送到不同的服务上, 在不

      同数据中心维护数据副本可以增加分布式应用程序的数据位置和可用性。 您还可以为专用目的维护其他

      副本,例如灾难恢复,报告或备份

    • MongoDB中的复制

      副本集是一组维护相同数据集的mongod实例。 副本集包含多个数据承载节点和可选的一个仲裁节点。

      在承载数据的节点中,一个且仅一个成员被视为主节点,而其他节点被视为次要(从)节点

      主节点接收所有写操作。 副本集只能有一个主要能够确认具有{w:“most”}写入关注的写入; 虽然在某

      些情况下,另一个mongod实例可能暂时认为自己也是主要的。主要记录其操作日志中的数据集的所有

      更改,即oplog辅助(副本)节点复制主节点的oplog并将操作应用于其数据集,以使辅助节点的数据集反映主节点的数据集。 如果主要人员不在,则符合条件的中学将举行选举以选出新的主要人员

      image-20200901143850255

    • 主从复制和副本集区别

      主从集群和副本集最大的区别就是副本集没有固定的“主节点”;整个集群会选出一个“主节点”,当其挂

      掉后,又在剩下的从节点中选中其他节点为“主节点”,副本集总有一个活跃点(主、primary)和一个或多

      个备份节点(从、secondary)

6.2 副本集的三个角色

  • 副本集有两种类型三种角色

  • 两种类型

    • 主节点(Primary)类型:数据操作的主要连接点,可读写
    • 次要(辅助、从)节点(Secondaries)类型:数据冗余备份节点,可以读或选举
  • 三种角色

    • 主要成员(Primary):主要接受所有写操作,就是主节点
    • 副本成员(Replicate):从节点通过复制操作以维护相同的数据集,即备份数据,不可写操作,但可以读操作(需额外配置),默认是一种从节点类型
    • 仲裁者(Arbiter):不保留任何数据的副本,只具有投票选举作用。当然也可以将冲裁服务器维护为一个副本集的一部分,即副本成员同时也可以是仲裁者,也是一种从节点类型
  • image-20200901144651867

  • 关于仲裁者的额外说明:

    您可以将额外的mongod实例添加到副本集作为仲裁者。 仲裁者不维护数据集。 仲裁者的目的是通过

    响应其他副本集成员的心跳和选举请求来维护副本集中的仲裁。 因为它们不存储数据集,所以仲裁器可

    以是提供副本集仲裁功能的好方法,其资源成本比具有数据集的全功能副本集成员更便宜。

    如果您的副本集具有偶数个成员,请添加仲裁者以获得主要选举中的“大多数”投票。 仲裁者不需要专用

    硬件。

    仲裁者将永远是仲裁者,而主要人员可能会退出并成为次要人员,而次要人员可能成为选举期间的主要

    人员

    如果你的副本+主节点的个数是偶数,建议加一个仲裁者,形成奇数,容易满足大多数的投票

    如果你的副本+主节点的个数是奇数,可以不加仲裁者

6.3 副本集架构目标

  • 一主一副本一仲裁

  • image-20200901145025399

6.4 副本集的创建

6.4.1 第一步:创建主节点
  • 建立存放数据和日志的目录

    #-----------myrs 
    #主节点
    mkdir -p /mongodb/replica_sets/myrs_27017/log \ & 
    mkdir -p /mongodb/replica_sets/myrs_27017/data/db
    
  • 新建或修改配置文件

    vim /mongodb/replica_sets/myrs_27017/mongod.conf
    
  • myrs_27017 mongod.conf(注意空格)

    systemLog:
       #MongoDB发送所有日志输出的目标指定为文件 
       destination: file
       #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径 
       path: "/mongodb/replica_sets/myrs_27017/log/mongod.log"
       #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
       logAppend: true
    storage:
       #mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。 
       dbPath: "/mongodb/replica_sets/myrs_27017/data/db"
       journal:
          #启用或禁用持久性日志以确保数据文件保持有效和可恢复。 
          enabled: true
    processManagement: 
       #启用在后台运行mongos或mongod进程的守护进程模式。 
       fork: true
       #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID 
       pidFilePath: "/mongodb/replica_sets/myrs_27017/log/mongod.pid"
    net:
       #服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip 
       #bindIpAll: true 
       #服务实例绑定的IP
       bindIp: localhost,192.168.83.133 
       #bindIp 
       #绑定的端口 
       port: 27017
    replication:
       #副本集的名称 
       replSetName: myrs
    
    

    image-20200901161752679

6.4.2 第二步:创建副本节点
  • 建立存放数据和日志的目录 27018

    #副本节点 
    mkdir -p /mongodb/replica_sets/myrs_27018/log \ & 
    mkdir -p /mongodb/replica_sets/myrs_27018/data/db
    
  • 新建或修改配置文件

    vim /mongodb/replica_sets/myrs_27018/mongod.conf
    
  • myrs_27018 mongod.conf(注意空格)

    systemLog:
       #MongoDB发送所有日志输出的目标指定为文件
       destination: file
       #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
       path: "/mongodb/replica_sets/myrs_27018/log/mongod.log"
       #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
       logAppend: true
    storage:
       #mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
       dbPath: "/mongodb/replica_sets/myrs_27018/data/db"
       journal:
          #启用或禁用持久性日志以确保数据文件保持有效和可恢复。
          enabled: true
    processManagement:
       #启用在后台运行mongos或mongod进程的守护进程模式。
       fork: true
       #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
       pidFilePath: "/mongodb/replica_sets/myrs_27018/log/mongod.pid"
    net:
       #服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
       #bindIpAll: true
       #服务实例绑定的IP
       bindIp: localhost,192.168.83.133
       #bindIp
       #绑定的端口
       port: 27018
    replication:
       #副本集的名称
       replSetName: myrs
    

    image-20200901162810042

6.4.3 第三步:创建冲裁节点
  • 建立存放数据和日志的目录 27019

    #-----------myrs 
    #仲裁节点 
    mkdir -p /mongodb/replica_sets/myrs_27019/log \ & 
    mkdir -p /mongodb/replica_sets/myrs_27019/data/db
    
  • 仲裁节点,新建或修改配置文件

    vim /mongodb/replica_sets/myrs_27019/mongod.conf
    
  • myrs_27019 mongod.conf

    systemLog:
       #MongoDB发送所有日志输出的目标指定为文件
       destination: file
       #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
       path: "/mongodb/replica_sets/myrs_27019/log/mongod.log"
       #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
       logAppend: true
    storage:
       #mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
       dbPath: "/mongodb/replica_sets/myrs_27019/data/db"
       journal:
          #启用或禁用持久性日志以确保数据文件保持有效和可恢复。
          enabled: true
    processManagement:
       #启用在后台运行mongos或mongod进程的守护进程模式。
       fork: true
       #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
       pidFilePath: "/mongodb/replica_sets/myrs_27019/log/mongod.pid"
    net:
       #服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
       #bindIpAll: true
       #服务实例绑定的IP
       bindIp: localhost,192.168.83.133
       #bindIp
       #绑定的端口
       port: 27019
    replication:
       #副本集的名称
       replSetName: myrs
    
6.4.4 第四步:初始化配置副本集和主节点
  • 启动三个节点

  • ./mongod -f /mongodb/replica_sets/myrs_27017/mongod.conf
    ./mongod -f /mongodb/replica_sets/myrs_27018/mongod.conf
    ./mongod -f /mongodb/replica_sets/myrs_27019/mongod.conf
    ps -ef|grep mongod
    
  • image-20200901165308216

  • 使用客户端命令连接任意一个节点,但这里尽量要连接主节点(27017节点)

    ./mongo --port 27017
    

    连接上之后,很多命令无法使用,,比如 show dbs 等,必须初始化副本集才行

    image-20200901165752314

  • 准备初始化新的副本集

    语法:rs.initiate(configuration)

    使用默认配置初始化副本集:rs.initiate()

    image-20200901170419299

6.4.5 查看副本集配置
  • 返回包含当前副本集配置的文档

  • 语法:rs.conf(configuration)

  • 使用默认,查看主节点配置:rs.conf()

    image-20200901170653057

  • 说明

    • "_id" : "myrs" :副本集的配置数据存储的主键值,默认就是副本集的名字

    • "members" :副本集成员数组,此时只有一个: "host" : "192.168.83.133:27017" ,该成员不

      是仲裁节点: "arbiterOnly" : false ,优先级(权重值): "priority" : 1

    • "settings" :副本集的参数配置

  • rs.status()查看节点当前运行状态image-20200901171026382

6.4.6 添加副本从节点
  • 在主节点添加从节点,将其它成员加入到副本集

  • 语法:

    rs.add(host,arbiterOnly)
    
  • 参数解释说明

    • host Stirng or Document 要添加到副本集的新成员。 指定为字符串或配置文档:1)如

      果是一个字符串,则需要指定新成员的主机名和可选的端口号;2)如果是一个文档,请指定在members数组中找到的副本集成员配置文档。 您必须在成员配置文档中指定主机字段。有关文档配置字段的说明,详见下方文档:主机成员的配置文档

    • arbiterOnly boolean 可选的。 仅在 值为字符串时适用。 如果为true,则添

      加的主机是仲裁者

  •  rs.add("192.168.83.133:27018")
    

    image-20200901171950429

    "ok" : 1 :说明添加成功

  • 查看副本集状态 rs.status()

    "name" : "192.168.83.133:27018" 是第二个节点的名字,其角色是 "stateStr" : "SECONDARY"

    image-20200901172421851

6.4.7 添加仲裁从节点
  • 添加一个仲裁节点到副本集

  • 语法:rs.addArb(host)

  • image-20200901172725595

    "ok" : 1 :说明添加成功

  • 查看副本集状态 rs.status()image-20200901172837714

6.5 副本集的数据读写操作

  • 目标:测试三个不同角色的节点的数据读写情况

  • 登录主节点27017,写入和读取数据

    use articledb
    
    db.comment.insert({"articleid":"100000","content":"今天天气真好,阳光 明媚","userid":"1001","nickname":"Rose","createdatetime":new Date()})
    
    db.comment.find()
    

    image-20200901173536700

  • 登录从节点27018

    image-20200901173738396

    发现,不能读取集合的数据。当前从节点只是一个备份,不是奴隶节点,无法读取数据,写当然更不

    行。因为默认情况下,从节点是没有读写权限的,可以增加读的权限,但需要进行设置

  • 设置读操作权限:设置为奴隶节点,允许在从成员上运行读的操作

    语法

    rs.slaveOk()
    #或
    rs.slaveOk(true)
    

    该命令是 db.getMongo().setSlaveOk() 的简化命令

  • 执行成功,具备读的权限,但仍然不允许插入image-20200901174159606

    image-20200901174317729

  • 现在可实现了读写分离,让主插入数据,让从来读取数据

  • 取消作为奴隶节点的读权限: rs.slaveOk(false)

  • 仲裁者节点,不存放任何业务数据的,可以登录查看image-20200902090237209

6.6 主节点的选举规则

  • MongoDB在副本集中,会自动进行主节点的选举,主节点选举的触发条件

    • 主节点故障
    • 主节点网络不可达(默认心跳信息为10秒)
    • 人工干预(rs.stepDown(600))
  • 一旦触发选举,就要根据一定规则来选主节点,选举规则是根据票数来决定谁获胜

    • 票数最高,且获得了“大多数”成员的投票支持的节点获胜

      “大多数”的定义为:假设复制集内投票成员数量为N,则大多数为 N/2 + 1。例如:3个投票成员,

      则大多数的值是2。当复制集内存活成员数量不足大多数时,整个复制集将无法选举出Primary,

      复制集将无法提供写服务,处于只读状态

    • 若票数相同,且都获得了“大多数”成员的投票支持的,数据新的节点获胜

      数据的新旧是通过操作日志oplog来对比的

    • 在获得票数的时候,优先级(priority)参数影响重大

      可以通过设置优先级(priority)来设置额外票数。优先级即权重,取值为0-1000,相当于可额外增加

      0-1000的票数,优先级的值越大,就越可能获得多数成员的投票(votes)数。指定较高的值可使成员

      更有资格成为主要成员,更低的值可使成员更不符合条件。

      默认情况下,优先级的值是1

      image-20200902093159437

      可以看出,主节点和副本节点的优先级各为1,即,默认可以认为都已经有了一票。但选举节点,优先

      级是0,(要注意是,官方说了,选举节点的优先级必须是0,不能是别的值。即不具备选举权,但具有

      投票权)

6.7 故障测试(*)

6.7.1 副本节点故障测试
  • 关闭27018副本节点

    • image-20200902095503887

    • 主节点和仲裁节点对27018的心跳失败,因为主节点还在,因此没有触发投票选举

    • 如果此时,主节点写入数据

      db.comment.insert({"_id":"1","articleid":"100001","content":"我们不应该把清晨浪费在 手机上,健康很重要,一杯温水幸福你我他。","userid":"1002","nickname":"相忘于江 湖","createdatetime":new Date("2019-08- 05T22:08:15.522Z"),"likenum":NumberInt(1000),"state":"1"})
      

      主节点插入读取一切正常image-20200902094500639

    • 再次启动从节点,会发现主节点写入的数据会自动同步到从节点

      再次启动27018服务image-20200902095548478

      副本节点数据自动同步image-20200902095623271

6.7.2 主节点故障测试
  • 关闭27017主节点,触发投票选举

    • image-20200902100103549

    • image-20200902100126237

    • 发现,从节点和仲裁节点对27017的心跳失败,当失败超过10秒,此时因为没有主节点了,会自动发起

      投票。而副本节点只有27018,因此,候选人只有一个就是27018,开始投票。27019向27018投了一票,27018本身自带一票,因此共两票,超过了“大多数”27019是仲裁节点,没有选举权,27018不向其投票,其票数是0

  • 结果:27018成为主节点,具备读写功能

    • 27018 退出重新进入,会发现自动转为主节点image-20200902100225126

    • 读写成功image-20200902100442952

    • 这时候再次启动之前宕机的主节点21017,发现27017变成了从节点,27018仍保持主节点。登录27017节点,发现是从节点了,数据自动从27018同步,从而实现高可用

      image-20200902100821108

      image-20200902101100770

6.7.3 仲裁节点和主节点故障
  • 先关掉仲裁节点27019,再关掉现在的主节点27018

    image-20200902101534358

  • 登录27017后,发现,27017仍然是从节点,副本集中没有主节点了,导致此时,副本集是只读状态,

    无法写入

    为什么不选举了?因为27017的票数,没有获得大多数,即没有大于等于2,它只有默认的一票(优先级是1)如果要触发选举,随便加入一个成员即可image-20200902101652218

    • 如果只加入27019仲裁节点成员,则主节点一定是27017,因为没得选了,仲裁节点不参与选举,

      但参与投票

      先启动27019仲裁节点image-20200902101856705

      27017从节点升级为主节点image-20200902102013565

    • 如果只加入27018节点,会发起选举。因为27017和27018都是两票,则按照谁数据新,谁当主节

      只启动27018,触发选举image-20200902102420537

      数据较新的当选主节点image-20200902102619140

6.7.4 仲裁节点和从节点故障
  • 先关掉仲裁节点27019,再关掉现在的副本节点27018

    image-20200902102310183

  • 10秒后,27017主节点自动降级为副本节点(服务降级)

    image-20200902102336666

  • 副本集不可写数据了,已经故障了

6.8 Compass工具连接副本集

  • image-20200902103300080
  • image-20200902103329154
  • image-20200902103354831

6.9 SpringDataMongoDB连接副本集(*)

  • 副本集语法

    mongodb://host1,host2,host3/articledb? connect=replicaSet&slaveOk=true&replicaSet=副本集名字
    
    • slaveOk=true:开启副本节点读的功能,可实现读写分离
    • connect=replicaSet:自动到副本集中选择读写的主机如果slaveOK是打开的,则实现了读写分离
  • 完整的连接字符串的参考(了解)

    mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]] [/[database][?options]]
    
    • mongodb:// 这是固定的格式,必须要指定
    • username:password@ 可选项,如果设置,在连接数据库服务器之后,驱动都会尝试登陆这个数据库
    • host1 必须的指定至少一个host, host1 是这个URI唯一要填写的。它指定了要连接服务器的地址。如果要连接复制集,请指定多个主机地址
    • portX 可选的指定端口,如果不填,默认为27017
    • /database 如果指定username:password@,连接并验证登陆指定数据库。若不指定,默认打开test 数据库
    • ?options 是连接选项。如果不使用/database,则前面需要加上/。所有连接选项都是键值name=value键值对之间通过&或;(分号)隔开
  • 示例:连接 replicaset 三台服务器 (端口 27017, 27018, 和27019),直接连接第一个服务器,无论是replica

    set一部分或者主服务器或者从服务器,写入操作应用在主服务器 并且分布查询到从服务器

    server:
      port: 7777
    
    
    spring:
    #数据源配置
      data:
        mongodb:
    #      # 主机地址
    #      host: 192.168.83.133
    #      # 默认端口是27017
    #      port: 27017
    #      # 数据库
    #      database: test
        # 副本集的连接字符串
          uri: mongodb://192.168.83.133:27017,192.168.83.133:27018,192.168.83.133:27019/articledb?connect=replicaSet&slaveOk=true&replicaSet=myrs
    

    注意:主机必须是副本集中所有的主机,包括主节点、副本节点、仲裁节点

  • SpringDataMongoDB自动实现了读写分离:

    • 写操作时,只打开主节点连接image-20200902104802182
    • 读操作是,同时打开主节点和从节点连接,但使用从节点获取数据image-20200902104540391

7. 分片集群-Sharded Cluster(*)

7.1 分片概念

  • 分片(sharding)是一种跨多台机器分布数据的方法, MongoDB使用分片来支持具有非常大的数据集和高吞吐量操作的部署

  • 换句话说:分片(sharding)是指将数据拆分,将其分散存在不同的机器上的过程。有时也用分区(partitioning)来表示这个概念。将数据分散到不同的机器上,不需要功能强大的大型计算机就可以储存更多的数据,处理更多的负载

  • 具有大型数据集或高吞吐量应用程序的数据库系统可以会挑战单个服务器的容量。例如,高查询率会耗尽服务器的CPU容量。工作集大小大于系统的RAM会强调磁盘驱动器的I / O容量

  • 有两种解决系统增长的方法:垂直扩展和水平扩展

    • 垂直扩展意味着增加单个服务器的容量,例如使用更强大的CPU,添加更多RAM或增加存储空间量。可用技术的局限性可能会限制单个机器对于给定工作负载而言足够强大。此外,基于云的提供商基于可用的硬件配置具有硬性上限。结果,垂直缩放有实际的最大值
    • 水平扩展意味着划分系统数据集并加载多个服务器,添加其他服务器以根据需要增加容量。虽然单个机器的总体速度或容量可能不高,但每台机器处理整个工作负载的子集,可能提供比单个高速大容量服务器更高的效率。扩展部署容量只需要根据需要添加额外的服务器,这可能比单个机器的高端硬件的总体成本更低。权衡是基础架构和部署维护的复杂性增加
  • MongoDB支持通过分片进行水平扩展

    • 以低价服务器成本,获取更高性能

7.2 分片集群包含的组件

  • MongoDB分片集群包含以下组件:
    • 分片(存储):每个分片包含分片数据的子集,每个分片都可以部署为副本集
    • mongos(路由):mongos充当查询路由器,在客户端应用程序和分片集群之间提供接口
    • config-servers(“调度”的配置):配置服务器存储集群的元数据和配置设置,从MongoDB 3.4开始,必须将配置服务器部署为副本集(CSRS)
  • 分片集群中组件交互图解image-20200902110411463
  • MongoDB在集合级别对数据进行分片,将集合数据分布在集群中的分片上

7.3 分片集群架构目标

  • 两个分片节点副本集(3+3)+一个配置节点副本集(3)+两个路由节点(2),共11个服务节点
  • image-20200902110546413

7.4 分片节点副本集的创建

7.4.1 第一套副本集
  • 准备存放数据和日志的目录

    #-----------myshardrs01 
    mkdir -p /mongodb/sharded_cluster/myshardrs01_27018/log \ &
    mkdir -p /mongodb/sharded_cluster/myshardrs01_27018/data/db \ & 
    mkdir -p /mongodb/sharded_cluster/myshardrs01_27118/log \ & 
    mkdir -p /mongodb/sharded_cluster/myshardrs01_27118/data/db \ & 
    mkdir -p /mongodb/sharded_cluster/myshardrs01_27218/log \ & 
    mkdir -p /mongodb/sharded_cluster/myshardrs01_27218/data/db
    
  • 新建或修改配置文件

    vim /mongodb/sharded_cluster/myshardrs01_27018/mongod.conf
    

    myshardrs01_27018:

    systemLog:
       #MongoDB发送所有日志输出的目标指定为文件
       destination: file
       #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
       path: "/mongodb/sharded_cluster/myshardrs01_27018/log/mongod.log"
       #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
       logAppend: true
    storage:
       #mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
       dbPath: "/mongodb/sharded_cluster/myshardrs01_27018/data/db"
       journal:
          #启用或禁用持久性日志以确保数据文件保持有效和可恢复。
          enabled: true
    processManagement:
       #启用在后台运行mongos或mongod进程的守护进程模式。
       fork: true
       #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
       pidFilePath: "/mongodb/sharded_cluster/myshardrs01_27018/log/mongod.pid"
    net:
       #服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
       #bindIpAll: true
       #服务实例绑定的IP
       bindIp: localhost,192.168.83.133
       #bindIp
       #绑定的端口
       port: 27018
    replication:
       #副本集的名称
       replSetName: myshards01
    sharding:
       #分片角色
       clusterRole: shardsvr	
    

    设置sharding.clusterRole需要mongod实例运行复制。 要将实例部署为副本集成员,请使用replSetName设置并指定副本集的名称 两种role:configsvr、shardsvr

  • 同样的操作 重复27118、27218 主要改端口号

    vim /mongodb/sharded_cluster/myshardrs01_27118/mongod.conf
    
    vim /mongodb/sharded_cluster/myshardrs01_27218/mongod.conf
    
  • 启动第一套副本集:一主一副本一仲裁

    • 依次启动image-20200902132356656

    • 初始化副本集和创建主节点,使用客户端命令连接任意一个节点,但这里尽量要连接主节点

      (1)执行初始化副本集命令rs.initiate()image-20200902132725098

      (2)主节点配置查看rs.status()image-20200902132840543

      (3)添加副本节点和仲裁节点image-20200902133112408

  • 查看副本集配置情况rs.conf(),出现如下效果则配置完成image-20200902133405414

7.4.2 第二套副本集
  • 准备存放数据和日志的目录

    #-----------myshardrs02
    mkdir -p /mongodb/sharded_cluster/myshardrs02_27318/log \ & 
    mkdir -p /mongodb/sharded_cluster/myshardrs02_27318/data/db \ & 
    mkdir -p /mongodb/sharded_cluster/myshardrs02_27418/log \ & 
    mkdir -p /mongodb/sharded_cluster/myshardrs02_27418/data/db \ & 
    mkdir -p /mongodb/sharded_cluster/myshardrs02_27518/log \ & 
    mkdir -p /mongodb/sharded_cluster/myshardrs02_27518/data/db
    
  • 新建或修改配置文件

    vim /mongodb/sharded_cluster/myshardrs02_27318/mongod.conf
    
    vim /mongodb/sharded_cluster/myshardrs02_27418/mongod.conf
    
    vim /mongodb/sharded_cluster/myshardrs02_27518/mongod.conf
    

    myshardrs02_27318:

    systemLog:
       #MongoDB发送所有日志输出的目标指定为文件
       destination: file
       #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
       path: "/mongodb/sharded_cluster/myshardrs02_27318/log/mongod.log"
       #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
       logAppend: true
    storage:
       #mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
       dbPath: "/mongodb/sharded_cluster/myshardrs02_27318/data/db"
       journal:
          #启用或禁用持久性日志以确保数据文件保持有效和可恢复。
          enabled: true
    processManagement:
       #启用在后台运行mongos或mongod进程的守护进程模式。
       fork: true
       #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
       pidFilePath: "/mongodb/sharded_cluster/myshardrs02_27318/log/mongod.pid"
    net:
       #服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
       #bindIpAll: true
       #服务实例绑定的IP
       bindIp: localhost,192.168.83.133
       #bindIp
       #绑定的端口
       port: 27318
    replication:
       #副本集的名称
       replSetName: myshards02
    sharding:
       #分片角色
       clusterRole: shardsvr	
    

    myshardrs02_27418、myshardrs02_27518 重复上述操作

  • 启动第二套副本集:一主一副本一仲裁image-20200902134308003

  • (1)初始化副本集和创建主节点:使用客户端命令连接任意一个节点,但这里尽量要连接主节点

    执行初始化副本集命令:rs.initiate()

    查看副本集情况(节选内容):rs.status()

  • (2)主节点配置查看:rs.conf()

  • (3)添加副本节点和仲裁节点如下image-20200902134940243

  • 查看副本集的配置情况

    • rs.conf()
    • rs.status()
    • image-20200902135209682

7.5 配置节点副本集的创建

  • 准备存放数据和日志的目录

    #-----------configrs 
    #建立数据节点data和日志目录 
    mkdir -p /mongodb/sharded_cluster/myconfigrs_27019/log \ & 
    mkdir -p /mongodb/sharded_cluster/myconfigrs_27019/data/db \ & 
    mkdir -p /mongodb/sharded_cluster/myconfigrs_27119/log \ & 
    mkdir -p /mongodb/sharded_cluster/myconfigrs_27119/data/db \ & 
    mkdir -p /mongodb/sharded_cluster/myconfigrs_27219/log \ & 
    mkdir -p /mongodb/sharded_cluster/myconfigrs_27219/data/db
    
  • 新建或修改配置文件

    vim /mongodb/sharded_cluster/myconfigrs_27019/mongod.conf
    
    vim /mongodb/sharded_cluster/myconfigrs_27119/mongod.conf
    
    vim /mongodb/sharded_cluster/myconfigrs_27219/mongod.conf
    

    myconfifigrs_27019/mongod.conf

    systemLog:
       #MongoDB发送所有日志输出的目标指定为文件
       destination: file
       #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
       path: "/mongodb/sharded_cluster/myconfigrs_27019/log/mongod.log"
       #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
       logAppend: true
    storage:
       #mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
       dbPath: "/mongodb/sharded_cluster/myconfigrs_27019/data/db"
       journal:
          #启用或禁用持久性日志以确保数据文件保持有效和可恢复。
          enabled: true
    processManagement:
       #启用在后台运行mongos或mongod进程的守护进程模式。
       fork: true
       #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
       pidFilePath: "/mongodb/sharded_cluster/myconfigrs_27019/log/mongod.pid"
    net:
       #服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
       #bindIpAll: true
       #服务实例绑定的IP
       bindIp: localhost,192.168.83.133
       #bindIp
       #绑定的端口
       port: 27019
    replication:
       #副本集的名称
       replSetName: myconfigrs
    sharding:
       #分片角色
       clusterRole: configsvr	
    
  • myconfifigrs_27119/mongod.conf 、myconfifigrs_27219/mongod.conf 同样配置即可

  • 依次启动三个mongod服务image-20200902140342148

  • (1)初始化副本集和创建主节点

    • 使用客户端命令连接任意一个节点,但这里尽量要连接主节点
    • 执行初始化副本集命令:rs.initiate()
    • 查看副本集情况(节选内容):rs.status()
  • 添加两个副本节点

    • rs.add("192.168.83.133:27119")
      rs.add("192.168.83.133:27219")
      rs.status()
      
    • image-20200902141219760

7.6 路由节点的创建和操作

7.6.1 第一个路由节点的创建和连接
  • 准备存放数据和日志的目录

    #-----------mongos01 
    mkdir -p /mongodb/sharded_cluster/mymongos_27017/log
    
  • 新建或修改配置文件:mymongos_27017/mongos.conf

    vi /mongodb/sharded_cluster/mymongos_27017/mongos.conf
    
    systemLog:
       #MongoDB发送所有日志输出的目标指定为文件
       destination: file
       #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
       path: "/mongodb/sharded_cluster//mymongos_27017/log/mongod.log"
       #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
       logAppend: true
    processManagement:
       #启用在后台运行mongos或mongod进程的守护进程模式。
       fork: true
       #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
       pidFilePath: "/mongodb/sharded_cluster//mymongos_27017/log/mongod.pid"
    net:
       #服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
       #bindIpAll: true
       #服务实例绑定的IP
       bindIp: localhost,192.168.83.133
       #bindIp
       #绑定的端口
       port: 27017
    sharding:
       #指定配置节点副本集 
       configDB: myconfigrs/192.168.83.133:27019,192.168.83.133:27119,192.168.83.133:27219	
    
  • 启动mongos服务

    • ./mongos -f /mongodb/sharded_cluster/mymongos_27017/mongos.conf
      
    • image-20200902142937475

  • 客户端登录mongos,此时可以查看库,但写不进数据image-20200902143449148

    原因:通过路由节点操作,现在只是连接了配置节点,还没有连接分片数据节点,因此无法写入业务数据

  • image-20200902143605190

7.6.2 在路由节点上进行分片配置操作
  • (1)使用命令添加分片,语法:

    sh.addShard("IP:Port")
    
    • 将第一套分片副本集添加进来
     sh.addShard("myshards01/192.168.83.133:27018,192.168.83.133:27118,192.168.83.133:27218")
    

    image-20200902144627977

    • 查看分片状态情况:sh.status()image-20200902144730171

    • 继续将第二套分片副本集添加进来

       sh.addShard("myshards02/192.168.83.133:27318,192.168.83.133:27418,192.168.83.133:27518")
      

    image-20200902145156070

    • 提示:如果添加分片失败,需要先手动移除分片,检查添加分片的信息的正确性后,再次添加分片

    移除分片

    use admin 
    db.runCommand( { removeShard: "myshards02" } )
    

    注意:如果只剩下最后一个shard,是无法删除的移除时会自动转移分片数据,需要一个时间过程,完成后,再次执行删除分片命令才能真正删除

  • (2)开启分片功能

    • sh.enableSharding("库名")、sh.shardCollection("库名.集合名",{"key":1})
    • image-20200902150723063
  • (3)集合分片

    • 对集合分片,你必须使用 sh.shardCollection() 方法指定集合和分片键

    • 语法:

      sh.shardCollection(namespace,key,unique)
      
    • 对集合进行分片时,你需要选择一个 片键(Shard Key) , shard key 是每条记录都必须包含的,且建立了

      索引的单个字段或复合字段,MongoDB按照片键将数据划分到不同的 数据块 中,并将 数据块 均衡地分布

      到所有分片中.为了按照片键划分数据块,MongoDB使用 基于哈希的分片方式(随机平均分配)或者基

      于范围的分片方式(数值大小分配)

      用什么字段当片键都可以,如:nickname作为片键,但一定是必填字段

    • 分片规则

      • 分片规则一:哈希策略

        对于 基于哈希的分片 ,MongoDB计算一个字段的哈希值,并用这个哈希值来创建数据块.在使用基于哈希分片的系统中,拥有”相近”片键的文档 很可能不会 存储在同一个数据块中,因此数据的分

        离性更好一些

        示例:使用nickname作为片键,根据其值的哈希值进行数据分片

        sh.shardCollection("articledb.comment",{"nickname":"hashed"})
        

        image-20200902150743281

        查看分片状态:sh.status()image-20200902151458640

      • 分片规则二:范围策略

        对于 基于范围的分片 ,MongoDB按照片键的范围把数据分成不同部分.假设有一个数字的片键:想象一个从负无穷到正无穷的直线,每一个片键的值都在直线上画了一个点.MongoDB把这条直线划分为更短的不重叠的片段,并称之为 数据块 ,每个数据块包含了片键在一定范围内的数据.在使用片键做范围划分的系统中,拥有”相近”片键的文档很可能存储在同一个数据块中,因此也会存储在同一个分片中.

        示例:使用作者年龄字段作为片键,按照年龄的值进行分片

        sh.shardCollection("articledb.author",{"age":1})
        

        查看分片状态:sh.status()image-20200902152251485

      • 注意的是:

        1)一个集合只能指定一个片键,否则报错。

        2)一旦对一个集合分片,分片键和分片值就不可改变。 如:不能给集合选择不同的分片键、不能更新分片键的值

        3)根据age索引进行分配数据

    • 基于范围的分片方式与基于哈希的分片方式性能对比

      • 基于范围的分片方式提供了更高效的范围查询,给定一个片键的范围,分发路由可以很简单地确定哪数据块存储了请求需要的数据,并将请求转发到相应的分片中.不过,基于范围的分片会导致数据在不同分片上的不均衡,有时候,带来的消极作用会大于查询性能的积极作用.比如,如果片键所在的字段是线性增长的,一定时间内的所有请求都会落到某个固定的数据块中,最终导致分布在同一个分片中.在这种情况下,一小部分分片承载了集群大部分的数据,系统并不能很好地进行扩展.
      • 与此相比,基于哈希的分片方式以范围查询性能的损失为代价,保证了集群中数据的均衡.哈希值的随机性使数据随机分布在每个数据块中,因此也随机分布在不同分片中.但是也正由于随机性,一个范围查询很难确定应该请求哪些分片,通常为了返回需要的结果,需要请求所有分片
      • 如无特殊情况,一般推荐使用 Hash Sharding
        • 而使用 _id 作为片键是一个不错的选择,因为它是必有的,你可以使用数据文档 _id 的哈希作为片键。这个方案能够是的读和写都能够平均分布,并且它能够保证每个文档都有不同的片键所以数据块能够很精细
        • 似乎还是不够完美,因为这样的话对多个文档的查询必将命中所有的分片。虽说如此,这也是一种比较好的方案了
        • 理想化的 shard key 可以让 documents 均匀地在集群中分布image-20200902152605580
7.6.3 分片后插入数据测试
  • (1)测试一(哈希规则):登录mongos后,向comment循环插入1000条数据

     use articledb
     for(var i=0;i<=1000;i++){db.comment.insert({_id:i+"",nickname:"BoBo"+i})}
     db.comment.count()
    
  • 提示:js的语法,因为mongo的shell是一个JavaScript的shell

  • 注意:从路由上插入的数据,必须包含片键,否则无法插入

  • 测试结果

    • 分别登录两个片的主节点,统计文档数量 当前一共1001条
    • 第一个分片副本集db.comment.count(),508条。注意切换数据库到articledb下 image-20200902154012479
    • 第二个分片副本集db.comment.count() 493条。注意切换数据库到articledb下image-20200902154222359
  • 结论

    • 可以看到,1000条数据近似均匀的分布到了2个shard上。是根据片键的哈希值分配的。这种分配方式非常易于水平扩展:一旦数据存储需要更大空间,可以直接再增加分片即可,同时提升了性能
    • 使用db.comment.stats()查看单个集合的完整情况,mongos执行该命令可以查看该集合的数据分片的情况
    • 使用sh.status()查看本库内所有集合的分片信息

  • (2)测试二(范围规则):登录mongs后,向comment循环插入20000条数据做测试

  • 注意:如果查看状态发现没有分片,则可能是由于以下原因造成了:

    ​ 1)系统繁忙,正在分片中。

    ​ 2)数据块(chunk)没有填满,默认的数据块尺寸(chunksize)是64M,填满后才会考虑向其他片的

    • 数据块填充数据,因此,为了测试,可以将其改小,这里改为1M,操作如下

      use config 
      db.settings.save( { _id:"chunksize", value: 1 } )
      
    • 测试完再改回来

      db.settings.save( { _id:"chunksize", value: 64 } )
      
  • //插入数据
    use articledb
    for(var i=1;i<=20000;i++) {db.author.save({"name":"BoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoB oBoBoBoBoBoBoBoBo"+i,"age":NumberInt(i%120)})}
    

    image-20200902155518840

  • 查看2个分片副本集的数据情况

    • 第一个分片副本集myshards01,7681条数据image-20200902155709635
    • 第二个分片副本集myshards02,18574条image-20200902155801183
7.6.4 再增加一个路由节点
  • 准备存放数据和日志的目录

    #-----------mongos02 
    mkdir -p /mongodb/sharded_cluster/mymongos_27117/log
    
  • 新建或修改配置文件

    vi /mongodb/sharded_cluster/mymongos_27117/mongos.conf
    
  • mymongos_27117/mongos.conf

    systemLog:
       #MongoDB发送所有日志输出的目标指定为文件
       destination: file
       #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
       path: "/mongodb/sharded_cluster//mymongos_27117/log/mongod.log"
       #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
       logAppend: true
    processManagement:
       #启用在后台运行mongos或mongod进程的守护进程模式。
       fork: true
       #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
       pidFilePath: "/mongodb/sharded_cluster//mymongos_27117/log/mongod.pid"
    net:
       #服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
       #bindIpAll: true
       #服务实例绑定的IP
       bindIp: localhost,192.168.83.133
       #bindIp
       #绑定的端口
       port: 27117
    sharding:
       #指定配置节点副本集 
       configDB: myconfigrs/192.168.83.133:27019,192.168.83.133:27119,192.168.83.133:27219	
    
  • 启动mongos服务./mongos -f /mongodb/sharded_cluster/mymongos_27117/mongos.confimage-20200902160639993

  • 使用mongo客户端登录27117,发现,第二个路由无需配置,因为分片配置都保存到了配置服务器了image-20200902161021314

6.7 SpringDataMongoDB连接分片集群

  • 多个路由的时候的SpringDataMongoDB的客户端配置参考如下

    server:
      port: 7777
    
    
    spring:
    #数据源配置
      data:
        mongodb:
    #      # 主机地址
    #      host: 192.168.83.133
    #      # 默认端口是27017
    #      port: 27017
    #      # 数据库
    #      database: test
        # 副本集的连接字符串
          #uri: mongodb://192.168.83.133:27017,192.168.83.133:27018,192.168.83.133:27019/articledb?connect=replicaSet&slaveOk=true&replicaSet=myrs
        #连接路由字符串
          uri: mongodb://192.168.83.133:27017,192.168.83.133:27117/articledb
    
  • 通过日志发现,写入数据的时候,会选择一个路由写入

    image-20200902161650173

    image-20200902161757931

7. 安全认证

7.1 MongoDB的用户和角色权限简介

  • 默认情况下,MongoDB实例启动运行时是没有启用用户访问权限控制的,也就是说,在实例本机服务器上都可以随意连接到实例进行各种操作,MongoDB不会对连接客户端进行用户验证,这是非常危险的

  • mongodb官网上说,为了能保障mongodb的安全可以做以下几个步骤:

    1)使用新的端口,默认的27017端口如果一旦知道了ip就能连接上,不太安全

    2)设置mongodb的网络环境,最好将mongodb部署到公司服务器内网,这样外网是访问不到的,公司内部访问使用vpn等

    3)开启安全认证,认证要同时设置服务器之间的内部认证方式,同时要设置客户端连接到集群的账号密码认证方式

  • 为了强制开启用户访问控制(用户验证),则需要在MongoDB实例启动时使用选项 --auth 或在指定启动配置文件中添加选项 auth=true

  • 相关概念

    • 1)启用访问控制:

      MongoDB使用的是基于角色的访问控制(Role-Based Access Control,RBAC)来管理用户对实例的访问

      通过对用户授予一个或多个角色来控制用户访问数据库资源的权限和数据库操作的权限,在对用户分配角色之前,用户无法访问实例,在实例启动时添加选项 --auth 或指定启动配置文件中添加选项 auth=true

    • 2)角色:

      在MongoDB中通过角色对用户授予相应数据库资源的操作权限,每个角色当中的权限可以显式指定,也可以通过继承其他角色的权限,或者两都都存在的权限。

    • 3)权限:权限由指定的数据库资源(resource)以及允许在指定资源上进行的操作(action)组成

      • 资源(resource)包括:数据库、集合、部分集合和集群;
      • 操作(action)包括:对资源进行的增、删、改、查(CRUD)操作。
  • 在角色定义时可以包含一个或多个已存在的角色,新创建的角色会继承包含的角色所有的权限。在同一个数据库中,新创建角色可以继承其他角色的权限,在 admin 数据库中创建的角色可以继承在其它任意数据库中角色的权限

  • 常用的内置角色

    • 数据库用户角色:read、readWrite
    • 所有数据库用户角色:readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase
    • 数据库管理角色:dbAdmin、dbOwner、userAdmin
    • 集群管理角色:clusterAdmin、clusterManager、clusterMonitor、hostManager
    • 备份恢复角色:backup、restore
    • 超级用户角色:root
    • 内部角色:system
  • 常用的角色权限描述

    • read:可以读取指定数据库中的任何数据
    • readWrite:可以读写指定数据库中任何数据,包括创建、重命名、删除集合
    • userAdmin:可以在指定数据库创建和修改用户
    • root:超级权限

7.2 单实例环境

  • 目标:对单实例的MongoDB服务开启安全认证,这里的单实例指的是未开启副本集或分片的MongoDB实例
7.2.1 关闭已开启的服务(可选)
  • 增加mongod的单实例的安全认证功能,可以在服务搭建的时候直接添加,也可以在之前搭建好的服务上添加

  • 停止服务的方式有两种:快速关闭和标准关闭

    • 快速关闭方法(快速,简单,数据可能会出错):通过系统的kill命令直接杀死进程

      kill -2 pID
      
    • 标准的关闭方法(数据不容易出错,但麻烦):通过mongo客户端中的shutdownServer命令来关闭服务

      //客户端登录服务,注意,这里通过localhost登录,如果需要远程登录,必须先登录认证才行。
      mongo --port 27017 
      //#切换到admin库 
      use admin 
      //关闭服务 
      db.shutdownServer()
      
  • 补充:如果一旦是因为数据损坏,则需要进行如下操作(了解)

    • (1)删除lock文件

      rm -f /mongodb/single/data/db/*.lock
      
    • (2)修复数据

      /usr/local/mongodb/bin/mongod --repair --dbpath=/mongodb/single/data/db
      
7.2.2 添加用户和权限
  • 启动single 单机模式的mongod服务image-20200902164452914

  • 客户端连接27017image-20200902164703360

  • 在操作用户时,启动mongod服务时尽量不要开启授权

  • 创建两个管理员用户,一个是系统的超级管理员 myroot ,一个是admin库的管理用户 myadmin

    • //切换到admin库 
      use admin 
      //创建系统超级用户 myroot,密码:123456,设置角色:root
      db.createUser({user:"myroot",pwd:"123456",roles:["root"]})
      //创建专门用来管理admin库的账号 myadmin,只用来作为用户权限的管理
      db.createUser({user:"myadmin",pwd:"123456",roles:[{role:"userAdminAnyDatabase",db:"admin"}]})
      //查看已经创建了的用户情况
      db.system.users.find()
      
      //删除用户
      db.dropUser("myadmin")
      //修改密码
      db.changeUserPassword("myroot", "123456")
      
    • image-20200902165417108

  • 提示

    • 1)本案例创建了两个用户,分别对应超管和专门用来管理用户的角色,事实上,你只需要一个用户即可。如果你对安全要求很高,防止超管泄漏,则不要创建超管用户

    • 2)和其它数据库(MySQL)一样,权限的管理都差不多一样,也是将用户和权限信息保存到数据库对应的表中。Mongodb存储所有的用户信息在admin 数据库的集合system.users中,保存用户名、密码和数据库信息。

    • 3)如果不指定数据库,则创建的指定的权限的用户在所有的数据库上有效,如{role:"userAdminAnyDatabase", db:""}

  • 认证测试

    //切换到admin
    use admin
    //密码输错,failed
    db.auth("myroot","12345")
    //密码正确
    db.auth("myroot","123456")
    

    image-20200902165953393

  • 创建普通用户

    • 创建普通用户可以在没有开启认证的时候添加,也可以在开启认证之后添加,但开启认证之后,必须使

      用有操作admin库的用户登录认证后才能操作。底层都是将用户信息保存在了admin数据库的集合

    • //创建(切换)将来要操作的数据库articledb,
      use articledb
      //创建用户,拥有articledb数据库的读写权限readWrite,密码是123456
      db.createUser({user: "bobo", pwd: "123456", roles: [{ role: "readWrite", db: "articledb" }]})
      //测试是否可用
      db.auth("bobo","123456")
      
    • image-20200902170356978

  • 提示:如果开启了认证后,登录的客户端的用户必须使用admin库的角色,如拥有root角色的myadmin用

    户,再通过myadmin用户去创建其他角色的用户

7.2.3 服务端开启认证和客户端连接登录
  • 关闭已经启动的服务

  • 有两种方式开启权限认证启动服务:一种是参数方式,一种是配置文件方式

    • 参数方式image-20200902170847939

    • 配置文件

      vim /mongodb/single/mongod.conf
      
      security: 
         #开启授权认证 
         authorization: enabled
      
  • 有两种认证方式,一种是先登录,在mongo shell中认证;一种是登录时直接认证

    • 先连接再认证

      • db.auth("muroot","123456")
        
    • 连接时直接认证

      •  ./mongo --port 27017 --authenticationDatabase admin -u myroot -p 123456
        
      • image-20200902171623546

      • 提示:

        -u :用户名

        -p :密码

        --authenticationDatabase :指定连接库。当登录是指定用户名密码时,必须指定对应的数据库

7.2.4 SpringDataMongoDB连接认证
  • 使用用户名和密码连接到 MongoDB 服务器,你必须使用'username:password@hostname/dbname' 格式,'username'为用户名,'password' 为密码
  • 目标:使用用户bobo使用密码 123456 连接到MongoDB 服务上

7.3 副本集环境

7.3.1 前言
  • 对于搭建好的mongodb副本集,为了安全,启动安全认证,使用账号密码登录
  • 副本集环境使用之前搭建好的image-20200902172539775
  • 对副本集执行访问控制需要配置两个方面
    • 副本集和共享集群的各个节点成员之间使用内部身份验证,可以使用密钥文件或x.509证书。密钥文件比较简单,本文使用密钥文件,官方推荐如果是测试环境可以使用密钥文件,但是正式环境,官方推x.509证书。原理就是,集群中每一个实例彼此连接的时候都检验彼此使用的证书的内容是否相同,只有证书相同的实例彼此才可以访问
    • 使用客户端连接到mongodb集群时,开启访问授权。对于集群外部的访问。如通过可视化客户端,或者通过代码连接的时候,需要开启授权
  • 在keyfifile身份验证中,副本集中的每个mongod实例都使用keyfifile的内容作为共享密码,只有具有正确密钥文件的mongod或者mongos实例可以连接到副本集。密钥文件的内容必须在6到1024个字符之间,并且在unix/linux系统中文件所有者必须有对文件至少有读的权限
7.3.2 关闭已开启的副本集服务(可选)
  • 关闭之前测试使用的单机mongod服务
7.3.3 通过主节点添加一个管理员账号
  • 依次启动副本集服务image-20200902172756363

  • 只需要在主节点上添加用户,副本集会自动同步

  • 开启认证之前,创建超管用户:myroot,密码:123456image-20200902173117859

7.3.4 创建副本集认证的key文件
  • 第一步:生成一个key文件到当前文件夹

    • 可以使用任何方法生成密钥文件。例如,以下操作使用openssl生成密码文件,然后使用chmod来更改文件权限,仅为文件所有者提供读取权限

    • openssl rand -base64 90 -out ./mongo.keyfile
      chmod 400 ./mongo.keyfile
      ll mongo.keyfile
      
    • image-20200902173519883

  • 提示:

    所有副本集节点都必须要用同一份keyfifile,一般是在一台机器上生成,然后拷贝到其他机器上,且必须有读的权限,否则将来会报错: permissions on /mongodb/replica_sets/myrs_27017/mongo.keyfile are too open

    一定要保证密钥文件一致,文件位置随便。但是为了方便查找,建议每台机器都放到一个固定的位置,都放到和配置文件一起的目录中,这里将该文件分别拷贝到多个目录中

    cp mongo.keyfile /mongodb/replica_sets/myrs_27017
    cp mongo.keyfile /mongodb/replica_sets/myrs_27018
    cp mongo.keyfile /mongodb/replica_sets/myrs_27019
    

    image-20200902173722748

7.3.5 修改配置文件指定keyfile
  • 分别编辑几个服务的mongod.conf文件,添加相关内容:

    /mongodb/replica_sets/myrs_27017/mongod.conf

    security:
       #KeyFile鉴权文件 
       keyFile: /mongodb/replica_sets/myrs_27017/mongo.keyfile 
       #开启认证方式运行 
       authorization: enabled
    
    • /mongodb/replica_sets/myrs_27018/mongod.conf、/mongodb/replica_sets/myrs_27019/mongod.conf 同样添加配置
  • 修改完配置,依次启动副本集服务image-20200902174351354

7.3.6 SpringDataMongoDB连接副本集
  • yml文件

    server:
      port: 7777
    
    
    spring:
    #数据源配置
      data:
        mongodb:
    #      # 主机地址
    #      host: 192.168.83.133
    #      # 默认端口是27017
    #      port: 27017
    #      # 数据库
    #      database: test
          #用户名
          # username: bobo
          #密码
          # password: 123456
        # 副本集的连接字符串
          #uri: mongodb://192.168.83.133:27017,192.168.83.133:27018,192.168.83.133:27019/articledb?connect=replicaSet&slaveOk=true&replicaSet=myrs
        #连接路由字符串
          #uri: mongodb://192.168.83.133:27017,192.168.83.133:27117/articledb
          #单机有认证的情况下,也使用字符串连接
          #uri: mongodb://bobo:123456@192.168.83.133:27017/articledb
          #副本集有认证的情况下,字符串连接 
          uri: mongodb://myroot:123456@192.168.83.133:27017,192.168.83.133:27018,192.168.83.133:2 7019/articledb?connect=replicaSet&slaveOk=true&replicaSet=myrs
    

7.4 分片集群环境认证

  • 一定要保证密钥文件一致,文件位置随便。但是为了方便查找,建议每台机器都放到一个固定的位置,

    都放到和配置文件一起的目录中。这里将该文件分别拷贝到多个目录中

    echo '/mongodb/sharded_cluster/myshardrs01_27018/mongo.keyfile /mongodb/sharded_cluster/myshardrs01_27118/mongo.keyfile /mongodb/sharded_cluster/myshardrs01_27218/mongo.keyfile /mongodb/sharded_cluster/myshardrs02_27318/mongo.keyfile /mongodb/sharded_cluster/myshardrs02_27418/mongo.keyfile /mongodb/sharded_cluster/myshardrs02_27518/mongo.keyfile /mongodb/sharded_cluster/myconfigrs_27019/mongo.keyfile /mongodb/sharded_cluster/myconfigrs_27119/mongo.keyfile /mongodb/sharded_cluster/myconfigrs_27219/mongo.keyfile /mongodb/sharded_cluster/mymongos_27017/mongo.keyfile /mongodb/sharded_cluster/mymongos_27117/mongo.keyfile' | xargs -n 1 cp -v /root/mongo.keyfile
    
  • 分片副本集操作 同副本集

  • 不同:/mongos.conf mongos服务的配置文件 添加认证

    security:
       #KeyFile鉴权文件 
       keyFile: /mongodb/sharded_cluster/mymongos_27017/mongo.keyfile
    
  • 不需要authorization:enabled的配置。原因是,副本集加分片的安全认证需要配置两方面的,副本集各个节点之间使用内部身份验证,用于内部各个mongo实例的通信,只有相同keyfifile

    才能相互访问。所以都要开启 keyFile: /mongodb/sharded_cluster/mymongos_27117/mongo.keyfile ,然而对于所有的mongod,才是真正的保存数据的分片。mongos只做路由,不保存数据。所以所有的mongod开启访问数据的授权authorization:enabled。这样用户只有账号密码正确才能访问到数据

  • SpringDataMongoDB连接认证

    server:
      port: 7777
    
    
    spring:
    #数据源配置
      data:
        mongodb:
    #      # 主机地址
    #      host: 192.168.83.133
    #      # 默认端口是27017
    #      port: 27017
    #      # 数据库
    #      database: test
          #用户名
          # username: bobo
          #密码
          # password: 123456
        # 副本集的连接字符串
          #uri: mongodb://192.168.83.133:27017,192.168.83.133:27018,192.168.83.133:27019/articledb?connect=replicaSet&slaveOk=true&replicaSet=myrs
        #连接路由字符串
          #uri: mongodb://192.168.83.133:27017,192.168.83.133:27117/articledb
          #单机有认证的情况下,也使用字符串连接
          #uri: mongodb://bobo:123456@192.168.83.133:27017/articledb
          #副本集有认证的情况下,字符串连接
          #uri: mongodb://myroot:123456@192.168.83.133:27017,192.168.83.133:27018,192.168.83.133:2 7019/articledb?connect=replicaSet&slaveOk=true&replicaSet=myrs
          # 分片集群有认证的情况下,字符串连接
          uri: mongodb://myroot:123456@192.168.83.133:27017,192.168.83.133:27117/articledb