MongoDB是一个基于分布式文件存储的数据库。由 C++ 语言编写,旨在简化用户开发和扩展。MongoDB 中的记录的数据结构类似一个文档,它是由字段和值对组成的。MongoDB 文档类似于 JSON 对象。字段的值可能包括其他文档、数组和文档数组。
图片来源:https://mongodb.net.cn/Upload/crud-annotated-document.bakedsvg.svg
它的主要特征如下:
高性能
MongoDB提供高性能的数据持久性。针对嵌入式数据模型,支持减少了数据库系统上的 I /O 活动,及通过索引支持更快的查询,并且可以包括来自嵌入式文档和数组的键。
丰富的查询语言
MongoDB 查询 API,提供丰富的查询语言,以支持读写操作,同时 MongoDB 还保留了关系型数据库即时查询的能力,保留了索引(底层是基于 Btree)的能力,相比于同类型的 NoSQL redis 并没有上述的能力。
高可用性
MongoDB 自身提供了副本集,能将数据分布在多台机器上实现冗余,目的是可以提供自动故障转移、扩展读能力。
一个副本集是一组维护相同数据集的 MongoDB 服务器,提供冗余并增加数据可用性。
水平可扩展性
MongoDB 提供水平可伸缩性功能,使用分片技术对数据进行扩展,MongoDB 能自动分片、自动转移分片里面的数据块,让每一个服务器里面存储的数据都是一样大小。
支持多种存储引擎
MongoDB 支持多个存储引擎,如 WiredTiger 和内存中存储引擎。此外,MongoDB 提供灵活的存储引擎 API,允许第三方为 MongoDB 开发存储引擎。
Standalone 模式:单点模式,单节点模式指运行在服务器上的一个 mongod 进程,用于读写数据。用户快速部署一个 MongoDB 单节点服务器,用于日常的开发、测试和学习等。
Replica Set 模式:副本集模式,一个副本集是一组 mongod 的实例集合,维护着相同的数据集,主要包含三类节点角色,如下图:
图片来源:https://mongodb.net.cn/Upload/replica-set-primary-with-two-secondaries.bakedsvg.svg
a. Primary 主节点
一个 Replica Set 可以有多个 Secondary 成员,但有且仅有一个节点是 Primary 节点,只有 Primary 节点是可读可写的,用户也可以修改配置,设置 Primary 节点只负责写入操作,而使 Secondary 节点负责读取操作,实现数据集的读写分离;
客户端在 Primary 节点上进行读写操作,然后通过 Replication 的异步同步机制,将数据同步到所有 Secondary 成员。在一定的时间之后,所有 Secondary 成员将拥有相同的数据集。
当 Primary 挂掉或不可用后,即 Replica Set 探测到 Primary 不可访问时,将启动自动故障转移进程,从其他的 Secondary 成员中,由 Secondary 或者 Arbiter (仲裁)节点投票选举出一个新成员作为 Primary,接收和处理客户端的请求,从而可以为用户继续提供服务了。
b. Secondary 副本节点
副本节点的主要功能是做数据的备份,当主节点不可用的时候,参与选主。副本节点之间相互有心跳监听,可以感知集群的整体状态,同时也可以作为数据源,为用户提供查询的功能。
c. Arbiter 仲裁节点
仲裁节点的特点主要是不存数据,不会被选为主,只进行选主投票功能。使用Arbiter 作用是可以减少数据的冗余备份,节省资源,又可以提供高可用的能力。
Sharding 模式:分片集群模式,分片是一种跨多台机器分发数据的方法。其实就是 MongoDB 横向扩容的一个整体架构实现,MongoDB 使用分片来支持具有非常大的数据集和高吞吐量操作的部署。解决 MongoDB 的性能和容量瓶颈等系统增长问题。
一个 MongoDB 分片集群,由 shard、mongos 和 config servers 三个组件组成。
图片来源:https://mongodb.net.cn/manual/sharding/
1. mongos:mongos 充当查询路由的角色,为客户端应用程序和分片集群间的通信提供一个接口。向上对接客户端 Client,当收到写请求的时,按照特定算法,将请求下发到某一个 Shard 集群,写入数据。当收到读请求的时,通过定位找到要读的数据对象在哪个 Shard 上,把请求转发到这个 Shard 上,读取数据。
2. shard:是存储数据的地方,每个分片存储的数据是分片集群的数据集中的一个子集。从 MongoDB 3.6 版本开始,每个分片必须部署为副本集架构。理论上,副本集集群的个数是可以无限增长的。
3. config servers: Config servers(配置服务器)主要存储了分片集群的元数据和配置信息。从 MongoDB 3.4 版本开始,config servers 也必须部署为副本集架构。
通过以上介绍,我们可知分片集群模式的主要特点,就是可以将数据集分成多个数据块,存储在不同的分片节点上。当数据量大量增加的时候,用户可以通过添加分片来实现扩容功能。同时,分片集群模式支持多主多从的能力,不同的分片的主节点处理不同的请求;每个分片的主从之间可以进行数据的同步和备份,当一个分片的主节点不可用时,也可以自动的进行选主功能,且在选主过程中,其他的分片主节点亦可对用户提供服务。
可以通过 CR 快速部署单点模式的 MongoDB 容器;
可以自动维护 MongoDB 实例节点状态;
可以调整 MongoDB 的配置文件;
可以设置 MongoDB 资源大小;
支持 MongoDB 镜像版本的设置;
支持设置 MongoDB 的 root 密码;
支持用户设置自定义数据库、用户和密码;
可以备份,备份快照数据支持放入 S3 存储;
可以设置备份计划,定时创建备份快照;
支持 MongoDB 数据的持久化, 使用支持 storageClass 方式的 PVC;
支持更新/删除 MongoDB 服务实例;
支持查看 MongoDB 服务的慢日志查询;
支持查看 MongoDB 服务事件查询;
支持对外可访问;
支持 Statefulset、Service、Pod 等资源对象的常见操作;
支持查看 MongoDB 实例 Pod 的实时日志和离线日志;
支持 Pod 的 exec 能力;
支持下载 Pod 中的日志文件;
支持 MongoDB 的常见能力的运维操作,如查看 mongo 的状态、配置信息、快速搜索等;
可以设置监控的资源配置,监控 MongoDB 实例的运行情况。
可以通过 CR 快速部署副本集模式的 MongoDB 容器;
可以自动维护 MongoDB 实例节点状态;
可以调整 MongoDB 的配置文件;
可以设置 MongoDB 资源大小;
支持 MongoDB 镜像版本的设置;
支持设置 MongoDB 的 root 密码;
支持用户设置自定义数据库、用户和密码;
支持设置仲裁节点;
支持快速扩缩容;
保证部署的排它能力,避免重要的服务跑在一台机器;
可以备份,备份快照数据支持放入 S3 存储;
可以设置备份计划,定时创建备份快照;
支持 MongoDB 数据的持久化, 使用支持 storageClass 方式的 PVC;
支持更新/删除 MongoDB 服务实例;
支持查看 MongoDB 服务的慢日志查询;
支持查看 MongoDB 服务事件查询;
支持对外可访问;
支持 Statefulset、Service、Pod 等资源对象的常见操作;
支持查看 MongoDB 实例 Pod 的实时日志和离线日志;
支持 Pod 的 exec 能力;
支持下载 Pod 中的日志文件;
支持查看 Mongo 节点的拓扑图;
支持手动切换 Mongo 主节点,及查看主从节点切换记录;
支持 MongoDB 的常见能力的运维操作,如查看 mongo 的状态、配置信息、插入数据等;
可以设置监控的资源配置,监控 MongoDB 实例的运行情况。
可以通过 CR 快速部署分片模式的 MongoDB 容器;
可以自动维护 MongoDB 实例节点状态;
可以调整 MongoDB 的配置文件;
可以设置 MongoDB 资源大小;
支持 MongoDB 镜像版本的设置;
支持设置 MongoDB 的 root 密码;
支持用户设置自定义数据库、用户和密码;
支持设置仲裁节点;
支持设置 mongo 路由以及配置中心的数量;
保证部署的排它能力,避免重要的服务跑在一台机器;
可以备份,备份快照数据支持放入 S3 存储;
可以设置备份计划,定时创建备份快照;
支持 MongoDB 数据的持久化, 使用支持 storageClass 方式的 PVC;
支持更新/删除 MongoDB 服务实例;
支持查看 MongoDB 服务的慢日志信息查询;
支持查看 MongoDB 服务事件查询;
支持 Statefulset、Service、Pod 等资源对象的常见操作;
支持查看 MongoDB 实例 Pod 的实时日志和离线日志;
支持 Pod 的 exec 能力;
支持下载 Pod 中的日志文件;
支持查看 Mongo 节点的拓扑图;
支持手动切换 Mongo 主节点,及查看主从节点切换记录;
支持 MongoDB 的常见能力的运维操作,如查看 mongo 的状态、配置信息、插入数据等;
可以设置监控的资源配置,监控 MongoDB 实例的运行情况。
以下介绍了 MongoDB 组建成高可用集群的两种模式,分别在当前 operator 中的设计方案:
副本集模式方案:使用 K8s 的 service 的 NodePort 方式作为外部连接的入口。用户可以通过集群外部连接地址访问 mongo 服务,通过 mongoDB Client 客户端本身的能力来发现 master 节点。
分片模式方案:在 mongo 高可用分片集群模式中,客户端访问的方式,设置一组 mongos 地址,由 mongo 客户端来连接和使用集群。mongod 存储了分片集群的数据和配置信息,保证状态一致。同时这些地址是外部可达的,也支持集群外部的服务连接访问。
MongoDB Operator 的实现基于 Operator SDK 技术框架来完成。通过 Operator 实现 Mongo 服务实例、备份、主从切换等 CRD 的定义,及通过 Operator Controller 中的 Reconcile,对 Mongo CR 实例运行状态进行监听,从而不断的调整和修复 Mongo CR,直到达到期望的状态,同时它还包含了对 Mongo 服务以及 Operator 的监控功能。
以下主要从 Opertaor 部署、功能开发、持续优化三个阶段,介绍 MongoDB Operator 开发设计思想:
Operator 部署阶段:作为开发者,确定了 mongo 相关的需求之后,首先要熟悉 mongo 的使用方式和基本知识,掌握 Kubernetes、Operator CRD/Controller Kubebuiler/operator-sdk 等技术,才能创建 mongo operator 项目;
Opertaor 功能开发阶段:mongo operator 功能主要包含 mongo 实例、备份、备份计划、主从切换等 CRD 设计定义、同时包含相应的监控的指标和告警规则的设计,实现对 Mongo 服务以及 Operator 的监控告警功能;
Opertaor 持续优化阶段:为实现 mongo CRD 相应的资源管理,通过 mongo operator 的 Reconclie 机制,实现对 CR 实例的监听和自动维护,使 CR 达到用户的期望的状态。
根据如上思想,MongoDB Operator 架构图如下:
其中 Reconcile 的核心思路如下:
单点模型
// MongoDBSpec defines the desired state of MongoDB
// Type 类型为 Standalone
type MongoDBSpec struct {
Image string `json:"image,omitempty"`
// +kubebuilder:validation:Enum=Standalone;ReplicaSet;ShardedCluster
Type string `json:"type,omitempty"`
Service string `json:"service,omitempty"`
RootPassword string `json:"rootPassword,omitempty"`
DBUserSpec DBUserSpec `json:"dbUserSpec,omitempty"`
NotPersistent bool `json:"notPersistent,omitempty"`
CustomConfig string `json:"customConfig,omitempty"`
ExportConnect bool `json:"exportConnect,omitempty"`
Resources *corev1.ResourceRequirements `json:"resources,omitempty"`
Storage string `json:"storage,omitempty"`
BackUpStorage string `json:"backUpStorage,omitempty"`
StorageClassName string `json:"storageClassName,omitempty"`
MetricsExporterSpec MetricsExporterSpec `json:"metricsExporterSpec,omitempty"`
PodSpec PodSpec `json:"podSpec,omitempty"`
}
副本集模型
// MongoDBSpec defines the desired state of MongoDB
// Type 类型为 ReplicaSet
type MongoDBSpec struct {
Image string `json:"image,omitempty"`
// +kubebuilder:validation:Enum=Standalone;ReplicaSet;ShardedCluster
Type string `json:"type,omitempty"`
Members int `json:"members,omitempty"`
Service string `json:"service,omitempty"`
RootPassword string `json:"rootPassword,omitempty"`
DBUserSpec DBUserSpec `json:"dbUserSpec,omitempty"`
Arbiter bool `json:"arbiter,omitempty"`
NotPersistent bool `json:"notPersistent,omitempty"`
CustomConfig string `json:"customConfig,omitempty"`
ExportConnect bool `json:"exportConnect,omitempty"`
Resources *corev1.ResourceRequirements `json:"resources,omitempty"`
Storage string `json:"storage,omitempty"`
BackUpStorage string `json:"backUpStorage,omitempty"`
StorageClassName string `json:"storageClassName,omitempty"`
MetricsExporterSpec MetricsExporterSpec `json:"metricsExporterSpec,omitempty"`
PodSpec PodSpec `json:"podSpec,omitempty"`
}
分片集群模型
// MongoDBSpec defines the desired state of MongoDB
// Type 类型为 ShardedCluster
type MongoDBSpec struct {
Image string `json:"image,omitempty"`
// +kubebuilder:validation:Enum=Standalone;ReplicaSet;ShardedCluster
Type string `json:"type,omitempty"`
ShardCount int `json:"shardCount,omitempty"`
MongodsPerShardCount int `json:"mongodsPerShardCount,omitempty"`
MongosCount int `json:"mongosCount,omitempty"`
ConfigServerCount int `json:"configServerCount,omitempty"`
Service string `json:"service,omitempty"`
RootPassword string `json:"rootPassword,omitempty"`
DBUserSpec DBUserSpec `json:"dbUserSpec,omitempty"`
Arbiter bool `json:"arbiter,omitempty"`
NotPersistent bool `json:"notPersistent,omitempty"`
CustomConfig string `json:"customConfig,omitempty"`
Resources *corev1.ResourceRequirements `json:"resources,omitempty"`
Storage string `json:"storage,omitempty"`
BackUpStorage string `json:"backUpStorage,omitempty"`
StorageClassName string `json:"storageClassName,omitempty"`
MetricsExporterSpec MetricsExporterSpec `json:"metricsExporterSpec,omitempty"`
PodSpec PodSpec `json:"podSpec,omitempty"`
}
备份模型
// MongoBackUpSpec defines the desired state of MongoBackUp
type MongoBackUpSpec struct {
Instance string `json:"instance"`
Restart bool `json:"restart,omitempty"`
ChangeMasterTo string `json:"changeMasterTo,omitempty"`
}
主从节点切换模型
type MongoChannelSpec struct {
Instance string `json:"instance"`
Restart bool `json:"restart,omitempty"`
ChangeMasterTo string `json:"changeMasterTo,omitempty"`
}
5.2 使用样例
单点部署/备份
apiVersion: mongo.daocloud.io/v1alpha1
kind: MongoDB
metadata:
name: mongodb-test
spec:
type: Standalone
image: daocloud.io/atsctoo/mongo:3.6
service: mongodb-001-svc
rootPassword: "654321"
dbUserSpec:
enable: true
name: mongo001
user: user001
password: "123456"
notPersistent: true
customConfig: mongo-operator-mongo-default-config
resources:
limits:
cpu: "1"
memory: 512Mi
requests:
cpu: "1"
memory: 512Mi
storage: 1Gi
backUpStorage: 1Gi
storageClassName: "nfs"
metricsExporterSpec:
enable: true
resources:
limits:
cpu: "0.1"
memory: 128Mi
requests:
cpu: "0.1"
memory: 128Mi
---
apiVersion: mongo.daocloud.io/v1alpha1
kind: MongoBackUp
metadata:
name: mongobackup-sample
spec:
backUpInstance: mongodb-test
backUpNode: mongodb-test-standalone-0-0
storages: mongo-operator-s3
副本集部署/备份/主从切换
apiVersion: mongo.daocloud.io/v1alpha1
kind: MongoDB
metadata:
name: mongodb-test
spec:
image: daocloud.io/atsctoo/mongo:3.6
type: ReplicaSet
members: 3
service: mongodb-test-svc
rootPassword: "123456"
dbUserSpec:
enable: true
name: mongo001
user: user001
password: "123456"
arbiter: false
notPersistent: false
customConfig: mongo-operator-mongo-default-config
exportConnect: true
resources:
limits:
cpu: "1"
memory: 512Mi
requests:
cpu: "1"
memory: 512Mi
storage: 1Gi
backUpStorage: 1Gi
storageClassName: "" # 存储类型 为空时,表示使用默认
metricsExporterSpec:
enable: true
resources:
limits:
cpu: "0.1"
memory: 128Mi
requests:
cpu: "0.1"
memory: 128Mi
---
apiVersion: mongo.daocloud.io/v1alpha1
kind: MongoBackUp
metadata:
name: mongobackup-sample
spec:
backUpInstance: mongodb-test
backUpNode: mongodb-test-replset-0-0
storages: mongo-operator-s3
---
apiVersion: mongo.daocloud.io/v1alpha1
kind: MongoChannel
metadata:
name: mongochannel-sample
spec:
changeMasterTo: 'mongdb-test-replset-0-2.dce.dsp.ats.io:35966'
instance: mongodb-test
分片部署/备份
apiVersion: mongo.daocloud.io/v1alpha1
kind: MongoDB
metadata:
name: mongodb-test
spec:
image: daocloud.io/atsctoo/mongo:3.6
type: ShardedCluster
service: mongodb-test-svc
shardCount: 2
mongodsPerShardCount: 3
configServerCount: 3
mongosCount: 2
rootPassword: "123456"
dbUserSpec:
enable: true
name: mongo001
user: user001
password: "123456"
arbiter: true
notPersistent: true
customConfig: mongo-operator-mongo-default-config
resources:
limits:
cpu: "1"
memory: 512Mi
requests:
cpu: "1"
memory: 512Mi
storage: 1Gi
backUpStorage: 1Gi
storageClassName: "" # 存储类型 为空时,表示使用默认
metricsExporterSpec:
enable: true
resources:
limits:
cpu: "0.1"
memory: 128Mi
requests:
cpu: "0.1"
memory: 128Mi
---
apiVersion: mongo.daocloud.io/v1alpha1
kind: MongoBackUp
metadata:
name: mongobackup-sample
spec:
backUpInstance: mongodb-test
backUpNode: mongodb-test-replset-0-0
storages: mongo-operator-s3
以上介绍了基于 K8s Operator 模式之上的 MongoDB Operator,MongoDB Operator 简化了 MongoDB 的部署、监控以及运维操作,它提供了在云上根据自主需求创建/更新/配置 MongoDB 服务、备份等功能,提升了用户对中间件 MongoDB 的管理能力。
本文作者
宋文杰
「DaoCloud 道客」Python研发工程师