高可用的MongoDB集群

2018-01-23 09:53:10
前言

MongoDB是一个介于关系数据库和非关系数据库之间的产品,适合存储对象及JSON形式的数据。支持丰富的查询方式,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。

mongo适用的场景:

  • 网站数据:Mongo 非常适合实时的插入,更新与查询,并具备网站实时数据存储所需的复制及高度伸缩性
  • 缓存:由于性能很高,Mongo 也适合作为信息基础设施的缓存层
  • 高伸缩性的场景:Mongo非常适合由数十或数百台服务器组成的数据库
  • 用于对象及JSON数据的存储:Mongo的BSON数据格式非常适合文档格式化的存储及查询

MongDB不适合的场景:

  • 高度事务性的系统:例如银行或会计系统。
  • 传统的商业智能应用:针对特定问题的 BI 数据库会对产生高度优化的查询方式。对于此类应用,数据仓库可能时更适合的选择(如Hadoop套件中的Hive)
MongDB 概念

首先了解几个概念:路由,分片、副本集、配置服务器等
mongodb支持数据的分布式存储,将collection作数据分片,减少每个节点的数据负载。
每个节点可以位于不同的物理机器上,一个简单的sharding集群如下图所示(引用自mongodb官网)
mongdb
从图中可以看到有四个组件:mongos、config server、shard、replica set。

mongos,数据库集群请求的入口,所有的请求都通过mongos进行协调,不需要在应用程序添加一个路由选择器,mongos自己就是一个请求分发中心,它负责把对应的数据请求请求转发到对应的shard服务器上。在生产环境通常有多mongos作为请求的入口,防止其中一个挂掉所有的mongodb请求都没有办法操作。

config server,顾名思义为配置服务器,存储所有数据库元信息(路由、分片)的配置。mongos本身没有物理存储分片服务器和数据路由信息,只是缓存在内存里,配置服务器则实际存储这些数据。mongos第一次启动或者关掉重启就会从 config server 加载配置信息,以后如果配置服务器信息变化会通知到所有的 mongos 更新自己的状态,这样 mongos 就能继续准确路由。在生产环境通常有多个 config server 配置服务器,因为它存储了分片路由的元数据,防止数据丢失!

shard,分片(sharding)是指将数据库拆分,将其分散在不同的机器上的过程。将数据分散到不同的机器上,不需要功能强大的服务器就可以存储更多的数据和处理更大的负载。基本思想就是将集合切成小块,这些块分散到若干片里,每个片只负责总数据的一部分,最后通过一个均衡器来对各个分片进行均衡(数据迁移)。

replica set,中文翻译副本集,其实就是shard的备份,防止shard挂掉之后数据丢失。复制提供了数据的冗余备份,并在多个服务器上存储数据副本,提高了数据的可用性, 并可以保证数据的安全性。

仲裁者(Arbiter),是复制集中的一个MongoDB实例,它并不保存数据。仲裁节点使用最小的资源并且不要求硬件设备,不能将Arbiter部署在同一个数据集节点中,可以部署在其他应用服务器或者监视服务器中,也可部署在单独的虚拟机中。为了确保复制集中有奇数的投票成员(包括primary),需要添加仲裁节点做为投票,否则primary不能运行时不会自动切换primary。

简单了解之后,我们可以这样总结一下,应用请求mongos来操作mongodb的增删改查,配置服务器存储数据库元信息,并且和mongos做同步,数据最终存入在shard(分片)上,为了防止数据丢失同步在副本集中存储了一份,仲裁在数据存储到分片的时候决定存储到哪个节点。

环境准备

九台测试服务器,操作系统centos6.8, MongoDB 3.6

服务器角色分配
192.168.1.100 config server
192.168.1.101 config server
192.168.1.102 config server

192.168.1.103 shard server1
192.168.1.104 shard server1 副节点
192.168.1.105 shard server1 仲裁

192.168.1.107 shard server2
192.168.1.108 shard server2 副节点
192.168.1.109 shard server2 仲裁

192.168.1.110 mongos

集群搭建
  • Install MongoDB on All Nodes

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    cat > /etc/yum.repos.d/mongodb-org-3.6.repo << 'EOF'
    [mongodb-org-3.6]
    name=MongoDB Repository
    baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/3.6/x86_64/
    gpgcheck=1
    enabled=1
    gpgkey=https://www.mongodb.org/static/pgp/server-3.6.asc
    EOF

    Package Name Description
    mongodb-org A metapackage that will automatically install the four component packages listed below.
    mongodb-org-server Contains the mongod daemon and associated configuration and init scripts.
    mongodb-org-mongos Contains the mongos daemon.
    mongodb-org-shell Contains the mongo shell.
    mongodb-org-tools Contains the following MongoDB tools: mongoimport bsondump, mongodump, mongoexport, mongofiles, mongoperf, mongorestore, mongostat, and mongotop.


    yum -y install mongodb-org
  • Configure Firewalld

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #for centos6,add under to file  /etc/sysconfig/iptables
    cat /etc/sysconfig/iptables
    -A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
    -A INPUT -p tcp -m state --state NEW -m tcp --dport 27017 -j ACCEPT
    service iptables restart
    #for centos7
    yum -y install firewalld
    systemctl start firewalld
    systemctl enable firewalld

    firewall-cmd --permanent --add-port=22/tcp
    firewall-cmd --permanent --add-port=27017/tcp
    firewall-cmd --reload
  • Configure MongoDB config server

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    net:
    port: 27017
    bindIP: 127.0.0.1,192.168.1.101
    #declare this is a config db of a cluster;
    sharding:
    clusterRole: configsvr
    replication:
    replSetName: configs

    #登录任意一台配置服务器,初始化配置副本集

    #连接
    mongo --port 27017
    #config变量
    config = {
    _id : "configs",
    members : [
    {_id : 0, host : "192.168.1.100:27017" },
    {_id : 0, host : "192.168.1.101:27017" },
    {_id : 1, host : "192.168.1.102:27017" }
    ]
    }

    #初始化副本集
    rs.initiate(config)

    其中,”_id” : “configs”应与配置文件中配置的 replicaction.replSetName 一致,”members” 中的 “host” 为三个节点的 ip 和 port

  • Configure MongoDB Replica Set

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    vim /etc/mongod.conf

    net:
    port: 27017
    bindIP: 127.0.0.1,192.168.1.103

    replication:
    replSetName: "shard1"
    sharding:
    clusterRole: shardsvr

    mongo --port 27017
    #使用admin数据库
    use admin
    #定义副本集配置
    config = {
    _id : "shard1",
    members : [
    {_id : 0, host : "192.168.1.103:27017" },
    {_id : 1, host : "192.168.1.104:27017" },
    {_id : 2, host : "192.168.1.105:27017", arbiterOnly: true }
    ]
    }
    #初始化副本集配置
    rs.initiate(config);

    第二个Replica Set也执行类似操作

  • Configure MongoDB mongos

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    [root@localhost ~]# cat mongos.conf 
    # where to write logging data.
    systemLog:
    destination: file
    logAppend: true
    path: /var/log/mongodb/mongos.log

    #security:
    #keyFile: /opt/mongo/mongodb-keyfile

    port=27017
    bind_ip=127.0.0.1,172.16.56.233
    #监听的配置服务器,只能有1个或者3个 configs为配置服务器的副本集名字
    configdb=configs/192.1688.1.100:27017,192.1688.1.101:27017,192.168.1.102:27017

    mongos --config mongos.conf --fork
  • MongoDB Replica Set initiate

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    登陆任意一台mongos

    mongo --port 27017
    #使用admin数据库
    use admin
    #串联路由服务器与分配副本集
    sh.addShard("shard1/192.168.1.103:27017,192.168.1.104:27017,192.168.1.105:27017")
    sh.addShard("shard2/192.168.1.106:27017,192.168.1.107:27017,192.168.1.108:27017")
    #查看集群状态
    sh.status()
  • Test the Replication

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    use admin
    #指定testdb分片生效
    sh.enableSharding( "testdb" )

    #Before sharding a non-empty collection, create an index on the shard key.
    use testdb
    db.table1.createIndex( { id : 1 } )

    #指定数据库里需要分片的集合和片键
    use testdb
    sh.shardCollection( "testdb.table1", { id : 1 } )

    #Confirm the shard is balancing
    use testdb
    db.stats()
    db.printShardingStatus()

    我们设置testdb的 table1 表需要分片,根据 id 自动分片到 shard1 ,shard2 上面去。要这样设置是因为不是所有mongodb 的数据库和表 都需要分片!
    测试分片配置结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    mongo  127.0.0.1:27017
    #使用testdb
    use testdb;
    #插入测试数据
    for (var i = 1; i <= 600000; i++)db.table1.save({id:i,"test1":"testval1"});
    #查看分片情况如下,部分无关信息省掉了
    mongos> db.printShardingStatus()
    --- Sharding Status ---
    sharding version: {
    "_id" : 1,
    "minCompatibleVersion" : 5,
    "currentVersion" : 6,
    "clusterId" : ObjectId("5a674706887e9c5d977acacc")
    }
    shards:
    { "_id" : "shard1", "host" : "shard1/192.168.1.103:27017,192.168.1.104:27017", "state" : 1 }
    { "_id" : "shard2", "host" : "shard2/192.168.1.106:27017,192.168.1.107:27017", "state" : 1 }
    active mongoses:
    "3.6.2" : 1
    autosplit:
    Currently enabled: yes
    balancer:
    Currently enabled: yes
    Currently running: no
    Failed balancer rounds in last 5 attempts: 0
    Migration Results for the last 24 hours:
    No recent migrations
    databases:
    { "_id" : "config", "primary" : "config", "partitioned" : true }
    config.system.sessions
    shard key: { "_id" : 1 }
    unique: false
    balancing: true
    chunks:
    shard1 1
    { "_id" : { "$minKey" : 1 } } -->> { "_id" : { "$maxKey" : 1 } } on : shard1 Timestamp(1, 0)

    { "_id" : "testdb", "primary" : "shard1", "partitioned" : true }
    testdb.table1
    shard key: { "id" : 1 }
    unique: false
    balancing: true
    chunks:
    shard1 1
    { "id" : { "$minKey" : 1 } } -->> { "id" : { "$maxKey" : 1 } } on : shard1 Timestamp(1, 0)

    可以看到目前只有一个chunk在shard1整个shard上

遇到的错误
1
2
3
4
5
6
7
 rs.initiate(config);
{
"ok" : 0,
"errmsg" : "Attempting to initiate a replica set with name shard2, but command line reports shard1; rejecting",
"code" : 93,
"codeName" : "InvalidReplicaSetConfig"
}

解决方案: 由于配置replSetName错误引起

常用命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#List Databases with Sharding Enabled
use config
db.databases.find( { "partitioned": true } )

#List Shards
db.adminCommand( { listShards: 1 } )
#remove shard
db.adminCommand( { removeShard: "testdb" } )

#View Cluster Details
db.printShardingStatus() or sh.status()

#drop database
use newdb
switched to db newdb
db.dropDatabase()

ref
mongoDB-3.x Sharding with Replica
From Replica Set to Sharding
通过一步步创建sharded cluster来认识mongodb


您的鼓励是我写作最大的动力

俗话说,投资效率是最好的投资。 如果您感觉我的文章质量不错,读后收获很大,预计能为您提高 10% 的工作效率,不妨小额捐助我一下,让我有动力继续写出更多好文章。