如何使用 Oracle Solaris 区域搭建 MongoDB NoSQL 集群

作者:Orgad Kimchi

如何在基于 x86 的系统上使用 Oracle Solaris 区域、Oracle Solaris 11 服务管理工具和 DTrace 分析工具搭建 MongoDB NoSQL 集群。


2013 年 6 月发布


想对本文发表评论吗?请将链接发布在 Facebook 的 OTN Garage 页面上。有类似文章要分享?请将其发布在 Facebook 或 Twitter 上,我们来进行讨论。
关于 MongoDB 和 Oracle Solaris 区域
下载并安装 MongoDB
创建虚拟网络接口
配置网络时间协议
编辑 ZFS 内存使用配置
创建 MongoDB 区域
配置服务管理工具
验证名称解析
设置 MongoDB 复制
执行基本数据库操作
检查 MongoDB 集群冗余
使用 DTrace 提高操作系统的可观察性
总结
另请参见
关于作者

本文首先简要介绍 MongoDB,之后给出了一个在基于 x86 的系统上搭建三节点 MongoDB 集群的示例。前提条件是,您应对 Oracle Solaris 区域和网络管理有一个基本的了解。

关于 MongoDB 和 Oracle Solaris 区域

MongoDB 是一种面向文档的 NoSQL 开源数据库,它将结构化数据存储为具有动态模式的类似 JavaScript 对象表示法 (JSON) 的文档。这就可以实现快速开发,因为随着应用的演变可以快速修改数据库模式,而无需关闭数据库。此外,MongoDB 还支持使用复制集进行主从复制,它还通过分片特性提供横向可扩展性,这让您可以将数据(基于分片密钥)分发到多个 MongoDB 服务器。

以下是使用 Oracle Solaris 搭建 MongoDB 集群的好处:

  • 使用区域克隆特性,您可以在几分钟(而不是几小时)内将新的 MongoDB 主机添加到集群。您可以使用 Oracle Solaris 区域轻松扩展 MongoDB 集群。
  • 如果遇到用户错误或软件错误,服务管理工具可确保每个集群成员的高可用性,并确保仅在不得已时才执行 MongoDB 复制故障切换。
  • 现在只需数分钟即可发现性能问题,而使用 DTrace 时需要数天,这提高了操作系统的可观察性。DTrace 提供操作系统的整体性能概览,并可通过与内置 MongoDB 工具协作深入分析性能。
  • 通过 ZFS 内置压缩可优化磁盘 I/O 利用率,从而提高 I/O 性能。

在本文所示示例中,将使用 Oracle Solaris 区域、服务管理工具、ZFS 和网络虚拟化技术安装所有 MongoDB 集群构建块。图 1 显示了架构:

图 1

图 1.架构

下载并安装 MongoDB

本文使用 Oracle Solaris 11.1,您可以从这里下载。

  1. 要获取 MongoDB 发行版,请从 MongoDB 下载站点下载新近稳定版本。本文采用 MongoDB Oracle Solaris 64 位 2.4.1 版本。

    :现在仅有适用于基于 x86 的系统上的 Oracle Solaris 的版本可用。没有适用于基于 SPARC 的系统的版本。

  2. 在全局区域上创建 /usr/local 目录(如果该目录不存在)。集群配置将以只读文件系统的形式跨区域共享 MongoDB 目录结构。

    root@global_zone:~# mkdir -p /usr/local
    
  3. 将 MongoDB tarball 复制到 /usr/local

    root@global_zone:~# cp /tmp/mongodb-sunos5-x86_64-2.4.1.tgz /usr/local
    
  4. 解压缩 tarball:

    root@global_zone:~# cd /usr/local
    root@global_zone:~# tar -xvfz /usr/local/mongodb-sunos5-x86_64-2.4.1.tgz
    
  5. 重命名 MongoDB 二进制文件的位置:

    root@global_zone:~# ln -s /usr/local/mongodb-sunos5-x86_64-2.4.1 /usr/local/mongodb
  6. 创建 MongoDB 配置目录:

    root@global_zone:~# mkdir /usr/local/mongodb/etc
    
  7. 创建 MongoDB 额外的库目录:

    root@global_zone:~# mkdir /usr/local/mongodb/mongo-extra-64
    
  8. MongoDB 需要更新版的 libstdc。请从 http://mirror.opencsw.org/opencsw/allpkgs/libstdc%2b%2b6-4.7.2%2cREV%3d2013.03.28-SunOS5.10-i386-CSW.pkg.gz 下载 libstdc 软件包。
  9. 解压缩 libstdc 软件包:

    root@global_zone:~# gzip -d /tmp/libstdc++6-4.7.2,REV=2013.03.28-SunOS5.10-i386-CSW.pkg.gz
    
  10. 使用 pkgtrans 命令将软件包转换成文件系统格式:

    root@global_zone:~# cd /tmp root@global_zone:~# pkgtrans /tmp/libstdc++6-4.7.2\,REV\=2013.03.28-SunOS5.10-i386-CSW.pkg /tmp
  11. 将显示以下输出。在提示符处按 Enter:

    The following packages are available:
      1  CSWlibstdc++6     libstdc++6 - The GNU Compiler Collection, libstdc++.so.6 (i386) 4.7.2,REV=2013.03.28
    
      Select package(s) you wish to process (or 'all' to process
    all packages). (default: all) [?,??,q]: 
    
  12. libstdc 库复制到 /usr/local/mongodb/mongo-extra-64/
    root@global_zone:~# cp /tmp/CSWlibstdc++6/root/opt/csw/lib/amd64/libstdc++.so.6.0.17 \
    /usr/local/mongodb/mongo-extra-64/
    
  13. 创建 MongoDB 组:

    root@global_zone:~# groupadd mongodb
    
  14. 添加 MongoDB 用户,并设置用户密码:

    root@global_zone:~# useradd -g mongodb mongodb
    root@global_zone:~# passwd mongodb
    
  15. 创建 MongoDB 用户主目录:

    root@global_zone:~# mkdir -p /export/home/mongodb
    root@global_zone:~# chown -R mongodb:mongodb /export/home/mongodb
    
  16. 编辑 MongoDB 配置文件,如表 1 所示:

    表 1.MongoDB 配置文件
    文件名 说明
    mongodb-start MongoDB 后台进程的启动脚本
    mongodb.conf 指定 MongoDB 后台进程相关参数的文件

    :要详细了解这些配置文件如何控制 MongoDB,请参见 MongoDB 手册

    1. 更改目录:

      root@global_zone:~# cd /usr/local/mongodb/etc
      
    2. 然后编辑 mongodb.conf 文件,按表 2 所述设置属性值:

      root@global_zone:~# vi mongodb.conf
      fork = true
      quiet = true
      logpath = /var/log/mongodb/mongod.log
      logappend = true
      replSet = rs0
      rest = true
      

      表 2.MongoDB 配置属性
      属性 说明
      fork true 启用 mongod 的后台进程模式,它是 MongoDB 系统的主要后台进程。它处理数据请求,管理数据格式,并执行后台管理操作。
      quiet true 这是详细级别的日志。在诊断或测试情况下,将此值设置为 false
      logpath /var/log/mongodb/mongod.log 指定 mongod 后台进程写入输出的文件。如果未设置此值,mongod 将所有输出写入标准输出(如 stdout)。
      logappend true 确保 mongod 不会覆盖跟踪服务器启动操作之后的现有日志文件。
      replSet rs0 指定此服务器的关联副本集。
      rest true 启用 REST 接口,该接口允许 HTTP 客户端对服务器运行命令。
    3. 编辑 MongoDB 启动脚本文件,应如下所示:

      root@global_zone:~# vi  /usr/local/mongodb/bin/mongodb-start
      #!/usr/bin/bash
      export LD_PRELOAD_64=/usr/local/mongodb/mongo-extra-64/libstdc++.so.6.0.17:/lib/amd64/libumem.so
      export LC_ALL=C
      /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/etc/mongodb.conf
      
  17. 更改目录所有权:

    root@global_zone:~# chown -R mongodb:mongodb /usr/local/mongodb-sunos5-x86_64-2.4.1
    root@global_zone:~# chmod -R 755 /usr/local/mongodb-sunos5-x86_64-2.4.1
    

创建虚拟网络接口

为 MongoDB 区域创建一系列虚拟网络接口 (VNIC):

root@global_zone:~# dladm create-vnic -l net0 mongodb_node1
root@global_zone:~# dladm create-vnic -l net0 mongodb_node2
root@global_zone:~# dladm create-vnic -l net0 mongodb_node3

配置网络时间协议

我们应确保使用网络时间协议 (NTP) 同步 MongoDB 区域上的系统时钟。

:建议选择可以作为专用时间同步源的 NTP 服务器,这样在关闭计算机进行计划维护时不会对其他服务产生负面影响。

在以下示例中,全局区域配置为 NTP 服务器。

  1. 配置 NTP 服务器:

    root@global_zone:~# cd /etc/inet
    root@global_zone:~# cp ntp.server ntp.conf
    root@global_zone:~# touch /var/ntp/ntp.drift
    
  2. 编辑 NTP 服务器配置文件,如清单 1 所示:

    root@global_zone:~# vi /etc/inet/ntp.conf
    
    server 127.127.1.0 prefer
    broadcast 224.0.1.1 ttl 4
    enable auth monitor
    driftfile /var/ntp/ntp.drift
    statsdir /var/ntp/ntpstats/
    filegen peerstats file peerstats type day enable
    filegen loopstats file loopstats type day enable
    filegen clockstats file clockstats type day enable
    keys /etc/inet/ntp.keys
    trustedkey 0
    requestkey 0
    controlkey 0
    

    清单 1.NTP 服务器配置文件

  3. 启用 NTP 服务器服务:

    root@global_zone:~# svcadm enable ntp
    
  4. 使用以下命令验证 NTP 服务器是否在线:

    root@global_zone:~# svcs -a | grep ntp
    online         16:04:15 svc:/network/ntp:default
    

编辑 ZFS 内存使用配置

MongoDB 和 Oracle Solaris ZFS 都是内存密集型进程。为避免 MongoDB 实例出现内存不足,需要通过调低 zfs_arc_max 参数值来减少 ZFS ARC 缓存的内存消耗。

  1. 将该参数设置为一个较低的值(如 2 GB),如以下示例中所示:

    root@global_zone:~# echo "set zfs:zfs_arc_max=2147483648" >> /etc/system
    
  2. 使用以下命令监视 ZFS ARC 使用的内存量:

    root@global_zone:~# kstat -m zfs -s c_max
    module: zfs                             instance: 0
    name:   arcstats                        class:    misc
            c_max                           2147483648
    

    您可以从输出中看到,zfs_arc_max 属性的值现在为 2 GB。(c_maxkstat 命令输出中 zfs_arc_max 的值。)

  3. 重新启动系统,以在 /etc/system 中实施该属性值。

    root@global_zone:~# reboot
    

创建 MongoDB 区域

表 3 显示了我们将创建的 MongoDB 区域配置汇总:

表 3.区域汇总
区域名称 功能 ZFS 挂载点 VNIC 名称 IP 地址 内存要求
mongodb-node1 主要 /zones/mongodb-node1 mongodb_node1 192.168.1.1 14 GB
mongodb-node2 辅助 /zones/mongodb-node2 mongodb_node2 192.168.1.2 14 GB
mongodb-node3 辅助 /zones/mongodb-node3 mongodb_node3 192.168.1.3 14 GB

  1. 如果您的 MongoDB 区域还没有文件系统,请执行以下命令:

    root@global_zone:~# zfs create -o compression=on -o mountpoint=/zones rpool/zones
    
  2. 创建 mongodb-node1 区域,如清单 2 所示:

    root@global_zone:~# zonecfg -z mongodb-node1
    Use 'create' to begin configuring a new zone.
    zonecfg:mongodb-node1> create
    create: Using system default template 'SYSdefault'
    zonecfg:mongodb-node1> set limitpriv="default,sys_time"
    zonecfg:mongodb-node1> set autoboot=true
    zonecfg:mongodb-node1> set zonepath=/zones/mongodb-node1
    zonecfg:mongodb-node1> add fs
    zonecfg:mongodb-node1:fs> set dir=/usr/local
    zonecfg:mongodb-node1:fs> set special=/usr/local
    zonecfg:mongodb-node1:fs> set type=lofs
    zonecfg:mongodb-node1:fs> set options=[ro,nodevices]
    zonecfg:mongodb-node1:fs> end
    zonecfg:mongodb-node1> add net
    zonecfg:mongodb-node1:net> set physical=mongodb_node1
    zonecfg:mongodb-node1:net> end
    zonecfg:mongodb-node1> add capped-memory
    zonecfg:mongodb-node1:capped-memory> set physical=14g
    zonecfg:mongodb-node1:capped-memory> end
    zonecfg:mongodb-node1> verify
    zonecfg:mongodb-node1> exit
    

    清单 2.创建 mongodb-node1 区域

  3. 创建第二个 MongoDB 区域,如清单 3 所示:

    root@global_zone:~# zonecfg -z mongodb-node2
    Use 'create' to begin configuring a new zone.
    zonecfg:mongodb-node2> create
    create: Using system default template 'SYSdefault'
    zonecfg:mongodb-node2> set limitpriv="default,sys_time"
    zonecfg:mongodb-node2> set autoboot=true
    zonecfg:mongodb-node2> set zonepath=/zones/mongodb-node2
    zonecfg:mongodb-node2> add fs
    zonecfg:mongodb-node2:fs> set dir=/usr/local
    zonecfg:mongodb-node2:fs> set special=/usr/local
    zonecfg:mongodb-node2:fs> set type=lofs
    zonecfg:mongodb-node2:fs> set options=[ro,nodevices]
    zonecfg:mongodb-node2:fs> end
    zonecfg:mongodb-node2> add net
    zonecfg:mongodb-node2:net> set physical=mongodb_node2
    zonecfg:mongodb-node2:net> end
    zonecfg:mongodb-node2> add capped-memory
    zonecfg:mongodb-node2:capped-memory> set physical=14g
    zonecfg:mongodb-node2:capped-memory> end
    zonecfg:mongodb-node2> verify
    zonecfg:mongodb-node2> exit
    

    清单 3.创建 mongodb-node2 区域

  4. 创建第三个 MongoDB 区域,如清单 4 所示:

    root@global_zone:~# zonecfg -z mongodb-node3
    Use 'create' to begin configuring a new zone.
    zonecfg:mongodb-node3> create
    create: Using system default template 'SYSdefault'
    zonecfg:mongodb-node3> set limitpriv="default,sys_time"
    zonecfg:mongodb-node3> set autoboot=true
    zonecfg:mongodb-node3> set zonepath=/zones/mongodb-node3
    zonecfg:mongodb-node3> add fs
    zonecfg:mongodb-node3:fs> set dir=/usr/local
    zonecfg:mongodb-node3:fs> set special=/usr/local
    zonecfg:mongodb-node3:fs> set type=lofs
    zonecfg:mongodb-node3:fs> set options=[ro,nodevices]
    zonecfg:mongodb-node3:fs> end
    zonecfg:mongodb-node3> add net
    zonecfg:mongodb-node3:net> set physical=mongodb_node3
    zonecfg:mongodb-node3:net> end
    zonecfg:mongodb-node3> add capped-memory
    zonecfg:mongodb-node3:capped-memory> set physical=14g
    zonecfg:mongodb-node3:capped-memory> end
    zonecfg:mongodb-node3> verify
    zonecfg:mongodb-node3> exit
    

    清单 4.创建 mongodb-node3 区域

  5. 现在安装 mongodb-zone1 区域;稍后我们将克隆此区域,以提高其他区域的区域创建速度。

    root@global_zone:~# zoneadm -z mongodb-node1 install
    
  6. 启动 mongodb-node1 区域,并查看所创建区域的状态,如清单 5 所示:

    root@global_zone:~# zoneadm -z mongodb-node1 boot
    root@global_zone:~# zoneadm list -cv
    ID NAME             STATUS     PATH                   BRAND    IP
    0  global           running    /                      solaris  shared
    1  mongodb-node1    running    /zones/mongodb-node1   solaris  excl
    -  mongodb-node2    configured /zones/mongodb-node2   solaris  excl
    -  mongodb-node3    configured /zones/mongodb-node3   solaris  excl
    root@global_zone:~# zlogin -C mongodb-node1   
    

    清单 5.启动 mongodb-node1 区域

  7. 使用 mongodb-node1 区域的以下配置提供区域的主机信息:

    1. 主机名使用 mongodb-node1
    2. 确保 mongodb_node1 的网络接口 IP 地址是 192.168.1.1/24。
    3. 确保名称服务基于您的网络配置。在本文中,我们将使用 /etc/hosts 作名称解析。您还可以设置 DNS 进行主机名称解析。
  8. 完成区域设置之后,将出现登录提示。使用 root 密码以 root 身份登录区域。
  9. MongoDB 需要适用于其环境的库,因此使用以下命令安装 gcc 编译器 4.5 版:

    root@mongodb-node1:~# pkg install gcc-45
    
  10. 创建 MongoDB 组:

    root@mongodb-node1:~# groupadd mongodb
    
  11. 添加 MongoDB 用户,并设置用户密码:

    root@mongodb-node1:~# useradd -g mongodb mongodb
    root@mongodb-node1:~# passwd mongodb
    
  12. 创建 MongoDB 用户主目录:

    root@mongodb-node1:~# mkdir -p /export/home/mongodb
    
  13. 编辑 MongoDB 用户的 bash shell 初始化脚本,如清单 6 所示:

    root@mongodb-node1:~# vi /export/home/mongodb/.profile
    
    PATH=/usr/local/mongodb/bin:$PATH
    export LD_PRELOAD_64=/lib/secure/64/libstdc++.so.6.0.1
    export LC_ALL=C
    ulimit -n 20000
    
    case ${SHELL} in
    *bash)
    typeset +x PS1="\u@\h:\w\\$ "
    ;;
    esac
    

    清单 6.编辑初始化脚本

  14. 更改 MongoDB 主目录所有权:

    root@mongodb-node1:~# chown -R mongodb:mongodb /export/home/mongodb
    
  15. 创建 MongoDB 数据文件目录:

    root@mongodb-node1:~# mkdir -p /data/db
    root@mongodb-node1:~# chown -R mongodb:mongodb /data/db
    
  16. 创建 MongoDB 日志文件目录:

    root@mongodb-node1:~# mkdir /var/log/mongodb
    root@mongodb-node1:~# chown -R mongodb:mongodb /var/log/mongodb
    
  17. libstdc 库创建符号链接,以便将其添加为安全库:

    root@mongodb-node1:~# ln -s /usr/local/mongodb/mongo-extra-64/libstdc++.so.6.0.17 /lib/secure/64
    
  18. 配置 NTP 客户端,如以下示例所示:

    1. 安装 NTP 软件包:

      root@mongodb-node1:~# pkg install ntp
      
    2. 创建 NTP 客户端配置文件:

      root@mongodb-node1:~# cd /etc/inet
      root@mongodb-node1:~# cp ntp.client ntp.conf
      root@mongodb-node1:~# touch /var/ntp/ntp.drift
      
  19. 编辑 NTP 客户端配置文件,如下所示:

    root@mongodb-node1:~# vi /etc/inet/ntp.conf
    server <ntp-server> prefer
    driftfile /var/ntp/ntp.drift
    statsdir /var/ntp/ntpstats/
    filegen peerstats file peerstats type day enable
    filegen loopstats file loopstats type day enable
    

    :使用本地时间服务器的 IP 地址或主机名或 http://support.ntp.org/bin/view/Servers/NTPPoolServers 处推荐的服务器的 IP 地址或主机名替换 IP 地址 ntp-server

  20. 启用 NTP 客户端服务:

    root@mongodb-node1:~# svcadm enable ntp
    
  21. 验证 NTP 客户端状态:

    root@mongodb-node1:~# svcs ntp
    STATE          STIME    FMRI
    online         12:44:01 svc:/network/ntp:default
    
  22. 检查 NTP 客户端能否与 NTP 服务器同步时钟:

    root@mongodb-node1:~# ntpq -p
    
  23. /etc/hosts 中添加 MongoDB 集群成员的主机名和 IP 地址:

    root@mongodb-node1:~# cat /etc/hosts
    
    ::1        localhost
    127.0.0.1  localhost loghost
    192.168.1.1 mongodb-node1
    192.168.1.2 mongodb-node2
    192.168.1.3 mongodb-node3
    

    :如果您使用 NTP,需要将 NTP 服务器主机名和 IP 地址添加到 /etc/hosts

配置服务管理工具

服务管理工具是 Oracle Solaris 中用来管理系统和应用服务的特性,它取代了传统的 init 脚本启动。服务管理工具可确保重要系统和应用服务即便在软硬件发生故障时也能继续运行,从而提高了系统的可用性。此外,服务管理工具的自动重启功能还可以在出现错误时重新启动操作系统服务,无需人工干预。

  1. 使用 svcbundle 工具创建服务管理工具清单,该清单将在计算机重启时自动启动 MongoDB 并在出现错误时重启服务。

    root@mongodb-node1:~# svcbundle -s service-name=application/mongodb \
    -s start-method="/usr/local/mongodb/bin/mongodb-start" \
    -s model=daemon -o mongodb.xml
    
  2. 编辑 mondodb.xml 清单,以便使用 MongoDB 组和用户启用服务启动。为此,在 </dependency> 所在代码行后面,添加以下行:

    <method_context>
       <method_credential group="mongodb" user="mongodb"/>
    </method_context>
    

    清单 7 显示修改后的 MongoDB 服务管理工具清单:

    root@mongodb-node1:~# vi mongodb.xml
    <?xml version="1.0" ?>
    <!DOCTYPE service_bundle
      SYSTEM '/usr/share/lib/xml/dtd/service_bundle.dtd.1'>
    <!--
        Manifest created by svcbundle (2013-Apr-10 11:04:28+0300)
    -->
    <service_bundle type="manifest" name="application/mongodb">
        <service version="1" type="service" name="application/mongodb">
            <!--
                The following dependency keeps us from starting until the
                multi-user milestone is reached.
            -->
            <dependency restart_on="none" type="service"
                name="multi_user_dependency" grouping="require_all">
                <service_fmri value="svc:/milestone/multi-user"/>
            </dependency>
            <method_context>
                   <method_credential group="mongodb" user="mongodb"/>
            </method_context>
            <exec_method timeout_seconds="60" type="method" name="start"
                exec="/usr/local/mongodb/bin/mongodb-start"/>
            <!--
                The exec attribute below can be changed to a command that SMF
                should execute to stop the service.  See smf_method(5) for more
                details.
            -->
            <exec_method timeout_seconds="60" type="method" name="stop"
                exec=":kill"/>
            <!--
                The exec attribute below can be changed to a command that SMF
                should execute when the service is refreshed.  Services are
                typically refreshed when their properties are changed in the
                SMF repository.  See smf_method(5) for more details.  It is
                common to retain the value of :true which means that SMF will
                take no action when the service is refreshed.  Alternatively,
                you may wish to provide a method to reread the SMF repository
                and act on any configuration changes.
            -->
            <exec_method timeout_seconds="60" type="method" name="refresh"
                exec=":true"/>
            <!--
                We do not need a duration property group, because contract is
                the default.  Search for duration in svc.startd(1M).
            -->
            <instance enabled="true" name="default"/>
            <template>
                <common_name>
                    <loctext xml:lang="C">
                        <!--
                            Replace this comment with a short name for the
                            service.
                        -->
                    </loctext>
                </common_name>
                <description>
                    <loctext xml:lang="C">
                        <!--
                            Replace this comment with a brief description of
                            the service
                        -->
                    </loctext>
                </description>
            </template>
        </service>
    </service_bundle>
    

    清单 7.MongoDB 服务管理工具清单

  3. 使用以下命令验证清单:

    root@global_zone:~# svccfg validate mongodb.xml
    
  4. 启动 MongoDB 服务:

    root@global_zone:~# svccfg import mongodb.xml
    
  5. 验证 MongoDB 服务是否已经启动:

    root@mongodb-node1:~# svcs mongodb
    STATE          STIME    FMRI
    online         14:51:52 svc:/application/mongodb:default
    
  6. 可以使用以下命令监视 MongoDB 启动消息:

    root@mongodb-node1:~# su - mongodb
    mongodb@mongodb-node1:~ tail -f /var/log/mongodb/mongod.log
    
  7. 运行 mongotop 命令检查 MongoDB 运行,该命令显示 MongoDB 实例读取和写入数据所用的时间:

    mongodb@mongodb-node1:~ /usr/local/mongodb/bin/mongotop
            connected to: 127.0.0.1
    
                                ns       total        read       write   2013-04-08T16:44:12
                 mydb.system.users         0ms         0ms         0ms
                local.system.users         0ms         0ms         0ms
              local.system.replset         0ms         0ms         0ms
              local.system.indexes         0ms         0ms         0ms
                 local.startup_log         0ms         0ms         0ms
            local.replset.minvalid         0ms         0ms         0ms
                    local.oplog.rs         0ms         0ms         0ms
                          local.me         0ms         0ms         0ms
    

    清单 8.验证 MongoDB 是否正在运行

  8. 在全局区域运行以下命令创建 mongodb-node2 区域,作为 mongodb-node1 的克隆:

    root@global_zone:~# zoneadm -z mongodb-node1 shutdown 
    root@global_zone:~# zoneadm -z mongodb-node2 clone mongodb-node1
    
  9. 启动 mongodb-node2 区域:

    root@global_zone:~# zoneadm -z mongodb-node2 boot
    root@global_zone:~# zlogin -C mongodb-node2
    
  10. 与前面一样,系统配置工具启动。然后执行 mongodb-node2 区域的最终配置:

    1. 主机名使用 mongodb-node2
    2. 网络接口使用 mongodb_node2
    3. 使用 IP 地址 192.168.1.2/24。
    4. 确保名称服务设置为 none
  11. 从全局区域对 mongodb-node3 执行类似步骤:

    root@global_zone:~# zoneadm -z mongodb-node3 clone mongodb-node1
    root@global_zone:~# zoneadm -z mongodb-node3 boot
    root@global_zone:~# zlogin -C mongodb-node3
    
  12. 执行 mongodb-node3 区域的最终配置:

    1. 主机名使用 mongodb-node3
    2. 网络接口使用 mongodb_node3
    3. 使用 IP 地址 192.168.1.3/24。
    4. 确保名称服务设置为 none
  13. 启动 mongodb-node1 区域:

    root@global_zone:~# zoneadm -z mongodb-node1 boot
    
  14. 验证所有区域是否启动和运行:

    root@global_zone:~# zoneadm list -cv
     ID NAME          STATUS     PATH                     BRAND    IP
      0 global        running    /                        solaris shared
      1 mongodb-node1 running    /zones/mongodb-node1     solaris  excl
      2 mongodb-node2 running    /zones/mongodb-node2     solaris  excl
      3 mongodb-node3 running    /zones/mongodb-node3     solaris  excl
    

验证名称解析

验证所有 MongoDB 区域在 /etc/hosts 中均有以下主机条目:

# cat /etc/hosts

::1         localhost
127.0.0.1   localhost loghost
192.168.1.1 mongodb-node1             
192.168.1.2 mongodb-node2
192.168.1.3 mongodb-node3

:如果您使用 NTP 服务器,还必须将其主机名和 IP 地址添加到 /etc/hosts

设置 MongoDB 复制

复制通过称为副本集 的服务器组进行。大多数副本集由两个或更多个 mongod 实例组成,其中至多一个指定为主成员,其余作为辅助成员。客户端将所有写入指向主成员,而辅助成员则从主成员异步复制。MongoDB 的数据库复制提供了冗余,有助于确保高可用性。此外,它还简化了备份,可能会增加读取容量。大多数生产部署使用复制。

在本例中,mongodb-node1 将是主成员,mongodb-node2mongodb-node3 将是 rs0 副本集上的辅助成员,如表 4 所示。

表 4.复制配置
主机名 功能 副本集
mongodb-node1 主要 rs0
mongodb-node2 辅助 rs0
mongodb-node3 辅助 rs0

  1. 在每个区域上,使用以下命令验证 MongoDB 实例已经启动并运行:

    root@mongodb-node1:~# svcs mongodb
    STATE          STIME    FMRI
    online         14:51:52 svc:/application/mongodb:default
    
  2. 在第一个节点 (mongodb-node1) 上,使用以下命令连接到 MongoDB shell:

    root@mongodb-node1:~# su - mongodb
    mongodb@mongodb-node1:~ /usr/local/mongodb/bin/mongo
    
  3. 输入以下命令序列,将 mongodb-node1 添加到 rs0 副本集。

    >  rsconf = { _id: "rs0", members: [  {  _id: 0,  host: "mongodb-node1:27017" } ]  }
    

    您会看到以下输出:

    {
            "_id" : "rs0",
            "members" : [
                    {
                            "_id" : 0,
                            "host" : "mongodb-node1:27017"
                    }
            ]
    }
    
  4. 使用以下命令启动一个副本集,它由当前成员组成并使用默认配置:

    > rs.initiate( rsconf )
    

    您会看到以下输出:

    {
            "info" : "Config now saved locally.  Should come online in about a minute.",
            "ok" : 1
    }
    
  5. 显示当前副本集配置:

    > rs.conf()
    

    您应看到以下输出,其中只显示副本集中的一个节点 (mongodb-node1):

    {
            "_id" : "rs0",
            "version" : 1,
            "members" : [
                    {
                            "_id" : 0,
                            "host" : "mongodb-node1:27017"
                    }
            ]
    }
    
  6. 接下来,使用 rs.add() 方法将第二个和第三个实例(mongodb-node2mongodb-node3)添加到 rs0 副本集:

    rs0:PRIMARY>  rs.add("mongodb-node2")
      { "ok" : 1 }
    
    rs0:PRIMARY> rs.add("mongodb-node3")
       { "ok" : 1 }
    
  7. 运行以下命令确保复制配置正确,并检查副本集当前成员之间的连接。

    rs0:PRIMARY> rs.status()
    

    应显示如清单 9 所示的输出:

    {
            "set" : "rs0",
            "date" : ISODate("2013-04-10T08:23:00Z"),
            "myState" : 1,
            "members" : [
                    {
                            "_id" : 0,
                            "name" : "mongodb-node1:27017",
                            "health" : 1,
                            "state" : 1,
                            "stateStr" : "PRIMARY",
                            "uptime" : 536,
                            "optime" : {
                                    "t" : 1365582138,
                                    "i" : 1
                            },
                            "optimeDate" : ISODate("2013-04-10T08:22:18Z"),
                            "self" : true
                    },
                    {
                            "_id" : 1,
                            "name" : "mongodb-node2:27017",
                            "health" : 1,
                            "state" : 2,
                            "stateStr" : "SECONDARY",
                            "uptime" : 58,
                            "optime" : {
                                    "t" : 1365582138,
                                    "i" : 1
                            },
                            "optimeDate" : ISODate("2013-04-10T08:22:18Z"),
                            "lastHeartbeat" : ISODate("2013-04-10T08:22:58Z"),
                            "lastHeartbeatRecv" : ISODate("2013-04-10T08:22:58Z"),
                            "pingMs" : 0
                    },
                    {
                            "_id" : 2,
                            "name" : "mongodb-node3:27017",
                            "health" : 1,
                            "state" : 2,
                            "stateStr" : "SECONDARY",
                            "uptime" : 42,
                            "optime" : {
                                    "t" : 1365582138,
                                    "i" : 1
                            },
                            "optimeDate" : ISODate("2013-04-10T08:22:18Z"),
                            "lastHeartbeat" : ISODate("2013-04-10T08:22:58Z"),
                            "lastHeartbeatRecv" : ISODate("2013-04-10T08:22:59Z"),
                            "pingMs" : 0
                    }
            ],
            "ok" : 1
    }
    

    清单 9.检查复制配置

    您可以从输出看到,mongodb-node1 是主成员,mongodb-node2mongodb-node3 是辅助集群成员。

执行基本数据库操作

MongoDB 数据库保存一组集合。集合保存一组文档。文档是一组键值对。

文档有动态模式,这意味着同一集合中的文档不需要有一组相同的字段或结构,而集合文档中的通用字段可以保存不同类型的数据。

要显示数据库列表,请使用以下命令:

rs0:PRIMARY> show dbs
local   6.0751953125GB

要切换到名为 mydb 的新数据库,请使用以下命令:

:您无需在首次使用数据库之前创建数据库。

rs0:PRIMARY> use mydb
switched to db mydb

要在名为mydb 的新数据库内将文档插入名为 things 的新集合,请执行以下操作:

  1. 使用以下操作序列创建两个名为 jk 的文档:

    rs0:PRIMARY> j = { name : "mongo" }
    { "name" : "mongo" }
    rs0:PRIMARY> k = { x : 3 }
    { "x" : 3 }
    
  2. 使用以下操作序列将 jk 文档插入集合 things

    rs0:PRIMARY> db.things.insert( j )
    rs0:PRIMARY> db.things.insert( k )
    
  3. things 集合执行此查询,确认 things 集合中是否有这两个文档:

    rs0:PRIMARY> db.things.find()
    { "_id" : ObjectId("5162ef329e3aac3f0f6972de"), "name" : "mongo" }
    { "_id" : ObjectId("5162ef3c9e3aac3f0f6972df"), "x" : 3 }
    

    :您的文档 ID 值将有所不同。

  4. 退出 MongoDB shell:

    rs0:PRIMARY> exit
    

检查 MongoDB 集群冗余

我们通过模拟集群节点故障来测试集群弹性。

如果主 MongoDB 实例出现故障或其他集群成员因网络故障而无法连接,MongoDB 集群将启动选举过程,以选出新的集群主节点。

  1. root 用户身份停止 mongodb-node1 区域上的 MongoDB 服务:

    root@global_zone:~# zlogin mongodb-node1
    root@mongodb-node1:~# svcadm disable mongodb
    
  2. 连接到第二个 MongoDB 区域 (mongodb-node2),并运行 MongoDB shell:

    root@global_zone:~# zlogin mongodb-node2
    root@mongodb-node2:~# su - mongodb
    mongodb@mongodb-node2:~ /usr/local/mongodb/bin/mongo
    
  3. 运行 rs.status() 命令获取复制集状态。

    rs0:PRIMARY> rs.status()
    

    您将看到,mongodb-node2 已提升为主节点,而 mongodb-node3 仍为辅助节点。

    :在选举过程中,可以选举不同的主机作为主节点;例如,可以将 mongodb-node3 作为主成员,而将 mongodb-node2 作为辅助成员。您还可以定义优先级,让一个成员的优先级值高于集合中其他成员。请参见 MongoDB 文档中的示例。

  4. mongodb-node1 区域上启动 MongoDB 实例:

    root@global_zone:~# zlogin mongodb-node1
    root@mongodb-node1:~# svcadm enable mongodb
    
  5. 验证 MongoDB 服务已经启动并运行:

    root@mongodb-node1:~# svcs mongodb
           STATE          STIME    FMRI
           online         11:29:09 svc:/application/mongodb:default
    
  6. 连接到 mongodb-node1 区域,并运行 MongoDB shell:

    root@mongodb-node1:~# su - mongodb
    mongodb@mongodb-node1:~ /usr/local/mongodb/bin/mongo
    
  7. 运行 rs.status() 命令获取复制集状态。

    rs0:SECONDARY> rs.status()
    

    您将看到,mongodb-node1 现在是辅助成员,而 mongodb-node3 仍为辅助成员。

    :您的集群成员级别可能因选举过程而不同。

  8. 退出 MongoDB shell:

    rs0:SECONDARY> exit
    
  9. (可选)您可以通过监视 MongoDB 日志文件监视 MongoDB 选举过程:

    mongodb@mongodb-node1:~ tail -f /var/log/mongodb/mongod.log
    

使用 DTrace 提高操作系统的可观察性

MongoDB 软件包括用于分析数据库负载的内置工具。但为了全面了解性能分析过程,除了数据库之外,还需要观察操作系统。Oracle Solaris 包括一个名为 DTrace 的全面的动态跟踪工具。使用此工具,您可以检查用户程序和操作系统自身的行为。

以下示例演示了如何使用 DTrace 分析 MongoDB 数据库负载过程中的 I/O 负载模式。我们将使用 DTrace Toolkit(这是位于 /usr/dtrace/DTT/ 中的一个 DTrace 脚本集合)运行磁盘 I/O 性能分析。

  1. 从 MongoDB shell 使用 rs.status( ) 命令获取 MongoDB 主实例名称。您可以在地址为 http://<mongodb_IPaddress>:28017/_replSet 的 Replica Set Status 页面上找到同样的信息,如图 2 所示。

    图 2

    图 2.Replica Set Status 页面

  2. mongodb 用户身份在主 MongoDB 实例上运行以下命令,在 MongoDB 数据库上生成负载。

    :在本例中,主成员是 mongodb-node2,但也可以是其他主机。

    root@global_zone:~# zlogin mongodb-node2
    root@mongodb-node2:~# su - mongodb
    mongodb@mongodb-node2:~ /usr/local/mongodb/bin/mongo
    
    rs0:PRIMARY> res = benchRun( {      ops : [ {          ns : "test.foo" ,          op : "insert" ,          doc : { y : { "#RAND_STRING" : [ 10 ] } }      } ] ,      parallel : 2 ,      seconds : 1000 ,      totals : true  } );
    

    清单 10.生成负载

    有关详细的负载说明,请参见 http://www.mongodb.org/about/contributors/js-benchmarking-harness/

  3. 从全局区域上的另一个终端运行 DTrace iopattern 脚本(如清单 11 所示),分析磁盘 I/O 负载的类型:

    root@global_zone:~# /usr/dtrace/DTT/iopattern
    %RAN  %SEQ  COUNT   MIN    MAX    AVG     KR     KW
      84   16    196    512 1032704  42302      5   8092
      80   20     98   1024  189952  53221      0   5093
      72   28     68   4096   97280  58910      0   3912
      75   25     77   2048   96256  59910      2   4503
      75   25     72   4096   97280  58887      0   4140
      76   24    180    512 1046016 141405      0  24856
      87   13    110    512  181248  46982    115   4932
      75   25     73   4096   96768  58557    158   4016
      79   21     77   4096   97280  58387      0   4390
      73   27     75   4096  174080  57603    159   4060
      66   34    140    512 1048064 262645      0  35908
      84   16    120    512  437248  36369      0   4262
      79   21     72   4096   97280  58368      0   4104
      75   25     74   2560   97280  57489      2   4152
    

    清单 11.分析负载

    输出中显示以下项:

    • %RAN 是随机事件的百分比。
    • %SEQ 是顺序事件的百分比。
    • COUNT 是 I/O 事件数量。
    • MIN 是最小的 I/O 事件大小。
    • MAX 是最大的 I/O 事件大小。
    • AVG 是平均 I/O 事件大小。
    • KR 是本例中读取的总千字节数。
    • KW 是本例中写入的总千字节数。

    从脚本输出可以看出,I/O 负载主要为随机写入(%RANKW)。

总结

在本文中,我们了解了如何利用 Oracle Solaris 区域、ZFS、DTrace 以及 Oracle Solaris 中的服务管理工具技术构建、观察和管理 MongoDB 数据库集群。

另请参见

另请参见该作者发表的其他文章:

下面是其他 Oracle Solaris 11 资源:

关于作者

Orgad Kimchi 是 Oracle(之前任职于 Sun Microsystems)ISV 工程小组的首席软件工程师。5 年来,他一直专注于虚拟化和云计算技术。

修订版 1.1,2013 年 7 月 18 日

关注我们:
博客 | Facebook | Twitter | YouTube