1.Mongodb介绍
Mongodb:是一个nosql的数据库的一种数据库,他是介于关系型数据库与非关系型数据库之间的一种数据库,也可以理解为它是介于Redis与Mysql之间的一种数据库。它是由大数据时代的3V,与互联网需求的三高而产生出来的。
- 3V:海量Volume ,多样Variety ,实时Velocity
- 高并发,高可扩,高性能
1. 与传统数据库的对比
统数据库 | Mongodb |
---|---|
datebase(数据库) | datebase |
table(表) | collecttion(集合)可以理解成泛型集合 |
row(行) | document(文档)可理解为对象序列化的结果 |
注:
- Mongodb 数据10亿加的数据处理不了了,的使用HBASE。
- 是关系型数据库和非关系型数据库的一种。
2. Docker 下的安装
docker run -d --name mongo1 -p 27017:27017 mongo
进入:docker exec -it 容器id /bin/bash
2.数据操作
1. 基本操作
查询数据库
show databases
切换数据库
use test
查询当前数据库下面的集合
show collections
创建集合
db.createCollection("集合名称")
删除集合
db.集合名称.drop()
删除数据库
db.dropDatabase() //首先要通过use切换到当前的数据库
2. Mongodb增删改查(CURD)
id 系统会自动加一个
时间戳+机器码 生成
1. 增(insert)
新增一条
db.userinfo.insert({name:"贾宝玉",age:25,gander:"男",address:'贾府'})
新增多条
db.userinfo.insert([{name:"贾宝玉",age:25,gander:"男",address:'贾府'}
,{name:"林黛玉",age:16,gander:"女",address:'林府'}])
可不可以快速插入10条数据
for(var i=1;i<=10;i++)
{
db.userinfo.insert({name:"clay"+i,age:i})
}
2. 查(find)
查询所有的数据
db.集合名称.find({})
查询top条数
db.集合名称.find({}).limit(条数)
条件查询
db.userinfo.find({name:"clay1",age:1},{name:1,_id:0})
排序&分页
db.c1.insert({_id:1,name:"a",sex:1,age:1})
db.c1.insert({_id:2,name:"a",sex:1,age:2})
db.c1.insert({_id:3,name:"b",sex:2,age:3})
db.c1.insert({_id:4,name:"c",sex:2,age:4})
db.c1.insert({_id:5,name:"d",sex:2,age:5})
db.c1.find()
正序
db.c1.find({}).sort({age:1})
降序
db.c1.find({}).sort({age:-1})
分页查询 跳过两条查询两条
db.c1.find({}).sort({age:1}).skip(2).limit(2)
运算符
运算符 | 作用 |
---|---|
$gt | 大于 |
$gte | 大于等于 |
$lt | 小于 |
$lte | 小于等于 |
$ne | 不等于 |
$in | in |
$nin | not in |
//年龄大于1
db.c1.find({age:{$gt:1}})
//年龄是 3,4,5的
db.c1.find({age:{$in:[3,4,5]}})
3. 改(update)
db.集合名.update(条件, 新数据) {修改器: {键:值}}
修改器 | 作用 |
---|---|
$inc | 递增 |
$rename | 重命名列 |
$set | 修改列值 |
$unset | 删除列 |
准备数据
db.c1.insert({name:"8888",age:1,addr:'address',flag:true})
db.c1.update({name:"8888"}, {name:"99"})
db.c1.update({name:"8888"},
{
$set:{name: "zs44"},
$inc:{age:10},
$rename:{addr:"address"} ,
$unset:{flag:""}
}
)
db.c1.find({name:"zs44"})
4. 删(delete)
//全部移除
db.userinfo.deleteMany({})
db.userinfo.deleteMany({age:1})
5. 聚合查询
顾名思义就是把数据聚起来,然后统计
语法
db.集合名称.aggregate([
{管道:{表达式}}
....
])
常用管道
$group 将集合中的文档分组,用于统计结果
$match 过滤数据,只要输出符合条件的文档
$sort 聚合数据进一步排序
$skip 跳过指定文档数
$limit 限制集合数据返回文档数
....
常用表达式
$sum 总和 $sum:1同count表示统计
$avg 平均
$min 最小值
$max 最大值
...
准备
use test4
db.c1.insert({_id:1,name:"a",sex:1,age:1})
db.c1.insert({_id:2,name:"a",sex:1,age:2})
db.c1.insert({_id:3,name:"b",sex:2,age:3})
db.c1.insert({_id:4,name:"c",sex:2,age:4})
db.c1.insert({_id:5,name:"d",sex:2,age:5})
练习
- 统计男生、女生的总年龄
db.c1.aggregate([ { $group:{ _id: "$sex", rs: {$sum: "$age"} } } ])
- 统计男生、女生的总人数
db.c1.aggregate([ { $group:{ _id: "$sex", rs: {$sum:1} } } ])
- 求学生总数和平均年龄
db.c1.aggregate([ { $group:{ _id: null, total_num: {$sum:1}, total_avg: {$avg: "$age"} } } ])
- 查询男生、女生人数,按人数升序
db.c1.aggregate([ {$group:{_id: "$sex",rs: {$sum: 1}}}, {$sort:{rs: -1}} ])
3. 事务
4.X版本之后,支持了事务,支持事务之前,必须要搭建集群,如果不是集群,则也不会支持事务。
use test
db.createCollection("userinfo");
s=db.getMongo().startSession();
s.startTransaction();
s.getDatabase("test").userinfo.insert({name:"a"});
s.commitTransaction();//提交
s.abortTransaction();//回滚
4. 使用JavaScript
1. 创建 Javascript 函数
现在,我们创建函数 getNextSequenceValue 来作为序列名的输入, 指定的序列会自动增长 1 并返回最新序列值。在本文的实例中序列名为 productid 。
>function getNextSequenceValue(sequenceName){
var sequenceDocument = db.counters.findAndModify(
{
query:{_id: sequenceName },
update: {$inc:{sequence_value:1}},
"new":true
});
return sequenceDocument.sequence_value;
}
2. 使用 Javascript 函数
接下来我们将使用 getNextSequenceValue 函数创建一个新的文档, 并设置文档 _id 自动为返回的序列值:
>db.products.insert({
"_id":getNextSequenceValue("productid"),
"product_name":"Apple iPhone",
"category":"mobiles"})
>db.products.insert({
"_id":getNextSequenceValue("productid"),
"product_name":"Samsung S3",
"category":"mobiles"})
就如你所看到的,我们使用 getNextSequenceValue 函数来设置 _id 字段。
为了验证函数是否有效,我们可以使用以下命令读取文档:
>db.products.find()
以上命令将返回以下结果,我们发现 _id 字段是自增长的:
{ "_id" : 1, "product_name" : "Apple iPhone", "category" : "mobiles"}
{ "_id" : 2, "product_name" : "Samsung S3", "category" : "mobiles" }
5. 自增ID
#创建序列
db.counters.insert({_id:"productid",sequence_value:0})
3. 代码对接
1. 使用驱动包
MongoDB.Driver
连接数量可以通过配置文件修改
2. 直接对JSON操作
var client = new MongoClient("mongodb://192.168.3.202:27017");
var database = client.GetDatabase("mongodbDemo");
var document = BsonDocument.Parse("{ a: 1, b: [{ c: 1 }],c: 'ff'}");
database.GetCollection<BsonDocument>("order").InsertOne(document);
3. 操作对象
帮助类:
public class DBbase<T> where T : class, new()
{
MongoClient client;
IMongoDatabase database;
public IMongoCollection<T> collection;
public DBbase()
{
//创建连接
//var client = new MongoClient("mongodb://host:27017,host2:27017/?replicaSet=rs0");//集群的连接方式
client = new MongoClient("mongodb://81.70.91.63:27017");
//创建数据库
database = client.GetDatabase("test");
//创建集合
Type type = typeof(T);
collection = database.GetCollection<T>(type.Name.ToLower());
}
public void DropDatabase()
{
client.DropDatabase("test");
}
public void InsertOne(T model)
{
collection.InsertOne(model);
}
public void InsertMany(params T[] modes)
{
collection.InsertMany(modes);
}
public IMongoQueryable<T> Select()
{
return collection.AsQueryable<T>();
}
public IMongoQueryable<T> Select(int pageIndex, int pageSize)
{
return collection.AsQueryable<T>().Skip(pageSize * (pageIndex - 1)).Take(pageSize);
}
public IMongoQueryable<T> Select(Expression<Func<T, bool>> predicate, Expression<Func<T, object>> keySelector, int pageIndex, int pageSize)
{
return collection.AsQueryable<T>().Where(predicate).OrderBy(keySelector).Skip(pageSize * (pageIndex - 1)).Take(pageSize);
}
public void UpdateMany(Expression<Func<T, bool>> filter, UpdateDefinition<T> update)
{
collection.UpdateMany(filter, update);
}
public void UpdateOne(Expression<Func<T, bool>> filter, T update)
{
collection.ReplaceOne(filter, update);
}
public void DeleteMany(Expression<Func<T, bool>> filter)
{
collection.DeleteMany(filter);
}
}
dBbase.InsertOne(new Userinfo()
{
Id = Guid.NewGuid().ToString(),
Name = "诸葛亮",
Address = "蜀国",
Age = 27,
Sex = "男",
DetpInfo = new DetpInfo()
{
DeptId = 1,
DeptName = "蜀国集团"
}
});
var pagelist = dBbase.Select(m => m.Sex == "男", m => m.Age, 2, 2);
foreach (var item in pagelist)
{
Console.WriteLine(item.Name + ":" + item.Age);
}
var query = from p in dBbase.collection.AsQueryable()
where (p.Sex == "男") && p.Age > 18
select p;
foreach (var item in query)
{
Console.WriteLine(item.Name + ":" + item.Age);
}
var daqiaod = dBbase.Select().Where(m => m.Name == "大乔").FirstOrDefault();
daqiaod.Age = 18;
dBbase.UpdateOne(m => m.Id == daqiaod.Id, daqiaod);
Console.WriteLine("修改完成");
dBbase.DeleteMany(m => m.Name == "大乔");
Console.WriteLine("删除完成");
//全部删除
dBbase.DeleteMany(m => 1 == 1);
Console.WriteLine("全部删除完成");
var groups = dBbase.collection.AsQueryable().GroupBy(m => new { m.DetpInfo.DeptId, m.DetpInfo.DeptName }).Select(t => new
{
DeptId = t.Key.DeptId,
DeptName = t.Key.DeptName,
number = t.Count(),
ages = t.Sum(s => s.Age)
}).Take(0).Skip(10);
foreach (var item in groups)
{
Console.WriteLine(item.DeptName + ":" + item.number + ":" + item.ages);
}
4. 缺点与需要注意地方
- 想要严格的操作mongo,可以创建一个map。net代码写的类要和map里面对字段类型要一致,如果多了一个字段或者少一个字段又或者类型不对,则写入失败。
- 与mysql区别,mongodb它不能做两和集合连查。可以通过数据冗余的办法,实现连查的效果。如果一个文档(json)16M会报错。如果超过把数据存在多个文档,然后根据一个关联字段去关联就行。比较特殊一般的业务完全够用。
- 多表关联:仅仅支持Left Outer Join
- SQL 语句支持:查询为主 部分支持
- 多表原子事务:不支持
- 多文档原子事务:不支持
- 16MB 大小限制超过报错,不支持中文排序,服务端JavaScript性能不好
5. 使用条件与场景###
-
使用条件
- 使用数据有亿万级或者需要不断的扩容。
- 需要2000-3000的每秒读写速度。
- 新应用需求会变,数据模型无法确定。
- 需要整合多个外部数据源。
- 系统需要99.999的高可用。
- 系统需要大量的地理位置查询。
- 系统需要提供最小的延迟。
- 管理的主要对象小于10。
-
使用场景
- 日志收集
- 传感器
- 网络爬虫
6. 慎用场景
慎用场景 | 原因 |
---|---|
PB数据持久存储大数据分析数据湖 | Hadoop、Spark提供更多分析运算功能和工具,并行计算能力更强 Mongodb+hadoop /Spark |
搜素场景:文档有十几个字段,需要按照任意字段搜索并排序限制等 | 不建索引查询太慢,索引太多影响写入和更新操作 |
ERP、CRM或者类似负责应用,几十上百个对象互相关联 | 关联支持较弱,事务较弱 |
需要参与远程事务,需要跨表、跨文档原子性更新 | MongoDB 事务支持仅限于本机的单文档事务 |
100%写可用:任何时间写入不能停 | MongoDB 换主节点时候会有短暂的不可写设计所限 |
7. 原理
8. 持久化
NOSQL:特性速度写入速度快 ,使用的是刷盘机制。写数据的时候,先把数据写入到内存,然后根据异步刷盘机制把数据存放到硬盘。
刷盘机制:先把数据保存到缓冲中,然后在保存到日志文件中,最后通过日志文件保存到磁盘中。如果直接由缓存保存到磁盘会造成随机性,消耗性能。
当从新打开mongodb的时候,程序先从Datafile 中读入数据,然后再从 log 中读入数据。
注意:
- mongodb 也会造成数据的丢失,丢失数据的原因再缓存区的数据没有来的及写入log 中,最大丢失数据的时间是99 ms之内产生的。
- 增加缓存区,增大刷盘时间可以提高mongodb 的处理数据速度。
9. 集群
1. 副本集
一个主库两个从库组成,主库把数据备份到从库中,从库之间有心跳,主库宕机时,这两个从库自动竞争选为主库,实现为高可用。主从架构:主节点负责写,从节点负责读。
1. 老版本搭建
结构如图:
-
一主一从
version: '2' services: master: image: mongo:3.4 volumes: - /data/mongodbml/master:/data/db command: mongod --dbpath /data/db --master slaver: image: mongo:3.4 volumes: - /data/mongodbml/slaver:/data/db command: mongod --dbpath /data/db --slave --source master:27017 links: - master
运行测试
//运行 docker-compose up -d //进入主节点测试 docker-compose exec master mongo //创建数据库 use test //插入数据 db.test.insert({msg: "this message is from master", ts: new Date()}) //进入从节点 docker-compose exec slaver mongo rs.slaveOk(): //查询数据 use test db.test.find(); //获得结果:证明主从架构建立完成。
注意:
- 一主一丛,当主节点宕机,不会把从节点切换成主节点。只能实现数据的备份,不能实现高可用。
-
一主多从
架构如图:
version: '2'
services:
rs1:
image: mongo:3.4
volumes:
- /data/mongodbtest/replset/rs1:/data/db
command: mongod --dbpath /data/db --replSet myset
rs2:
image: mongo:3.4
volumes:
- /data/mongodbtest/replset/rs2:/data/db
command: mongod --dbpath /data/db --replSet myset
rs3:
image: mongo:3.4
volumes:
- /data/mongodbtest/replset/rs3:/data/db
command: mongod --dbpath /data/db --replSet myset
运行测试
![6](F:\learn\2021Mongodb\笔记\image\6.png)//运行
docker-compose up -d
//进入rs1
docker-compose exec rs1 mongo
//初始化
rs.initiate()
//把rs2 添加到rs1 中
rs.add('rs2:27017')
//把rs3 添加到rs1 中
rs.add('rs3:27017')
//查看副本状态
rs.conf()
rs.status()
//插入信息到主节点
docker-compose exec rs1 mongo
use test
db.test.insert({msg: 'this is from primary', ts: new Date()})
//在rs2副本查看信息
docker-compose exec rs2 mongo
rs.slaveOk()
use test
db.test.find()
//在rs3副本查看信息
docker-compose exec rs3 mongo
rs.slaveOk() //副本集默认仅primary可读写
use test
db.test.find()
注意:
- 当主节点宕机后,从节点主节点,一个主多个从是可以实现高可用。
- 宕机后的主节点回来后,变成了新的主节点。
问题:一主多从,其中一主宕机后,从节点之间的数据交流只是心跳,没有数据的转移,所有从中选择出主节点,可能是主观的,但是这样不是我们想要的,所有又提供了一种新的方式:一主一从一仲裁。
-
一主一从一仲裁
仲裁的一方记录副本的:网络,备份数据如何,计算机性能等,这都是从节点竞争主节点的依据。当存在仲裁arbiter节点(只是仲裁,不存储数据)。仲裁可以搭建一个或是多个。
架构如图:
version: '2'
services:
master:
image: mongo:3.4
volumes:
- /data/mongodb3node/replset/rs1:/data/db
command: mongod --dbpath /data/db --replSet newset --oplogSize 128
slave:
image: mongo:3.4
volumes:
- /data/mongodb3node/replset/rs2:/data/db
command: mongod --dbpath /data/db --replSet newset --oplogSize 128
myarbiter:
image: mongo:3.4
command: mongod --dbpath /data/db --replSet newset --smallfiles --oplogSize 128
运行测试:
//运行
docker-compose exec master mongo
//设置
rs.initiate()
rs.add('slave:27017')//slave 可以是IP
rs.add('myarbiter:27017',true)//设置为仲裁节点
//查看配置
rs.conf()
rs.status()
//插入信息到主节点:
docker-compose exec master mongo
use test
db.test.insert({msg: 'this is from primary', ts: new Date()})
//在副本集中检测信息是否同步
docker-compose exec slave mongo
rs.slaveOk()
use test
db.test.find()
主节点宕机处理:
2. 新版本搭建
推介使用最新的
-
加入仲裁的
#三台节点安装实例 docker run --name mongo1 -p 27017:27017 -d mongo mongod --replSet "rs0" docker run --name mongo2 -p 27017:27017 -d mongo mongod --replSet "rs0" docker run --name mongo3 -p 27017:27017 -d mongo mongod --replSet "rs0"
#进入mongo1容器 docker exec -ti mongo1 /bin/bash #连接mondb mongo #初始化副本集 rs.initiate({"_id": "rs0", "members": [{"_id":0, "host":"192.168.3.202:27017"}, {"_id":1, "host":"192.168.3.203:27017","arbiterOnly":true}, {"_id":2, "host":"192.168.3.204:27017"}]}) # 加这个字段,说明该节点就是仲裁不存放数据 "arbiterOnly":true #查看副本集配置信息 rs.conf() #从节点开启读数据模式 db.getMongo().setSlaveOk();
//代码测试 MongoClient client = new MongoClient("mongodb://39.96.34.52:27017,47.95.2.2:27017,39.96.82.51:27017"); //事务 var session = client.StartSession(); var database = session.Client.GetDatabase("test"); session.StartTransaction(new TransactionOptions( readConcern: ReadConcern.Snapshot,writeConcern: WriteConcern.WMajority)); try { IMongoCollection<Userinfo> collection = database.GetCollection<Userinfo>("userinfo"); IMongoCollection<DetpInfo> weiguocollection = database.GetCollection<DetpInfo>("deptindo"); Userinfo daqiao = new Userinfo() { Id = Guid.NewGuid().ToString(), Address = "吴国", Name = "大乔", Sex = "女", DetpInfo = new DetpInfo() { DeptId = 1, DeptName = "蜀国集团" } }; collection.InsertOne(session, daqiao); //throw new Exception("取消事务"); DetpInfo weiguo = new DetpInfo() { DeptId = 1, DeptName = "魏国" }; weiguocollection.InsertOne(session,weiguo); session.CommitTransaction(); } catch (Exception ex) { //回滚 session.AbortTransaction(); Console.WriteLine(ex.Message); }
以下是docker-compose
version: '2' services: rs1: image: mongo volumes: - /data/mongodbtest/replset/rs1:/data/db ports: - 27017:27017 command: mongod --dbpath /data/db --replSet rs0 rs2: image: mongo volumes: - /data/mongodbtest/replset/rs2:/data/db ports: - 27018:27017 command: mongod --dbpath /data/db --replSet rs0 rs3: image: mongo volumes: - /data/mongodbtest/replset/rs3:/data/db ports: - 27019:27017 command: mongod --dbpath /data/db --replSet rs0
运行
进入mongo1容器 docker exec -ti mongodb_rs1_1 /bin/bash #连接mondb mongo #初始化副本集 注意的是rs0是启动节点的时候--replSet rs0 的名字 rs.initiate({"_id": "rs0", "members": [{"_id":0, "host":"192.168.3.204:27017"}, {"_id":1, "host":"192.168.3.204:27018","arbiterOnly":true}, {"_id":2, "host":"192.168.3.204:27019"}]}) # 加这个字段,说明该节点就是仲裁不存放数据 "arbiterOnly":true #查看副本集配置信息 rs.conf() #从节点开启读数据模式 db.getMongo().setSlaveOk();
2. 分片
1. 概念
分片(sharding)是指将数据库拆分,将其分散在不同的机器上的过程。将数据分散到不同的机器上,不需要功能强大的服务器就可以存储更多的数据和处理更大的负载。基本思想就是将集合切成小块,这些块分散到若干片里,每个片只负责总数据的一部分,最后通过一个均衡器来对各个分片进行均衡(数据迁移)。通过一个名为mongos的路由进程进行操作,mongos知道数据和片的对应关系(通过配置服务器)。大部分使用场景都是解决磁盘空间的问题,对于写入有可能会变差,查询则尽量避免跨分片查询。使用分片的时机:
1,机器的磁盘不够用了。使用分片解决磁盘空间的问题。
2,单个mongod已经不能满足写数据的性能要求。通过分片让写压力分散到各个分片上面,使用分片服务器自身的资源。
3,想把大量数据放到内存里提高性能。和上面一样,通过分片使用分片服务器自身的资源。
2. 分片集群架构
上图中主要有如下所述三个主要组件:
Shard:分片服务器
用于存储实际的数据块,实际生产环境中一个shard server角色可由几台机器组个一个replica set承担,防止主机单点故障
Config Server:配置服务器
mongod实例,存储了整个 分片群集的配置信息,其中包括 chunk信息。
Query Routers:前端路由
客户端由此接入,且让整个集群看上去像单一数据库,前端应用可以透明使用
这里的两个shard(分片)相当于mongodb节点服务器,内部的块是将order集合再切割的结果,随着数据量的的增大,分片会分割和迁移,以满足数据的均匀分布。
请求分流:通过路由节点将请求分发到对应的分片和块中
数据分流:内部提供平衡器保证数据的均匀分布,这是数据平均分布式、请求平均分布的前提
块的拆分:3.4版本块的最大容量为64M或者10w的数据,当到达这个阈值,触发块的拆分,一分为二
块的迁移:为保证数据在分片节点服务器分片节点服务器均匀分布,块会在节点之间迁移。一般相差8个分块的时候触发
MongoDB分片优势:
减少单个分片需要处理的请求数,提高群集的存储容量和吞吐量 比如,当插入一条数据时,应用只需要访问存储这条数据的分片 减少单分片存储的数据,提高数据可用性,提高大型数据库查询服务的性能。 当MongoDB单点数据库服务器存储和性能成为瓶颈,或者需要部署大型应用以充分利用内存时,可以使用分片技术
环境准备
docker、docker-compose、lunux。版本问题应该不大,我用的是Docker version 18.09.0, build 4d60db4、docker-compose version 1.23.0-rc3, buildea3d406e、centos7.2。
本套Mongodb搭建分片集群是基于mongodb4.0.5,直接从官方镜像仓库拉取docker pull mongo:4.0.5即可
完成准备之后,docker images看一下,mongodb.镜像是否搞定了。
3. 搭建
编写yml文件,docker-compose.yml
version: '2'
services:
shard1:
image: mongo:4.0.5
container_name: mongo_shard1
# --shardsvr: 这个参数仅仅只是将默认的27017端口改为27018,如果指定--port参数,可用不需要这个参数
# --directoryperdb:每个数据库使用单独的文件夹
command: mongod --shardsvr --directoryperdb --replSet shard1
volumes:
- /etc/localtime:/etc/localtime
- /data/base/fates/mongo/shard1:/data/db
privileged: true
networks:
- mongo
shard2:
image: mongo:4.0.5
container_name: mongo_shard2
command: mongod --shardsvr --directoryperdb --replSet shard2
volumes:
- /etc/localtime:/etc/localtime
- /data/base/fates/mongo/shard2:/data/db
privileged: true
networks:
- mongo
shard3:
image: mongo:4.0.5
container_name: mongo_shard3
command: mongod --shardsvr --directoryperdb --replSet shard3
volumes:
- /etc/localtime:/etc/localtime
- /data/base/fates/mongo/shard3:/data/db
privileged: true
networks:
- mongo
config1:
image: mongo:4.0.5
container_name: mongo_config1
# --configsvr: 这个参数仅仅是将默认端口由27017改为27019, 如果指定--port可不添加该参数
command: mongod --configsvr --directoryperdb --replSet fates-mongo-config --smallfiles
volumes:
- /etc/localtime:/etc/localtime
- /data/base/fates/mongo/config1:/data/configdb
networks:
- mongo
config2:
image: mongo:4.0.5
container_name: mongo_config2
command: mongod --configsvr --directoryperdb --replSet fates-mongo-config --smallfiles
volumes:
- /etc/localtime:/etc/localtime
- /data/base/fates/mongo/config2:/data/configdb
networks:
- mongo
config3:
image: mongo:4.0.5
container_name: mongo_config3
command: mongod --configsvr --directoryperdb --replSet fates-mongo-config --smallfiles
volumes:
- /etc/localtime:/etc/localtime
- /data/base/fates/mongo/config3:/data/configdb
networks:
- mongo
mongos:
image: mongo:4.0.5
container_name: mongo_mongos
# mongo3.6版默认绑定IP为127.0.0.1,此处绑定0.0.0.0是允许其他容器或主机可以访问
command: mongos --configdb fates-mongo-config/config1:27019,config2:27019,config3:27019 --bind_ip 0.0.0.0 --port 27017
ports:
- 27017:27017
volumes:
- /etc/localtime:/etc/localtime
depends_on:
- config1
- config2
- config3
networks:
- mongo
networks:
mongo:
driver: bridge
编写deploy-and-start.sh脚本
#!/bin/sh
docker-compose up -d
#鐫$湢涓ゅ垎閽燂紝绛夊緟mongodb鎵€鏈夊ㄨ捣鏉ヤ箣鍚庡皢瀹冧滑閰嶇疆鍔犲叆鍒嗙墖
sleep 30s
docker-compose exec config1 bash -c "echo 'rs.initiate({_id: \"fates-mongo-config\",configsvr: true, members: [{ _id : 0, host : \"config1:27019\" },{ _id : 1, host : \"config2:27019\" }, { _id : 2, host : \"config3:27019\" }]})' | mongo --port 27019"
docker-compose exec shard1 bash -c "echo 'rs.initiate({_id: \"shard1\",members: [{ _id : 0, host : \"shard1:27018\" }]})' | mongo --port 27018"
docker-compose exec shard2 bash -c "echo 'rs.initiate({_id: \"shard2\",members: [{ _id : 0, host : \"shard2:27018\" }]})' | mongo --port 27018"
docker-compose exec shard3 bash -c "echo 'rs.initiate({_id: \"shard3\",members: [{ _id : 0, host : \"shard3:27018\" }]})' | mongo --port 27018"
docker-compose exec mongos bash -c "echo 'sh.addShard(\"shard1/shard1:27018\")' | mongo"
docker-compose exec mongos bash -c "echo 'sh.addShard(\"shard2/shard2:27018\")' | mongo"
docker-compose exec mongos bash -c "echo 'sh.addShard(\"shard3/shard3:27018\")' | mongo"
该脚本流程详细描述一下
1)先启动mongodb分片容器组
- 睡眠30s等待容器全部完全启动(可能不需要30s)
3)操作config1,配置config副本集,将config*容器组作为config角色,此时config1作为config副本集里的主节点
4)操作shard1、shard2、shard3,将shard*容器组作为shard角色。
5)将shard1、shard2、shard3加入分片集群组。
执行脚本
#提交进去使用notepad++ 修过为utf8格式 (mobaxterm 选择文件右击open with--选择notepad++打开 )
#替换文本的换行等字符串 ,
sed -i 's/\r$//' deploy-and-start.sh
sh deploy-and-start.sh
# sh deploy-and-start.sh 等待脚本启动完成,如果出现connect fail报错,检查一下网络,再次启动一次脚本即可。
到这里,单机版的mongodb的分片集群,就搭建好了,一般真正的运维环境,Mongodb集群应该分布在不同的机器,但是只要熟悉这套部署方案的机制,只要稍作修改,就可以实现。
但是,Mongodb库默认是不会将你的表进行分片的,是需要手动配置的,如果不配置,数据都会全部存放在主节点,不会均匀分配到各个分片。
现在手动将一个表做分片,就拿order表作为例子
docker exec -it mongo_mongos bash
mongo --host 192.168.3.202 --port 27017
#数据库 启用 分片
sh.enableSharding("mongodbDemo")
# _id 字段进行哈希分片:
sh.shardCollection("mongodbDemo.order", {"_id": "hashed" })
#刷新路由
db.adminCommand("flushRouterConfig")
#让当前分片支持平衡
sh.enableBalancing("mongodbDemo.order")
#开启平衡
sh.startBalancer()
#查看详细分片信息
sh.status({"verbose":1})
#插入数据
use mongodbDemo
for (i = 1;i <= 100;i=i+1){
db.order.insert({'price': 1})
}
#查看该表分片数据信息
db.order.getShardDistribution()
4. 可视化工具
docker run -it --rm \
--name mongo-express \
-p 8081:8081 \
-e ME_CONFIG_OPTIONS_EDITORTHEME="ambiance" \
-e ME_CONFIG_MONGODB_SERVER="192.168.3.202" \
-e ME_CONFIG_MONGODB_PORT="27017" \
-e ME_CONFIG_BASICAUTH_USERNAME="admin" \
-e ME_CONFIG_BASICAUTH_PASSWORD="admin" \
mongo-express
10. 索引
db.c1.createIndex({age:1},{background:true,expireAfterSeconds:
150,name:"ix_age",unique:true});
db.c1.find({age:18}).explain('executionStats'); //查看执行计划
db.c1.getIndexes()
COLLSCAN 全表扫描 最慢的,没有走索引
IXSCAN 索引扫描
FETCH 根据索引去检索指定document
11. 注意
- redis与mongodb对比,redis速度要快,redis的纯内存的。
12. 扩展
MongoDB处理的数据是小于10亿的.
当达到了PB级别的数据:使用的NoSql是:hbase .
大数据本质:让数据又价值值钱,而让数据有意义首先经过以下步骤: 1:收集数据(各式各样的数据)->2.清洗数据(格式化处理数据)->3.分析统计.
hbase:列数据库:k:v
1.对数据随机读写,数据增删改查
2.高并发操作,一秒能对PB级别的数据,进行上千次不等操作
3.读和写都是简单的操作。
松散存储--nosql---列族 (一个列族里面可以存放多个字段)
创建数据库的时候,只要把列族创建好就行,至于你这列族里面几个字段,随便你。。
高效查询只能通过rowkey:1001 这个,要么直接=rowkey,要么给rowkey范围非常重要,设计者rowkey(包含了使用了它的60%思想思维)
hbase,分片是根据rowkey来分配
尽量让我们的rowkey分配均匀,还有松散, 可以利用多个节点.
-
业务有时候,需要查询的时候,可能需要尽量让查询的这个数据在一个节点上面。
例如: 具体的业务具体分析:保存(123123412340) 保存到30 不同的分片上去,并且做到均衡,可以对(12312341234 + 202101 (年与月))%30保存
HBase安装:
docker run -d -h myhbase -p 2181:2181 -p 8080:8080 -p 8085:8085 -p 9090:9090 -p 9095:9095 -p 16000:16000 -p 16010:16016 -p 16201:16201 -p 16301:16301 --name hbase1.3 harisekhon/hbase:1.3
访问地址:[http://IP:16010/master-status](http://IP:16010/master-status)
//进入
docker exec -it 容器id /bin/bash
hbase shell
//查看list
list
//创建list
create 'table' 'info1' 'info2'
//插入数据
put 'student','1001','info1:name','sss'
//查看数据
scan 'student'