返回 导航

Docker / K8s

hangge.com

K8s - 安装部署MongoDB数据库教程3(分片集群)

作者:hangge | 2022-02-18 08:03
    我在之前文章中介绍如何在 K8s 上搭建副本集模式的 MongoDB 数据库集群(点击查看),本文接着介绍分片(Sharding)模式。MongoDB 的分片机制允许创建一个包含许多台机器的集群,将数据子集分散在集群中,每个分片维护着一个数据集合的子集。与副本集相比,使用分片集群架构可以使应用程序具有更强大的数据处理能力。
    构建一个 MongoDB 的分片集群,需要三个重要的组件,分别是分片服务器(Shard Server)、配置服务器(Config Server)和路由服务器(Route Server):
  • Shard Server:每个 Shard Server 都是一个 mongod 数据库实例,用于存储实际的数据块。整个数据库集合分成多个块存储在不同的 Shard Server 中。在实际生产中,一个 Shard Server 可由几台机器组成一个副本集来承担,防止因主节点单点故障导致整个系统崩溃。
  • Config Server:这是独立的一个 mongod 进程,保存集群和分片的元数据,在集群启动最开始时建立,保存各个分片包含数据的信息。
  • Route Server:这是独立的一个 mongos 进程,Route Server 在集群中可作为路由使用,客户端由此接入,让整个集群看起来像是一个单一的数据库,提供客户端应用程序和分片集群之间的接口。Route Server 本身不保存数据,启动时从 Config Server 加载集群信息到缓存中,并将客户端的请求路由给每个 Shard Server,在各 Shard Server 返回结果后进行聚合并返回客户端。
    在实际生产环境中,为了满足高可用性和高可扩展性的需求,并不会单纯只采用分片模式。而是将副本集和分片是结合起来使用的,即每一个分片服务器又会由多台机器组成的一个副本集来承担,从而防止某一分片单点故障导致整个系统奔溃。下面通过样例进行演示如何搭建副本集+分片集群模式。

三、分片(Sharding)+ 副本集(Replica Set)集群模式部署

1,创建 NFS 存储

    NFS 存储主要是为了给 MongoDB 提供稳定的后端存储,当 MongoDB 的 Pod 发生故障重启或迁移后,依然能获得原先的数据。
(1)这里我选择在 master 节点创建 NFS 存储,首先执行如下命令安装 NFS
yum -y install nfs-utils
yum -y install rpcbind

(2)接着要创建共享文件夹,因为本次要搭建的集群包含两个分片(每个分片由三个节点组成的副本集承担),同时 Config Server 也由由三个节点组成的副本集承担,而 Route Server 不需要存储数据。所以我们执行如下命令创建 9 个文件夹:
mkdir -p /usr/local/k8s/mongodb/shard/pv1
mkdir -p /usr/local/k8s/mongodb/shard/pv2
mkdir -p /usr/local/k8s/mongodb/shard/pv3
mkdir -p /usr/local/k8s/mongodb/shard/pv4
mkdir -p /usr/local/k8s/mongodb/shard/pv5
mkdir -p /usr/local/k8s/mongodb/shard/pv6
mkdir -p /usr/local/k8s/mongodb/config/pv1
mkdir -p /usr/local/k8s/mongodb/config/pv2
mkdir -p /usr/local/k8s/mongodb/config/pv3

(3)编辑 /etc/exports 文件:
vi /etc/exports

(4)在里面添加如下内容:
/usr/local/k8s/mongodb/shard/pv1 *(rw,sync,no_root_squash)
/usr/local/k8s/mongodb/shard/pv2 *(rw,sync,no_root_squash)
/usr/local/k8s/mongodb/shard/pv3 *(rw,sync,no_root_squash)
/usr/local/k8s/mongodb/shard/pv4 *(rw,sync,no_root_squash)
/usr/local/k8s/mongodb/shard/pv5 *(rw,sync,no_root_squash)
/usr/local/k8s/mongodb/shard/pv6 *(rw,sync,no_root_squash)
/usr/local/k8s/mongodb/config/pv1 *(rw,sync,no_root_squash)
/usr/local/k8s/mongodb/config/pv2 *(rw,sync,no_root_squash)
/usr/local/k8s/mongodb/config/pv3 *(rw,sync,no_root_squash)

(5)保存退出后执行如下命令重启服务:
如果执行 systemctl restart nfs 报“Failed to restart nfs.service: Unit nfs.service not found.”错误,可以尝试改用如下命令:
  • sudo service nfs-server start
systemctl restart rpcbind
systemctl restart nfs
systemctl enable nfs

(6)执行 exportfs -v 命令可以显示出所有的共享目录:

(7)而其他的 Node 节点上需要执行如下命令安装 nfs-utils 客户端:
yum -y install nfs-util

(8)然后其他的 Node 节点上可执行如下命令(ipMaster 节点 IP)查看 Master 节点上共享的文件夹:
showmount -e 10.0.16.8

2,创建 PV 持久卷

(1)我们创建一个名为 mongodb-pv.yaml 的文件,文件中内容如下:
注意:配置里的 IP 地址改成实际 NFS 主机地址。
#创建shard的第1个PV
apiVersion: v1
kind: PersistentVolume
metadata:
name: mongodb-shard-pv1
labels:
app: mongodb
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
storageClassName: mongodb-shard-storage
nfs:
server: 10.0.16.8
path: "/usr/local/k8s/mongodb/shard/pv1"
persistentVolumeReclaimPolicy: Retain
---
#创建shard的第2个PV
apiVersion: v1
kind: PersistentVolume
metadata:
name: mongodb-shard-pv2
labels:
app: mongodb
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
storageClassName: mongodb-shard-storage
nfs:
server: 10.0.16.8
path: "/usr/local/k8s/mongodb/shard/pv2"
persistentVolumeReclaimPolicy: Retain
---
#创建shard的第3个PV
apiVersion: v1
kind: PersistentVolume
metadata:
name: mongodb-shard-pv3
labels:
app: mongodb
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
storageClassName: mongodb-shard-storage
nfs:
server: 10.0.16.8
path: "/usr/local/k8s/mongodb/shard/pv3"
persistentVolumeReclaimPolicy: Retain
---
#创建shard的第4个PV
apiVersion: v1
kind: PersistentVolume
metadata:
name: mongodb-shard-pv4
labels:
app: mongodb
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
storageClassName: mongodb-shard-storage
nfs:
server: 10.0.16.8
path: "/usr/local/k8s/mongodb/shard/pv4"
persistentVolumeReclaimPolicy: Retain
---
#创建shard的第5个PV
apiVersion: v1
kind: PersistentVolume
metadata:
name: mongodb-shard-pv5
labels:
app: mongodb
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
storageClassName: mongodb-shard-storage
nfs:
server: 10.0.16.8
path: "/usr/local/k8s/mongodb/shard/pv5"
persistentVolumeReclaimPolicy: Retain
---
#创建shard的第6个PV
apiVersion: v1
kind: PersistentVolume
metadata:
name: mongodb-shard-pv6
labels:
app: mongodb
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
storageClassName: mongodb-shard-storage
nfs:
server: 10.0.16.8
path: "/usr/local/k8s/mongodb/shard/pv6"
persistentVolumeReclaimPolicy: Retain
---
#创建config的第1个PV
apiVersion: v1
kind: PersistentVolume
metadata:
name: mongodb-config-pv1
labels:
app: mongodb
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
storageClassName: mongodb-config-storage
nfs:
server: 10.0.16.8
path: "/usr/local/k8s/mongodb/config/pv1"
persistentVolumeReclaimPolicy: Retain
---
#创建config的第2个PV
apiVersion: v1
kind: PersistentVolume
metadata:
name: mongodb-config-pv2
labels:
app: mongodb
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
storageClassName: mongodb-config-storage
nfs:
server: 10.0.16.8
path: "/usr/local/k8s/mongodb/config/pv2"
persistentVolumeReclaimPolicy: Retain
---
#创建config的第3个PV
apiVersion: v1
kind: PersistentVolume
metadata:
name: mongodb-config-pv3
labels:
app: mongodb
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
storageClassName: mongodb-config-storage
nfs:
server: 10.0.16.8
path: "/usr/local/k8s/mongodb/config/pv3"
persistentVolumeReclaimPolicy: Retain

(2)接着执行如下命令开始创建:
kubectl apply -f mongodb-pv.yaml

(3)最后执行如下命令查看所有 pv,可以看到 9 个持久卷均已创建成功:
kubectl get pv

3,部署 config server(配置服务器)

(1)首先创建一个名为 mongodb-config.yaml 的配置文件,文件里的内容如下:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mongodb-config
spec:
selector:
matchLabels:
app: mongodb-config
serviceName: "mongodb-config-hs"
replicas: 3
template:
metadata:
labels:
app: mongodb-config
spec:
terminationGracePeriodSeconds: 10
containers:
- name: mongodb-config
image: mongo:4.4
command:
- mongod
- "--port"
- "27017"
- "--configsvr"
- "--replSet"
- "configs"
- "--bind_ip"
- 0.0.0.0
ports:
- containerPort: 27017
volumeMounts:
- name: mongdb-config-persistent-storage
mountPath: /data/configdb
volumeClaimTemplates:
- metadata:
name: mongdb-config-persistent-storage
spec:
storageClassName: mongodb-config-storage
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
# headless 无头服务(提供域名供StatefulSet内部pod访问使用)
apiVersion: v1
kind: Service
metadata:
name: mongodb-config-hs
labels:
name: mongodb-config
spec:
ports:
- port: 27017
targetPort: 27017
clusterIP: None
selector:
app: mongodb-config

(2)接着执行如下命令对这个 YAML 文件进行部署:
kubectl apply -f mongodb-config.yaml

(3)稍等片刻,执行如下命令可以查看是否创建成功:
kubectl get pods
kubectl get service

(4)执行如下命令可以看到前面创建的 pvpod 也进行了关联:
kubectl get pv

(5)虽然我们已经创建了三个 Pod 实例,但它们目前还是相互独立的,接下来我们要将它们组建成集群。首先进入任意一个 Pod
kubectl exec -it mongodb-config-0 /bin/bash

(6)接着执行如下命令连接上任意一个实例:
bin/mongo mongodb-config-0.mongodb-config-hs.default.svc.cluster.local:27017

(7)接着执行如下命令开始配置副本集:
各参数说明:
  • cfg 是可以任意的名字,当然最好不要是 mongodb 的关键字,confconfig 都可以。
  • 最外层的 _id 表示 replica set 的名字(由于前面 yaml 文件中我们设置 replica set 的名字为 configs,所以这里也要保持一致)
  • members 里包含的是所有节点的地址。
cfg = {
    _id : "configs",
    members : [
    {_id : 0, host : "mongodb-config-0.mongodb-config-hs.default.svc.cluster.local:27017" },
    {_id : 1, host : "mongodb-config-1.mongodb-config-hs.default.svc.cluster.local:27017" },
    {_id : 2, host : "mongodb-config-2.mongodb-config-hs.default.svc.cluster.local:27017" }
    ]
}

(8)最后执行如下命令使配置生效:
rs.initiate(cfg)

(9)稍等一会执行如下命令查看副本集状态:
rs.status()

(10)可以看到 configs 副本集中已经有一个 Primary 节点和两个 Secondary 节点,说明副本集的启动配置已完成。

4,部署 shard server(分片服务器)

(1)首先创建一个名为 mongodb-shard.yaml 的配置文件,文件里的内容如下:
# 第1个分片(每个分片有3个副本)
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mongodb-shard0
spec:
selector:
matchLabels:
app: mongodb-shard
serviceName: "mongodb-shard-hs"
replicas: 3
template:
metadata:
labels:
app: mongodb-shard
spec:
terminationGracePeriodSeconds: 10
containers:
- name: mongodb-shard
image: mongo:4.4
command:
- mongod
- "--port"
- "27017"
- "--shardsvr"
- "--replSet"
- shard0
- "--bind_ip"
- 0.0.0.0
ports:
- containerPort: 27017
volumeMounts:
- name: mongdb-shard-persistent-storage
mountPath: /data/db
volumeClaimTemplates:
- metadata:
name: mongdb-shard-persistent-storage
spec:
storageClassName: mongodb-shard-storage
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
# 第2个分片(每个分片有3个副本)
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mongodb-shard1
spec:
selector:
matchLabels:
app: mongodb-shard
serviceName: "mongodb-shard-hs"
replicas: 3
template:
metadata:
labels:
app: mongodb-shard
spec:
terminationGracePeriodSeconds: 10
containers:
- name: mongodb-shard
image: mongo:4.4
command:
- mongod
- "--port"
- "27017"
- "--shardsvr"
- "--replSet"
- shard1
- "--bind_ip"
- 0.0.0.0
ports:
- containerPort: 27017
volumeMounts:
- name: mongdb-shard-persistent-storage
mountPath: /data/db
volumeClaimTemplates:
- metadata:
name: mongdb-shard-persistent-storage
spec:
storageClassName: mongodb-shard-storage
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
# headless 无头服务(提供域名供StatefulSet内部pod访问使用)
apiVersion: v1
kind: Service
metadata:
name: mongodb-shard-hs
labels:
name: mongodb-shard
spec:
ports:
- port: 27017
targetPort: 27017
clusterIP: None
selector:
app: mongodb-shard

(2)接着执行如下命令对这个 YAML 文件进行部署:
kubectl apply -f mongodb-shard.yaml

(3)稍等片刻,执行如下命令可以查看是否创建成功:
kubectl get pods
kubectl get service

(4)执行如下命令可以看到前面创建的 pvpod 也进行了关联:
kubectl get pv

(5)虽然我们已经创建了两个分片共六个 Pod 实例,但它们目前还是相互独立的,接下来我们要将它们组建成集群。首先配置第一个分片,进入该分片里任意一个 Pod
kubectl exec -it mongodb-shard0-0 /bin/bash

(6)接着执行如下命令连接上任意一个实例:
bin/mongo mongodb-shard0-0.mongodb-shard-hs.default.svc.cluster.local:27017

(7)连接成功后执行如下命令:
use adminrs

(8)接着执行如下命令开始配置副本集:
cfg = {_id: "shard0",members:[{_id: 0,host: 'mongodb-shard0-0.mongodb-shard-hs.default.svc.cluster.local:27017',priority: 3},{_id: 1,host: 'mongodb-shard0-1.mongodb-shard-hs.default.svc.cluster.local:27017',priority: 2},{_id: 2,host: 'mongodb-shard0-2.mongodb-shard-hs.default.svc.cluster.local:27017',priority: 1}]};

(9)最后执行如下命令使配置生效:
rs.initiate(cfg)

(10)稍等一会执行如下命令查看副本集状态,可以看到第一个分片中已经有一个 Primary 节点和两个 Secondary 节点:
rs.status()

(11)接着配置第二个分片,进入该分片里任意一个 Pod
kubectl exec -it mongodb-shard1-0 /bin/bash

(12)接着执行如下命令连接上任意一个实例:
bin/mongo mongodb-shard1-0.mongodb-shard-hs.default.svc.cluster.local:27017

(13)连接成功后执行如下命令:
use adminrs

(14)接着执行如下命令开始配置副本集:
cfg = {_id: "shard1",members:[{_id: 0,host: 'mongodb-shard1-0.mongodb-shard-hs.default.svc.cluster.local:27017',priority: 3},{_id: 1,host: 'mongodb-shard1-1.mongodb-shard-hs.default.svc.cluster.local:27017',priority: 2},{_id: 2,host: 'mongodb-shard1-2.mongodb-shard-hs.default.svc.cluster.local:27017',priority: 1}]};

(15)最后执行如下命令使配置生效:
rs.initiate(cfg)

(16)稍等一会执行如下命令查看副本集状态,可以看到第二个分片中已经有一个 Primary 节点和两个 Secondary 节点:
rs.status()

5,部署 route server(mongos 路由服务器)

(1)首先创建一个名为 mongodb-mongos.yaml 的配置文件,文件里的内容如下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: mongodb-mongos
spec:
selector:
matchLabels:
app: mongodb-mongos
replicas: 1
template:
metadata:
labels:
app: mongodb-mongos
spec:
terminationGracePeriodSeconds: 10
containers:
- name: mongodb-mongos
image: mongo:4.4
command:
- mongos
- "--port"
- "27017"
- "--configdb"
- "configs/mongodb-config-0.mongodb-config-hs.default.svc.cluster.local:27017,mongodb-config-1.mongodb-config-hs.default.svc.cluster.local:27017,mongodb-config-2.mongodb-config-hs.default.svc.cluster.local:27017"
- "--bind_ip"
- 0.0.0.0
ports:
- containerPort: 27017
---
# 标准服务(供外部访问)
apiVersion: v1
kind: Service
metadata:
name: mongodb-mongos-svc
labels:
name: mongodb-mongos
spec:
type: NodePort
ports:
- port: 27017
targetPort: 27017
nodePort: 30717
selector:
app: mongodb-mongos
 

(2)接着执行如下命令对这个 YAML 文件进行部署:
kubectl apply -f mongodb-mongos.yaml

(3)稍等片刻,执行如下命令可以查看是否创建成功:
kubectl get pods
kubectl get service

(4)接着将路由服务器和分片副本集串联起来,首先进入 Pod
注意:由于是使用 Deployment 方式部署,所以 Pod 名字并不固定。
kubectl exec -it mongodb-mongos-7f96455696-wbrlc /bin/bash

(5)接着执行如下命令连接服务:
bin/mongo --port 27017

(6)执行如下命令使用 admin 数据库:
use admin

(7)执行如下命令将副本集添加到分片集中:
sh.addShard("shard0/mongodb-shard0-0.mongodb-shard-hs.default.svc.cluster.local:27017,mongodb-shard0-1.mongodb-shard-hs.default.svc.cluster.local:27017,mongodb-shard0-2.mongodb-shard-hs.default.svc.cluster.local:27017");
sh.addShard("shard1/mongodb-shard1-0.mongodb-shard-hs.default.svc.cluster.local:27017,mongodb-shard1-1.mongodb-shard-hs.default.svc.cluster.local:27017,mongodb-shard1-2.mongodb-shard-hs.default.svc.cluster.local:27017");

(8)然后执行如下命令查看集群状态:
sh.status()

附:分片测试

(1)由于并不是所有数据库和集合都需要分片。所以要对一个集合分片,首先要对这个集合的数据库启用分片,我们连接 route server
kubectl exec -it mongodb-mongos-7f96455696-wbrlc /bin/bash
bin/mongo --port 27017

(2)执行如下命令使用 admin 数据库:
use admin

(3)假设我们需要让 hangge 这个数据库启用分片,只需要执行如下命令,便可以对该数据库内的集合进行分片了:
sh.enableSharding("hangge")

(4)对集合分片时,我们要选择一个分片键(shard key)。分片键是集合的一个键,MongoDB 根据这个键拆分数据。执行下面命令让 users 集合依据 username 对集合进行分片: 
(1)mongodb 提供了 2 种策略来对集合进行分片:
  • 范围(range)分片:可以使用多个字段作为分片键,并将数据划分为由分片键确定的连续范围。如:sh.shardCollection("hangge.users", {"username" : 1})
  • 哈希(hash)分片:对单列使用 hash 索引作为分片键。如:sh.shardCollection("hangge.users", {"username" : "hashed"})
(2)shard key 上必须有索引(可以是以 shard key 开头的联合索引),如何集合不存在插入数据时 mongodb 会为 shard key 创建索引。但如果是已经存在的集合那么必须手动为 shard key 创建索引。

sh.shardCollection("hangge.users", {"username" : "hashed"})

(5)切换到 hangge 数据库:
use hangge

(6)接着执行如下命令往 user 集合中插入 5.5 千条数据:
for(var i=100000;i<105500;i++){ 
  db.users.insert({"username" : "user"+i , "created_at" : new Date()}); 
}

(7)数据插入完毕后执行如下命令查看 users 集合的分片情况,可以发现数据已经均匀分布在两个分片上了:
db.users.getShardDistribution()

(8)而执行如下命令可以看到各个 chunk 包含的数据范围以及对应分片信息:
提示:由于 chunks 数量比较多,所以我们加了个 verbose 参数保证所有信息都能打印出来。否则会报“mongoDB sh.status() too many chunks to print
sh.status({"verbose":1})
评论

全部评论(0)

回到顶部