Monogo实践及原理

2022-10-31 11:45:46 浏览数 (1)

mongo简介

MongoDB 是由C 语言编写的,是一个基于分布式文件存储的开源数据库系统。

在高负载的情况下,添加更多的节点,可以保证服务器性能。

MongoDB 旨在为WEB应用提供可扩展的高性能数据存储解决方案。

MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档,数组及文档数组

代码语言:shell复制
{
   name:"sue",
   age:23,
   status:"A",
   groups:["news","sports"]
}

mongo功能

  • 每个数据库都包含集合,而集合又包含文档。每个文档可以具有不同数量的字段。每个文档的大小和内容可以互不相同。
  • 文档结构更符合开发人员如何使用各自的编程语言构造其类和对象。开发人员经常会说他们的类不是行和列,而是具有键值对的清晰结构。
  • 从NoSQL数据库的简介中可以看出,行(或在MongoDB中调用的文档)不需要预先定义架构。相反,可以动态创建字段。
  • MongoDB中可用的数据模型使我们可以更轻松地表示层次结构关系,存储数组和其他更复杂的结构。
  • 可伸缩性– MongoDB环境具有很高的可伸缩性。全球各地的公司已经定义了自己的集群,其中一些集群运行着100多个节点,数据库中包含大约数百万个文档

mongodb使用场景

MongoDB (名称来自"humongous") 是一个可扩展的高性能,开源,模式自由,面向文档的数据库。

MongoDB的主要目标是在键/值存储方式(提供了高性能和高度伸缩性)以及传统的RDBMS系统(丰富的功能)架起一座桥梁,集两者的优势于一身。

适用场景

网站数据:适合实时的插入,更新与查询,并具备网站实时数据存储所需的复制及高度伸缩性。 缓存:由于性能很高,也适合作为信息基础设施的缓存层。在系统重启之后,搭建的持久化缓存可以避免下层的数据源过载。 大尺寸、低价值的数据:使用传统的关系数据库存储一些数据时可能会比较贵,在此之前,很多程序员往往会选择传统的文件进行存储。 高伸缩性的场景:非常适合由数十或者数百台服务器组成的数据库。 用于对象及JSON数据的存储:MongoDB的BSON数据格式非常适合文档格式化的存储及查询。

应用案例

京东,中国著名电商,使用MongoDB存储商品信息,支持比价和关注功能.

赶集网,中国著名分类信息网站,使用MongoDB记录pv浏览计数

奇虎360,著名病毒软件防护和移动应用平台,使用MongoBD支撑的HULK平台每天接受200亿次的查询.

百度云,使用MongoDB管理百度云盘中500亿条关于文件源信息的记录.

CERN,著名的粒子物理研究所,欧洲核子研究中心大型强子对撞机的数据使用MongoDB

纽约时报,领先的在线新闻门户网站之一,使用MongoDB

sourceforge.net,资源网站查找,创建和发布开源软件免费,使用MongoDB的后端存储

不适合的场景

高度事物性的系统:例如银行或会计系统。传统的关系型数据库目前还是更适用于需要大量原子性复杂事务的应用程序。 传统的商业智能应用:针对特定问题的BI数据库会对产生高度优化的查询方式。对于此类应用,数据仓库可能是更合适的选择。 需要SQL的问题

mongodb架构

主要组件架构图如下:

MongoDB 的美妙之处在于为你提供了这些能力:

  • 一个简单的单机实例就可以满足大多数小型应用程序的需求。
  • 一个多机实例可以为大多数商业应用程序提供持久性 / 高可用性。
  • 一个具有水平伸缩能力的大型集群 (分片集群) 可以处理非常大的数据集和大量的查询。MongoDB 提供了自动化基础设施,用于实现分布式的数据分布和处理
单服务器/容错设置

对于小型应用程序,单台服务器就足以满足频繁的数据备份需求了。如果需要容错,可以使用副本集。在容错配置中,通常有 3 个或更多的 MongoDB 实例。这些实例当中只有一个作为主实例,如果它发生故障,其他两个辅助实例中的一个将成为主实例。这些实例中的数据都是一样的。

mongodb管理

账户角色管理
系统默认角色

数据库访问角色

代码语言:shell复制
Read:允许用户读取指定数据库
readWrite:允许用户读写指定数据库

数据库管理角色

代码语言:shell复制
dbAdmin:允许用户在指定数据库中执行管理函数,如索引创建、删除,查看统计或访问system.profile
userAdmin:允许用户向system.users集合写入,可以找指定数据库里创建、删除和管理用户
dbOwner: 数据库拥有者(最高), 集合了dbAdmin/userAdmin/readWrite角色的权限

集群管理角色

代码语言:shell复制
clusterAdmin:只在admin数据库中可用,赋予用户所有分片和复制集相关函数的管理权限。
clusterManager: 集群管理角色,允许对分片和副本集集群执行管理操作,如addShard,resync等
clusterMonitor:集群监控角色,允许度分片和副本集集群监控,如查看serverStatus
hostManager:节点管理角色,允许监控和管理节点,比如killOp,shutdown等

备份恢复

代码语言:shell复制
backup: 备份权限,允许执行mongodump操作
restore:恢复权限,允许执行mongorestore操作

通用角色

代码语言:shell复制
readAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的读权限
readWriteAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的读写权限
userAdminAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的userAdmin权限
dbAdminAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的dbAdmin权限。

特殊角色

代码语言:shell复制
root:只在admin数据库中可用。超级账号,超级权限
——system:内部角色,用于集群节点通讯
创建自定义角色

使用createRole命令可以创建自定义角色,每一个角色都需要被绑定到指定的库中。普通的业务库中的角色对象只允许访问当前库的资源对象,而位于admin库的角色则没有此限制。我们定义了一个特殊的角色,用来对分散在多个业务库中的数据进行ETL处理,代码如下

代码语言:shell复制
# 创建角色权限
use admin
db.createRole(
	{
		role: "etlRole",
		privileges: [
			{
				resource: {
					db: "tracedb", collection: "etlLogs"
				},
				actions: [
					"find",
					"update",
					"insert",
					"remote"
				]
			}
		],
		roles: [
			{ role: "read", db: "orderdb"},
			{ role: "read", db: "goodsdb"},
			{ role: "read", db: "userdb"}
		]
	},
	{ w: "majority", wtimeout: 5000}
)
# 授权
use somedb
db.grantRolesToUser("bus",[{role: "readWrite",db: "dimension"}])
常见权限添加
代码语言:shell复制
# 创建管理员角色
db.createUser({
  user : 'testadm',
  pwd : 'xxxxxx',
  roles : [
    'clusterAdmin',
    'dbAdminAnyDatabase',
    'userAdminAnyDatabase',
    'readWriteAnyDatabase',
    {
    	role: "readWrite", db: "xxxxx"
    }
  ]
})

# 新增权限
db.grantRolesToUser("admin", [ { role:"dbAdminAnyDatabase", db:"admin"} ])
db.grantRolesToUser("test", [ { role:"readWrite", db:"apiplatform"} ])

# 针对库创建角色
db.createUser({
  user : 'testadm',
  pwd : 'localhost',
  roles : [
    {
    role: "readWrite",db: "apiplatform"
    }
  ]
})

# 删除用户
use api-platform
db.system.users.remove({user: "admin"})
mongo 数据管理
数据新增
代码语言:shell复制
# 创建数据库
use db_name
# 创建集合
db.createCollection("mycol", { capped : true, autoIndexId : true, size : 
   6142800, max : 10000 } )
# 文档插入
db.mycol.insert({title: 'MongoDB 教程', 
    description: 'MongoDB 是一个 Nosql 数据库',
    by: '官网',
    url: 'http://www.runoob.com',
    tags: ['mongodb', 'database', 'NoSQL'],
    likes: 100
})
# 查询所有数据
db.mycol.find()
# 文档查询
db.mycol.find().pretty()
{
        "_id" : ObjectId("56063f17ade2f21f36b03133"),
        "title" : "MongoDB 教程",
        "description" : "MongoDB 是一个 Nosql 数据库",
        "by" : "菜鸟教程",
        "url" : "http://www.runoob.com",
        "tags" : [
                "mongodb",
                "database",
                "NoSQL"
        ],
        "likes" : 100
}
# 条件查询
db.mycol.find({"title":"MongoDB 教程"}).pretty()
{
        "_id" : ObjectId("56063f17ade2f21f36b03133"),
        "title" : "MongoDB 教程",
        "description" : "MongoDB 是一个 Nosql 数据库",
        "by" : "菜鸟教程",
        "url" : "http://www.runoob.com",
        "tags" : [
                "mongodb",
                "database",
                "NoSQL"
        ],
        "likes" : 100
}
# 条件查询(or)
db.mycol.find({$or:[{"by":"官网"},{"title": "MongoDB 教程"}]}).pretty()
{
        "_id" : ObjectId("56063f17ade2f21f36b03133"),
        "title" : "MongoDB 教程",
        "description" : "MongoDB 是一个 Nosql 数据库",
        "by" : "菜鸟教程",
        "url" : "http://www.runoob.com",
        "tags" : [
                "mongodb",
                "database",
                "NoSQL"
        ],
        "likes" : 100
}
数据更新
代码语言:shell复制
# 更新一条
db.mycol.find({$or:[{"by":"官网"},{"title": "MongoDB 教程"}]}).pretty()
{
        "_id" : ObjectId("56063f17ade2f21f36b03133"),
        "title" : "MongoDB 教程",
        "description" : "MongoDB 是一个 Nosql 数据库",
        "by" : "菜鸟教程",
        "url" : "http://www.runoob.com",
        "tags" : [
                "mongodb",
                "database",
                "NoSQL"
        ],
        "likes" : 100
}
# 更新第一条
db.mycol.update({},{})
# 全部更新
db.mycol.update({},{}, false, true)
# 添加一条
db.mycol.update({},{}, true, false)
数据删除
代码语言:shell复制
# 删除数据
db.mycol.delete()
# 批量删除
db.mycol.deleteMany({})

mongodb安装及使用

安装

详情见官网

代码语言:shell复制
# 下载二进制文件
yum install libcurl openssl
wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-4.0.4.tgz
# 下载地址
https://repo.mongodb.org/yum/redhat/7/mongodb-org/4.0/x86_64/RPMS/mongodb-org-server-4.0.4-1.el7.x86_64.rpm
https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-4.0.4.tgz
mkdir -pv /usr/local/mongodb
tar zxvf mongodb-linux-x86_64-4.0.4.tgz -C /usr/local/src
mv /usr/local/src/mongodb-linux-x86_64-4.0.4 /usr/local/mongodb
echo 'export PATH=/usr/local/mongodb/bin:$PATH' >> /etc/profile
source /etc/profile
# 创建mongodb数据库目录
 mkdir -pv /data/mongo/db
 mkdir -pv /data/mongo/mongodb.cnf
 mkdir -pv /data/mongo/mongo.log
 # 创建启动配置文件
 cat > /data/mongo/mongodb.cnf <<- 'EOF'
 dbpath=/data/mongo/db
 logpath=/data/mongo/mongod.log
 pidfilepath=/data/mongo/mongod.pid
 logappend=true
 fork=true
 port=27017
 # 副本集
 #replSet=rs0
 EOF
 # 启动mongo
mongod --auth -f /data/mongo/mongodb.cnf
 # 进入mongo管理控制台
mongo
# 配置开机启动
cat > /etc/systemd/system/mongod.service <<- 'EOF'
[Unit]
Description=mongodb
After=network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
ExecStart=/usr/local/mongodb/bin/mongod --config /servers/db/mongo/mongodb.cnf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/usr/local/mongodb/bin/mongod --shutdown --config /servers/db/mongo/mongodb.cnf
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
systemctl enable mongod.servcie
systemctl start mongod
使用
代码语言:shell复制
# 下载
## mac版
wget https://downloads.mongodb.com/compass/mongosh-1.0.5-darwin-x64.zip
## linux
wget https://downloads.mongodb.com/compass/mongosh-0.1.0-linux.tgz
# 连接
主节点: mongo mongodb://mongodb0.example.com.local:27017
从节点: mongo mongodb://mongodb1.example.com.local:27017
副本集: mongo "mongodb://mongodb0.example.com.local:27017,mongodb1.example.com.local:27017,mongodb2.xample.com.local:27017/?replicaSet=replA"
mongo数据导入导出
下载mongo-tools工具
代码语言:shell复制
wget https://repo.mongodb.org/yum/redhat/7Server/mongodb-org/4.4/x86_64/RPMS/mongodb-database-tools-100.3.1.x86_64.rpm -P /usr/local/src
wget https://repo.mongodb.org/yum/redhat/7Server/mongodb-org/4.4/x86_64/RPMS/mongodb-org-tools-4.4.6-1.el7.x86_64.rpm -P /usr/local/src
yum localinstall -y mongodb-database-tools-100.3.1.x86_64.rpm
yum localinstall -y mongodb-org-tools-4.4.6-1.el7.x86_64.rpm
导出集合数据
代码语言:shell复制
mongoexport --host xxx --port 3717 --authenticationDatabase admin -u admin -p xxxx --db scrm_dimension --collection xxx --type=json --out scrm_dimension.json
导入集合数据
代码语言:shell复制
mongoimport --host xxxx --port 3717 --authenticationDatabase admin -u admin -p xxxx  --db scrm_dimension --collection xxxx --type=json --out scrm_dimension.json
mongo故障恢复

mongo分布式集群

MongoDB 有三种集群部署模式,分别为主从复制(Master-Slaver)、副本集(Replica Set)和分片(Sharding)模式。

  • Master-Slaver 是一种主从副本的模式,目前已经不推荐使用。
  • Replica Set 模式取代了 Master-Slaver 模式,是一种互为主从的关系。Replica Set 将数据复制多份保存,不同服务器保存同一份数据,在出现故障时自动切换,实现故障转移,在实际生产中非常实用。
  • Sharding 模式适合处理大量数据,它将数据分开存储,不同服务器保存不同的数据,所有服务器数据的总和即为整个数据集

Sharding 模式追求的是高性能,而且是三种集群中最复杂的。在实际生产环境中,通常将 Replica SetSharding 两种技术结合使用。

主从复制

  • 主从复制是 MongoDB 中最简单的数据库同步备份的集群技术,其基本的设置方式是建立一个主节点(Primary)和一个或多个从节点(Secondary)。
  • 这种方式比单节点的可用性好很多,可用于备份、故障恢复、读扩展等。集群中的主从节点均运行 MongoDB 实例,完成数据的存储、查询与修改操作。
  • 主从复制模式的集群中只能有一个主节点,主节点提供所有的增、删、查、改服务,从节点不提供任何服务,但是可以通过设置使从节点提供查询服务,这样可以减少主节点的压力。

另外,每个从节点要知道主节点的地址,主节点记录在其上的所有操作,从节点定期轮询主节点获取这些操作,然后对自己的数据副本执行这些操作,从而保证从节点的数据与主节点一致。

在主从复制的集群中,当主节点出现故障时,只能人工介入,指定新的主节点,从节点不会自动升级为主节点。同时,在这段时间内,该集群架构只能处于只读状态。

副本集

此集群拥有一个主节点和多个从节点,这一点与主从复制模式类似,且主从节点所负责的工作也类似,但是副本集与主从复制的区别在于:当集群中主节点发生故障时,副本集可以自动投票,选举出新的主节点,并引导其余的从节点连接新的主节点,而且这个过程对应用是透明的。

  • MongoDB 副本集使用的是 N 个 mongod 节点构建的具备自动容错功能、自动恢复功能的高可用方案。在副本集中,任何节点都可作为主节点,但为了维持数据一致性,只能有一个主节点。
  • 主节点负责数据的写入和更新,并在更新数据的同时,将操作信息写入名为 oplog 的日志文件当中。主节点还负责指定其他节点为从节点,并设置从节点数据的可读性,从而让从节点来分担集群读取数据的压力。

另外,从节点会定时轮询读取 oplog 日志,根据日志内容同步更新自身的数据,保持与主节点一致。

在一些场景中,用户还可以使用副本集来扩展读性能,客户端有能力发送读写操作给不同的服务器,也可以在不同的数据中心获取不同的副本来扩展分布式应用的能力。

在副本集中还有一个额外的仲裁节点(不需要使用专用的硬件设备),负责在主节点发生故障时,参与选举新节点作为主节点。

副本集中的各节点会通过心跳信息来检测各自的健康状况,当主节点出现故障时,多个从节点会触发一次新的选举操作,并选举其中一个作为新的主节点。为了保证选举票数不同,副本集的节点数保持为奇数。

分片

副本集可以解决主节点发生故障导致数据丢失或不可用的问题,但遇到需要存储海量数据的情况时,副本集机制就束手无策了。副本集中的一台机器可能不足以存储数据,或者说集群不足以提供可接受的读写吞吐量。这就需要用到 MongoDB 的分片(Sharding)技术,这也是 MongoDB 的另外一种集群部署模式。

  • 分片是指将数据拆分并分散存放在不同机器上的过程。有时也用分区来表示这个概念。将数据分散到不同的机器上,不需要功能强大的大型计算机就可以存储更多的数据,处理更大的负载。
  • MongoDB 支持自动分片,可以使数据库架构对应用程序不可见,简化系统管理。对应用程序而言,就如同始终在使用一个单机的 MongoDB 服务器一样。
  • 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 返回结果后进行聚合并返回客户端。

0 人点赞