mongodb

1.安装 mongodb

https://www.mongodb.com/try/download/community

wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-4.0.23.tgz
tar xf mongodb-linux-x86_64-rhel70-4.0.23.tgz
mkdir /mongodb/{conf,log,data} -p
cp -a mongodb-linux-x86_64-rhel70-4.0.23/bin/ /mongodb/
useradd mongod -s /sbin/nologin

cat >/etc/profile.d/mongod.sh <<EOF
export PATH=\$PATH:/mongodb/bin
EOF
source /etc/profile.d/mongod.sh

echo 'if test -f /sys/kernel/mm/transparent_hugepage/enabled; then
  echo never > /sys/kernel/mm/transparent_hugepage/enabled
fi
if test -f /sys/kernel/mm/transparent_hugepage/defrag; then
   echo never > /sys/kernel/mm/transparent_hugepage/defrag
fi' >>/etc/rc.local
chmod +x /etc/rc.d/rc.local

echo 'never' >/sys/kernel/mm/transparent_hugepage/enabled
echo 'never' >/sys/kernel/mm/transparent_hugepage/defrag 

cat >  /mongodb/conf/mongo.conf <<EOF
systemLog:
   destination: file
   path: "/mongodb/log/mongodb.log"
   logAppend: true
storage:
   journal:
      enabled: true
   dbPath: "/mongodb/data/"
processManagement:
   fork: true
net:
   port: 27017
   bindIp: $(ifconfig eth0|awk 'NR==2{print $2}'),127.0.0.1
EOF

cat > /etc/systemd/system/mongod.service <<EOF
[Unit]
Description=mongodb 
After=network.target remote-fs.target nss-lookup.target
[Service]
User=mongod
Type=forking
ExecStart=/mongodb/bin/mongod --config /mongodb/conf/mongo.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/mongodb/bin/mongod --config /mongodb/conf/mongo.conf --shutdown
PrivateTmp=true  
[Install]
WantedBy=multi-user.target
EOF

chown -R mongod:mongod /mongodb
systemctl enable mongod
systemctl start mongod

2.mongodb配置文件介绍

YAML模式

NOTE:
YAML does not support tab characters for indentation: use spaces instead.

--系统日志有关  
systemLog:
   destination: file        
   path: "/mongodb/log/mongodb.log"    --日志位置
   logAppend: true                     --日志以追加模式记录
  
--数据存储有关   
storage:
   journal:
      enabled: true
   dbPath: "/mongodb/data"            --数据路径的位置

-- 进程控制  
processManagement:
   fork: true                         --后台守护进程
   pidFilePath: <string>              --pid文件的位置,一般不用配置,可以去掉这行,自动生成到data中
    
--网络配置有关   
net:            
   bindIp: <ip>                       -- 监听地址
   port: <port>                       -- 端口号,默认不配置端口号,是27017
   
-- 安全验证有关配置      
security:
  authorization: enabled              --是否打开用户名密码验证
  
------------------以下是复制集与分片集群有关----------------------  

replication:
 oplogSizeMB: <NUM>
 replSetName: "<REPSETNAME>"
 secondaryIndexPrefetch: "all"
 
sharding:
   clusterRole: <string>
   archiveMovedChunks: <boolean>
      
---for mongos only
replication:
   localPingThresholdMs: <int>

sharding:
   configDB: <string>
---

YAML配置例子
cat >  /mongodb/conf/mongo.conf <<EOF
systemLog:
   destination: file
   path: "/mongodb/log/mongodb.log"
   logAppend: true
storage:
   journal:
      enabled: true
   dbPath: "/mongodb/data/"
processManagement:
   fork: true
net:
   port: 27017
   bindIp: $(ifconfig eth0|awk 'NR==2{print $2}'),127.0.0.1
EOF
chown -R mongod:mongod /mongodb
su - mongod -s /bin/bash
mongod -f /mongodb/conf/mongo.conf   
mongod -f /mongodb/conf/mongo.conf --shutdown 关闭
su - mongod -s /bin/bash
mongod --dbpath=/mongodb/data --logpath=/mongodb/log/mongodb.log --port=27017 --logappend --fork 手动启动 无需配置文件
mongo 登录

3.mongdb 的使用

3.1 mongdb库

test:登录时默认存在的库
管理MongoDB有关的系统库
admin库:系统预留库,MongoDB系统管理库
local库:本地预留库,存储关键日志
config库:MongoDB配置信息库

database        #数据库
collection  #集合,类似于mysql中的表
filed           #类似于mysql中字段
document    #每行的记录

show databases/show dbs
show tables/show collections 显示表
use admin 
db   当期路径
use admin
db.shutdownServer() 关闭数据库

3.2 集合 增删改查

增加: 无需定义字段约束
use ceshi
db.myuser.insert({name:"ceshi",age:28})
show dbs
show tables
db.myuser.insert({name:"ceshi1",age:30})
db.myuser.insert({tel:123456}) 可随便插入 
查询:
db.myuser.find() 查询
db.myuser.find({name:"ceshi1"}) 有条件查询
db.myuser.find({age:28})
删除:
use ceshi
db.myuser.remove({name:'ceshi1'})
db.myuser.remove({}) 删除表(集合)中数据
db.myuser.drop({}) 删除表
更新:
db.myuser.update({'tel':123456},{$set:{'tel':7654321}})
db.myuser.insert({name:'yy',age:22})
db.myuser.update({name:'yy',age:22},{$set:{name:'ys'}})
删除数据库
use ceshi
db.dropDatabase()

3.3 集合的多种查询

collection数据准备
use shijiange
db.myuser.insert( {name:"shijiange1", age: 20} )
db.myuser.insert( {name:"shijiange2", age: 28} )
db.myuser.insert( {name:"shijiange3", age: 38} )
db.myuser.insert( {name:"zhangsan1", age: 58} )
db.myuser.insert( {name:"zhangsan2", age: 68} )
db.myuser.insert( {name:"zhangsan3", age: 25} )

pretty易读的方式
db.myuser.find().pretty()

limit限制条数查询
db.myuser.find()
db.myuser.find().limit(2)       #查看前面两条记录

使用skip跳过记录
db.myuser.find().skip(2).limit(2)

mongodb分页查询
db.myuser.find().skip(0).limit(2)
db.myuser.find().skip(2).limit(2)
db.myuser.find().skip(4).limit(2)

使用sort进行排序
db.myuser.find().sort({ age: 1 })   #按age升序
db.myuser.find().sort({ age: -1 })  #按age降序

根据字段进行数字比较查询
db.myuser.find({ age: {$lt: 30} })
$gt #大于
$lt #小于
$gte    #大于或等于
$lte    #小于或等于

查询多种条件的组合
db.myuser.find( {name: 'shijiange1'} )
db.myuser.find( {name: 'shijiange2'} )
db.myuser.find({ $or: [ {name: 'shijiange1'},{name: 'shijiange2'} ] })
db.myuser.find({ $and: [ {name: 'shijiange1'},{age: 20} ] })

mongodb正则查询,支持普通正则和扩展正则
db.myuser.find({ name: {$regex: "shijiange[1-9]"} })    #普通正则过滤
db.myuser.find( {"name":{$regex:"(zhangsan)"}} )        #支持分组正则

3.4 索引查询

use shijiange
for(i=1;i<500000;i++){db.myuser.insert({name:'mytset'+i,age:i})}
db.myuser.count() 查询行号
mongodb有慢查询的概念,默认是超过100ms会记录慢日志mongodb.log
db.getProfilingStatus() 打开
查询age为9999的,查看扫描的行数
db.myuser.find( {age:9999} )
db.myuser.find( {age:9999} ).explain(true)  #使用explain可以查看是否全表扫描

tailf /mongodb/log/mongodb.log
2021-03-11T20:49:29.278+0800 I COMMAND  [conn4] command shijiange.myuser appName: "MongoDB Shell" command: find { find: "myuser", filter: { age: 9999.0 }, lsid: { id: UUID("c32761fb-08d2-4309-82a0-55ebf8932614") }, $db: "shijiange" } planSummary: COLLSCAN keysExamined:0 docsExamined:579377 cursorExhausted:1 numYields:4526 nreturned:3 reslen:282 locks:{ Global: { acquireCount: { r: 4527 } }, Database: { acquireCount: { r: 4527 } }, Collection: { acquireCount: { r: 4527 } } } storage:{} protocol:op_msg 169ms

添加索引,加快查询
db.myuser.getIndexes()          #获取当前索引,默认有_id的索引,所以用_id查是比较快
db.myuser.ensureIndex( {age:1} )    #增加age的升序索引
db.myuser.getIndexes()
db.myuser.find( {age:9999} ) 再次查询 
db.myuser.find( {age:9999} ).explain(true)
db.myuser.dropIndex( {age:1} )  #删除索引

使用正则的话,索引无效果
db.myuser.find( {"name":"mytest1"} )
db.myuser.ensureIndex( {name:1} )           #添加索引
db.myuser.find( {"name":"mytest6"} )
db.myuser.find( {"name":/99999/} )
db.myuser.find( {"name":/99999/} ).explain(true)        #使用正则,全表扫描,也是慢

mongodb建立唯一索引,唯一索引对应的值不能重复
use shijiange
db.myuser.insert( {userid:1} )
db.myuser.insert( {userid:1} )
db.myuser.remove({})        #清空数据
db.myuser.ensureIndex( {userid:1},{unique:true} )   #创建唯一索引
db.myuser.insert( {userid:1} )
db.myuser.insert( {userid:2} )
db.myuser.insert( {userid:1} )                  #因为是唯一索引,所以会报错

4.用户及权限管理

验证库: 建立用户时use到的库,在使用用户时,要加上验证库才能登陆。

对于管理员用户,必须在admin下创建.
1. 建用户时,use到的库,就是此用户的验证库
2. 登录时,必须明确指定验证库才能登录
3. 通常,管理员用的验证库是admin,普通用户的验证库一般是所管理的库设置为验证库
4. 如果直接登录到数据库,不进行use,默认的验证库是test,不是我们生产建议的.
5. 从3.6 版本开始,不添加bindIp参数,默认不让远程登录,只能本地管理员登录。

4.1 创建用户语法

use admin 
db.createUser
{
    user: "<name>",
    pwd: "<cleartext password>",
    roles: [
       { role: "<role>",
     db: "<database>" } | "<role>",
    ...
    ]
}

基本语法说明:
user:用户名
pwd:密码
roles:
    role:角色名
    db:作用对象 
role:root, readWrite,read   
验证数据库:
mongo -u <name> -p <cleartext password>10.0.0.154/<验证库>

4.2 创建管理员

创建超级管理员:管理所有数据库(必须use admin再去创建)
$ mongo
use admin
db.createUser(
{
    user: "root",
    pwd: "root123",
    roles: [ { role: "root", db: "admin" } ]
}
)

vim /mongodb/conf/mongo.conf  追加下面
systemLog:
   destination: file
   path: "/mongodb/log/mongodb.log"
   logAppend: true
storage:
   journal:
      enabled: true
   dbPath: "/mongodb/data/"
processManagement:
   fork: true
net:
   port: 27017
   bindIp: 10.0.0.154,127.0.0.1
security:
  authorization: enabled

systemctl restart mongod.service

验证:
mongo -uroot -proot123  admin
mongo -uroot -proot123  10.0.0.154/admin

或者
mongo
use admin
db.auth('root','root123')
查看当前用户
use admin
db.system.users.find().pretty()

4.3 创建读写用户

use app
db.createUser(
    {
        user: "app01",
        pwd: "app01",
        roles: [ { role: "readWrite" , db: "app" } ]
    }
)
验证
mongo  -uapp01 -papp01 10.0.0.154/app
> use app
switched to db app
> db.myuser.insert({name:'app'})
WriteResult({ "nInserted" : 1 })
> db.myuser.find()
{ "_id" : ObjectId("604a18ea31bae3e7c35354a4"), "name" : "app" }
> use rrr
switched to db yyy
> db.myuser.insert({name:'app'})
WriteCommandError({
    "ok" : 0,
    "errmsg" : "not authorized on rrr to execute command { insert: \"myuser\", ordered: true, lsid: { id: UUID(\"9c843ae3-582a-41ea-aed2-0ec601a053f8\") }, $db: \"rrr\" }",
    "code" : 13,
    "codeName" : "Unauthorized"
})

4.4 删除用户

mongo -uroot -proot123 10.0.0.154/admin 
db.system.users.find().pretty() 查询用户验证库
use app 进入验证库
db.dropUser("app01") 

1. 建用户要有验证库,管理员admin,普通用户是要管理的库
2. 登录时,注意验证库
mongo -uapp01 -papp01 10.0.0.154:27017/a
3. 重点参数
net:
   port: 27017
   bindIp: 10.0.0.154,127.0.0.1
security:
   authorization: enabled

5. 副本集 >=3个节点

arbiter节点:主要负责选主过程中的投票,但是不存储任何数据,也不提供任何服务
hidden节点:隐藏节点,不参与选主,也不对外提供服务。
delay节点:延时节点,数据落后于主库一段时间,因为数据是延时的,也不应该提供服务或参与选主,所以通常会配合hidden(隐藏) 延时从库使用
一般情况下会将delay+hidden一起配置使用

5.1 副本集准备

mkdir /mongodb/{28017,28018}/{conf,log,data} -p

cat > /mongodb/28017/conf/mongo.conf <<EOF
systemLog:
  destination: file
  path: /mongodb/28017/log/mongodb.log
  logAppend: true
storage:
  journal:
    enabled: true
  dbPath: /mongodb/28017/data
  directoryPerDB: true
  #engine: wiredTiger
  wiredTiger:
    engineConfig:
      cacheSizeGB: 1
      directoryForIndexes: true
    collectionConfig:
      blockCompressor: zlib
    indexConfig:
      prefixCompression: true
processManagement:
  fork: true
net:
  bindIp: $(ifconfig eth0|awk 'NR==2{print $2}'),127.0.0.1
  port: 28017
replication:
  oplogSizeMB: 2048
  replSetName: my_repl
EOF

cat > /etc/systemd/system/mongod28017.service <<EOF
[Unit]
Description=mongodb 
After=network.target remote-fs.target nss-lookup.target
[Service]
User=mongod
Type=forking
ExecStart=/mongodb/bin/mongod --config /mongodb/28017/conf/mongo.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/mongodb/bin/mongod --config /mongodb/28017/conf/mongo.conf --shutdown
PrivateTmp=true  
[Install]
WantedBy=multi-user.target
EOF

cat > /mongodb/28018/conf/mongo.conf <<EOF
systemLog:
  destination: file
  path: /mongodb/28018/log/mongodb.log
  logAppend: true
storage:
  journal:
    enabled: true
  dbPath: /mongodb/28018/data
  directoryPerDB: true
  #engine: wiredTiger
  wiredTiger:
    engineConfig:
      cacheSizeGB: 1
      directoryForIndexes: true
    collectionConfig:
      blockCompressor: zlib
    indexConfig:
      prefixCompression: true
processManagement:
  fork: true
net:
  bindIp: $(ifconfig eth0|awk 'NR==2{print $2}'),127.0.0.1
  port: 28018
replication:
  oplogSizeMB: 2048
  replSetName: my_repl
EOF

cat > /etc/systemd/system/mongod28018.service <<EOF
[Unit]
Description=mongodb 
After=network.target remote-fs.target nss-lookup.target
[Service]
User=mongod
Type=forking
ExecStart=/mongodb/bin/mongod --config /mongodb/28018/conf/mongo.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/mongodb/bin/mongod --config /mongodb/28018/conf/mongo.conf --shutdown
PrivateTmp=true  
[Install]
WantedBy=multi-user.target
EOF

chown -R mongod:mongod /mongodb
systemctl daemon-reload
systemctl start mongod28017.service
systemctl start mongod28018.service
配置介绍:
  #engine: wiredTiger 数据引擎
  wiredTiger:
    engineConfig:
      cacheSizeGB: 1 相当于mysql buff
      directoryForIndexes: true
replication:
  oplogSizeMB: 2048  相当于mysql binlog  写入表中大小 默认是总磁盘的%5
  replSetName: my_repl  副本集名称 随意

5.2 副本集配置

1主2从,从库普通从库
mongo --port 28017 admin
config = {_id: 'my_repl', members: [
                          {_id: 0, host: '10.0.0.154:28017'},
                          {_id: 1, host: '10.0.0.154:28018'},
                          {_id: 2, host: '10.0.0.155:28017'}]
          }                   
rs.initiate(config) 
查询复制集状态
rs.status();
1主1从1 arbiterOnly 
mongo -port 28017 admin
config = {_id: 'my_repl', members: [
                          {_id: 0, host: '10.0.0.154:28017'},
                          {_id: 1, host: '10.0.0.154:28018'},
                          {_id: 2, host: '10.0.0.155:28017',"arbiterOnly":true}]
          }                
rs.initiate(config) 
rs.status();    //查看整体复制集状态
rs.isMaster(); // 查看当前是否是主节点
rs.conf();   //查看复制集配置信息
rs.slaveOk() 改成 rs.secondaryOk() 从节点不需执行这个才能查看数据 

5.3 副本集优先级调整 切换主从

设置各个实例的优先权重,挑选自己想要的实例为主,只有primary可以更改权重配置
conf = rs.config()          #获取副本集的配置,默认权重都是1
conf.members[0].priority = 10   #索引号从0开始,每次递增1,类似数组
conf.members[1].priority = 5
conf.members[2].priority = 2
rs.reconfig(conf)           #更新mongodb副本集的配置,优先权重最高的提升为primary,关闭启动后也为

conf=rs.config()
conf.members[0].priority=2
conf.members[1].priority=5
conf.members[2].priority=10
rs.reconfig(conf)

或者 
--副本集角色切换(不要人为随便操作)
admin> rs.stepDown()
注:
admin> rs.freeze(300) //锁定从,使其不会转变成主库
freeze()和stepDown单位都是秒。

5.4 副本集增加删除节点

主节点操作PRIMARY: 必须  
use admin
rs.remove("ip:port"); // 删除一个节点 无法移除PRIMARY节点
rs.add("ip:port"); // 新增从节点
rs.addArb("ip:port"); // 新增仲裁节点

use admin
rs.remove("10.0.0.154:28018")
rs.addArb('10.0.0.154:28018')
rs.status(); 查看
"stateStr" : "ARBITER",

5.5 特殊从节点

配置延时节点(一般延时节点也配置成hidden)
cfg=rs.conf() 
cfg.members[2].priority=0  #索引号从0开始,每次递增1,类似数组
cfg.members[2].hidden=true
cfg.members[2].slaveDelay=120
rs.reconfig(cfg)    


取消以上配置
cfg=rs.conf() 
cfg.members[2].priority=1
cfg.members[2].hidden=false
cfg.members[2].slaveDelay=0
rs.reconfig(cfg)    
配置成功后,通过以下命令查询配置后的属性
rs.conf(); 

查看副本节点(监控主从延时)
admin> rs.printSlaveReplicationInfo()
source: 192.168.1.22:27017
    syncedTo: Thu May 26 2016 10:28:56 GMT+0800 (CST)
    0 secs (0 hrs) behind the primary

6. 分片集

image.png
角色 IP地址 shard sh1 shard sh2 configsvr router
db01 10.0.0.154 38017 38018 38019 -
db02 10.0.0.155 38017 38018 38019 -
db03 10.0.0.156 38017 38018 38019 -
db04 10.0.0.157 - - - 38020

6.1 shard sh1 sh2 副本集

mkdir /mongodb/{38017,38018,38019}/{conf,log,data} -p
tar xf mongodb-linux-x86_64-rhel70-4.0.23.tgz
cp -a mongodb-linux-x86_64-rhel70-4.0.23/bin/ /mongodb/
useradd mongod -s /sbin/nologin

cat >/etc/profile.d/mongod.sh <<EOF
export PATH=\$PATH:/mongodb/bin
EOF
source /etc/profile.d/mongod.sh

echo 'if test -f /sys/kernel/mm/transparent_hugepage/enabled; then
  echo never > /sys/kernel/mm/transparent_hugepage/enabled
fi
if test -f /sys/kernel/mm/transparent_hugepage/defrag; then
   echo never > /sys/kernel/mm/transparent_hugepage/defrag
fi' >>/etc/rc.local
chmod +x /etc/rc.d/rc.local

echo 'never' >/sys/kernel/mm/transparent_hugepage/enabled
echo 'never' >/sys/kernel/mm/transparent_hugepage/defrag 
mkdir /mongodb/{38017,38018,38019}/{conf,log,data} -p
cat > /mongodb/38017/conf/mongo.conf <<EOF
systemLog:
  destination: file
  path: /mongodb/38017/log/mongodb.log
  logAppend: true
storage:
  journal:
    enabled: true
  dbPath: /mongodb/38017/data
  directoryPerDB: true
  #engine: wiredTiger
  wiredTiger:
    engineConfig:
      cacheSizeGB: 1
      directoryForIndexes: true
    collectionConfig:
      blockCompressor: zlib
    indexConfig:
      prefixCompression: true
processManagement:
  fork: true
net:
  bindIp: $(ifconfig eth0|awk 'NR==2{print $2}'),127.0.0.1
  port: 38017
replication:
  oplogSizeMB: 2048
  replSetName: sh1
sharding:
  clusterRole: shardsvr
EOF

cat > /etc/systemd/system/mongod38017.service <<EOF
[Unit]
Description=mongodb 
After=network.target remote-fs.target nss-lookup.target
[Service]
User=mongod
Type=forking
ExecStart=/mongodb/bin/mongod --config /mongodb/38017/conf/mongo.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/mongodb/bin/mongod --config /mongodb/38017/conf/mongo.conf --shutdown
PrivateTmp=true  
[Install]
WantedBy=multi-user.target
EOF

chown -R mongod:mongod /mongodb
systemctl daemon-reload
systemctl start mongod38017.service
cat > /mongodb/38018/conf/mongo.conf <<EOF
systemLog:
  destination: file
  path: /mongodb/38018/log/mongodb.log
  logAppend: true
storage:
  journal:
    enabled: true
  dbPath: /mongodb/38018/data
  directoryPerDB: true
  #engine: wiredTiger
  wiredTiger:
    engineConfig:
      cacheSizeGB: 1
      directoryForIndexes: true
    collectionConfig:
      blockCompressor: zlib
    indexConfig:
      prefixCompression: true
processManagement:
  fork: true
net:
  bindIp: $(ifconfig eth0|awk 'NR==2{print $2}'),127.0.0.1
  port: 38018
replication:
  oplogSizeMB: 2048
  replSetName: sh2
sharding:
  clusterRole: shardsvr
EOF

cat > /etc/systemd/system/mongod38018.service <<EOF
[Unit]
Description=mongodb 
After=network.target remote-fs.target nss-lookup.target
[Service]
User=mongod
Type=forking
ExecStart=/mongodb/bin/mongod --config /mongodb/38018/conf/mongo.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/mongodb/bin/mongod --config /mongodb/38018/conf/mongo.conf --shutdown
PrivateTmp=true  
[Install]
WantedBy=multi-user.target
EOF

chown -R mongod:mongod /mongodb
systemctl daemon-reload
systemctl start mongod38018.service
mongo --port 38017
use  admin
config = {_id: 'sh1', members: [
                          {_id: 0, host: '10.0.0.154:38017'},
                          {_id: 1, host: '10.0.0.155:38017'},
                          {_id: 2, host: '10.0.0.156:38017',"arbiterOnly":true}]
           }

rs.initiate(config)
##arbiterOnly 也可以不是
mongo --port 38018
use  admin
config = {_id: 'sh2', members: [
                          {_id: 0, host: '10.0.0.154:38018'},
                          {_id: 1, host: '10.0.0.155:38018'},
                          {_id: 2, host: '10.0.0.156:38018',"arbiterOnly":true}]
           }

rs.initiate(config)

6.2 config节点配置 不允许使用arbiterOnly节点

cat > /mongodb/38019/conf/mongo.conf <<EOF
systemLog:
  destination: file
  path: /mongodb/38019/log/mongodb.log
  logAppend: true
storage:
  journal:
    enabled: true
  dbPath: /mongodb/38019/data
  directoryPerDB: true
  #engine: wiredTiger
  wiredTiger:
    engineConfig:
      cacheSizeGB: 1
      directoryForIndexes: true
    collectionConfig:
      blockCompressor: zlib
    indexConfig:
      prefixCompression: true
processManagement:
  fork: true
net:
  bindIp: $(ifconfig eth0|awk 'NR==2{print $2}'),127.0.0.1
  port: 38019
replication:
  oplogSizeMB: 2048
  replSetName: configReplSet
sharding:
  clusterRole: configsvr
EOF

cat > /etc/systemd/system/mongod38019.service <<EOF
[Unit]
Description=mongodb 
After=network.target remote-fs.target nss-lookup.target
[Service]
User=mongod
Type=forking
ExecStart=/mongodb/bin/mongod --config /mongodb/38019/conf/mongo.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/mongodb/bin/mongod --config /mongodb/38019/conf/mongo.conf --shutdown
PrivateTmp=true  
[Install]
WantedBy=multi-user.target
EOF

chown -R mongod:mongod /mongodb
systemctl daemon-reload
systemctl start mongod38019.service
mongo --port 38019
use  admin
config = {_id: 'configReplSet', members: [
                          {_id: 0, host: '10.0.0.154:38019'},
                          {_id: 1, host: '10.0.0.155:38019'},
                          {_id: 2, host: '10.0.0.156:38019'}]
           }

rs.initiate(config)

6.3 mongos节点配置 注意mongos启动

mkdir /mongodb/38020/{conf,log,data} -p
tar xf mongodb-linux-x86_64-rhel70-4.0.23.tgz
cp -a mongodb-linux-x86_64-rhel70-4.0.23/bin/ /mongodb/
useradd mongod -s /sbin/nologin

cat >/etc/profile.d/mongod.sh <<EOF
export PATH=\$PATH:/mongodb/bin
EOF
source /etc/profile.d/mongod.sh

echo 'if test -f /sys/kernel/mm/transparent_hugepage/enabled; then
  echo never > /sys/kernel/mm/transparent_hugepage/enabled
fi
if test -f /sys/kernel/mm/transparent_hugepage/defrag; then
   echo never > /sys/kernel/mm/transparent_hugepage/defrag
fi' >>/etc/rc.local
chmod +x /etc/rc.d/rc.local

echo 'never' >/sys/kernel/mm/transparent_hugepage/enabled
echo 'never' >/sys/kernel/mm/transparent_hugepage/defrag 
cat > /mongodb/38020/conf/mongos.conf <<EOF
systemLog:
  destination: file
  path: /mongodb/38020/log/mongos.log
  logAppend: true
net:
  bindIp: $(ifconfig eth0|awk 'NR==2{print $2}'),127.0.0.1
  port: 38020
sharding:
  configDB: configReplSet/10.0.0.154:38019,10.0.0.155:38019,10.0.0.156:38019
processManagement: 
  fork: true
EOF
cat > /etc/systemd/system/mongos38020.service <<EOF
[Unit]
Description=mongodb 
After=network.target remote-fs.target nss-lookup.target
[Service]
User=mongod
Type=forking
ExecStart=/mongodb/bin/mongos --config /mongodb/38020/conf/mongos.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/mongodb/bin/mongos --config /mongodb/38020/conf/mongos.conf --shutdown
PrivateTmp=true  
[Install]
WantedBy=multi-user.target
EOF
chown -R mongod:mongod /mongodb
systemctl daemon-reload
systemctl start mongos38020.service
mongo 10.0.0.157:38020/admin

db.runCommand( { addshard : "sh1/10.0.0.154:38017,10.0.0.155:38017,10.0.0.156:38017",name:"shard1"} )
db.runCommand( { addshard : "sh2/10.0.0.154:38018,10.0.0.155:38018,10.0.0.156:38018",name:"shard2"} )

db.runCommand( { listshards : 1 } )
sh.status();

7 使用分片集群 range hash

7.1 range分片配置与测试

7.1.1 激活数据库分片功能

mongo --port 38020 admin
admin>  ( { enablesharding : "数据库名称" } )
例如:
admin> db.runCommand( { enablesharding : "ceshi" } )

7.1.2 指定分片键对集合分片

### 创建索引
use ceshi
> db.vast.ensureIndex( { id: 1 } )
### 开启分片
use admin
> db.runCommand( { shardcollection : "ceshi.vast",key : {id: 1} } )

7.1.3 集合分片验证

admin> use ceshi
ceshi> for(i=1;i<1000000;i++){ db.vast.insert({"id":i,"name":"shenzheng","age":70,"date":new Date()}); }
ceshi> db.vast.stats()

7.1.3 验证结果

use admin
db.runCommand( { enablesharding : "xx" } )
use xx
db.yy.ensureIndex( { id: 1 } )
use admin
db.runCommand( { shardcollection : "xx.yy",key : {id: 1} } )
use xx
for(i=1;i<1000000;i++){ db.yy.insert({"id":i,"name":"shenzheng","age":70,"date":new Date()}); }
db.yy.stats()

7.2 hash分片配置与测试

对boy库下的vast大表进行hash
创建哈希索引
(1)对于boy开启分片功能
mongo --port 38020 admin
use admin
admin> db.runCommand( { enablesharding : "boy" } )
(2)对于boy库下的vast表建立hash索引
use boy
boy> db.vast.ensureIndex( { id: "hashed" } )
(3)开启分片 
use admin
admin > sh.shardCollection( "boy.vast", { id: "hashed" } )
(4)录入10w行数据测试
use boy
for(i=1;i<100000;i++){ db.vast.insert({"id":i,"name":"shenzheng","age":70,"date":new Date()}); }
(5)hash分片结果测试
mongo --port 38017
use boy
db.vast.count();
sh1:PRIMARY> db.vast.count()
50393
mongo --port 38018
use boy
db.vast.count();
sh2:PRIMARY> db.vast.count()
49606

8. balancer操作

https://docs.mongodb.com/manual/tutorial/manage-sharded-cluster-balancer/#schedule-the-balancing-window

mongos的一个重要功能,自动巡查所有shard节点上的chunk的情况,自动做chunk迁移。
什么时候工作?
1、自动运行,会检测系统不繁忙的时候做迁移
2、在做节点删除的时候,立即开始迁移工作
3、balancer只能在预设定的时间窗口内运行

有需要时可以关闭和开启blancer(备份的时候)
mongos> sh.stopBalancer()
mongos> sh.startBalancer()
use config
sh.setBalancerState( true )
db.settings.update({ _id : "balancer" }, { $set : { activeWindow : { start : "3:00", stop : "5:00" } } }, true )

sh.getBalancerWindow()
sh.status()

关于集合的balancer(了解下)
关闭某个集合的balance
sh.disableBalancing("students.grades")
打开某个集合的balancer
sh.enableBalancing("students.grades")
确定某个集合的balance是开启或者关闭
db.getSiblingDB("config").collections.findOne({_id : "students.grades"}).noBalance;

9. mongodb 备份 恢复

9.1 备份工具介绍

9.1.1 备份工具介绍

(1)**   mongoexport/mongoimport
(2)***** mongodump/mongorestore

9.1.2 备份工具区别

应用场景总结:
mongoexport/mongoimport:json csv 
1、异构平台迁移  mysql  <---> mongodb
2、同平台,跨大版本:mongodb 2  ----> mongodb 3
mongodump/mongorestore
日常备份恢复时使用.

9.2 导出工具mongoexport

use oldboy
for(i=1;i<10000;i++){ db.log.insert({"id":i,"name":"shenzheng","age":70,"date":new Date()}); }

mongoexport具体用法如下所示:
$ mongoexport --help  
参数说明:
-h:指明数据库宿主机的IP
-u:指明数据库的用户名
-p:指明数据库的密码
-d:指明数据库的名字
-c:指明collection的名字
-f:指明要导出那些列
-o:指明到要导出的文件名
-q:指明导出数据的过滤条件
--authenticationDatabase admin

1.单表备份至json格式
mongoexport -uroot -proot123 --port 27017 --authenticationDatabase admin -d oldboy -c log -o /mongodb/log.json

注:备份文件的名字可以自定义,默认导出了JSON格式的数据。

2. 单表备份至csv格式
如果我们需要导出CSV格式的数据,则需要使用----type=csv参数:

 mongoexport -uroot -proot123 --port 27017 --authenticationDatabase admin -d oldboy -c log --type=csv -f id,name,age,date  -o /mongodb/log.csv

9.3 导入工具mongoimport

$ mongoimport --help
参数说明:
-h:指明数据库宿主机的IP
-u:指明数据库的用户名
-p:指明数据库的密码
-d:指明数据库的名字
-c:指明collection的名字
-f:指明要导入那些列
-j, --numInsertionWorkers=<number>  number of insert operations to run concurrently                                                  (defaults to 1)
//并行
数据恢复:
1.恢复json格式表数据到log1
mongoimport -uroot -proot123 --port 27017 --authenticationDatabase admin -d oldboy -c log1 /mongodb/log.json
2.恢复csv格式的文件到log2
上面演示的是导入JSON格式的文件中的内容,如果要导入CSV格式文件中的内容,则需要通过--type参数指定导入格式,具体如下所示:
[root@db01 mongodb]# head -n10 log.csv   csv备份中有一行数据
id,name,age,date
1,shenzheng,70,2021-03-15T08:18:31.722Z
2,shenzheng,70,2021-03-15T08:18:32.539Z
3,shenzheng,70,2021-03-15T08:18:32.541Z
4,shenzheng,70,2021-03-15T08:18:32.541Z
5,shenzheng,70,2021-03-15T08:18:32.542Z

注意:
(1)csv格式的文件头行,有列名字
mongoimport   -uroot -proot123 --port 27017 --authenticationDatabase admin   -d oldboy -c log2 --type=csv --headerline --file  /mongodb/log.csv

(2)csv格式的文件头行,没有列名字
mongoimport   -uroot -proot123 --port 27017 --authenticationDatabase admin   -d oldboy -c log3 --type=csv -f id,name,age,date --file  /mongodb/log.csv
--headerline:指明第一行是列名,不需要导入。

9.4 案例 mysql数据导入mongodb中

wget https://downloads.mysql.com/docs/world.sql.zip

world数据库下city表进行导出,导入到mongodb

(1)mysql开启安全路径
vim /etc/my.cnf   --->添加以下配置
secure-file-priv=/tmp

--重启数据库生效
/etc/init.d/mysqld restart

(2)导出mysql的city表数据
source /root/world.sql

select * from world.city into outfile '/tmp/city1.csv' fields terminated by ',';

(3)处理备份文件
desc world.city
  ID          | int(11)  | NO   | PRI | NULL    | auto_increment |
| Name        | char(35) | NO   |     |         |                |
| CountryCode | char(3)  | NO   | MUL |         |                |
| District    | char(20) | NO   |     |         |                |
| Population

vim /tmp/city.csv   ----> 添加第一行列名信息

ID,Name,CountryCode,District,Population

(4)在mongodb中导入备份
mongoimport -uroot -proot123 --port 27017 --authenticationDatabase admin -d world  -c city --type=csv -f ID,Name,CountryCode,District,Population --file  /tmp/city1.csv

use world
db.city.find({CountryCode:"CHN"});

-------------
world共100张表,全部迁移到mongodb

select table_name ,group_concat(column_name) from columns where table_schema='world' group by table_name;

select * from world.city into outfile '/tmp/world_city.csv' fields terminated by ',';

select concat("select * from ",table_schema,".",table_name ," into outfile '/tmp/",table_schema,"_",table_name,".csv' fields terminated by ',';")
from information_schema.tables where table_schema ='world';

导入:
提示,使用infomation_schema.columns + information_schema.tables

mysql导出csv:
select * from test_info   
into outfile '/tmp/test.csv'   
fields terminated by ','    ------字段间以,号分隔
optionally enclosed by '"'   ------字段用"号括起
escaped by '"'           ------字段中使用的转义符为"
lines terminated by '\r\n';  ------行以\r\n结束

mysql导入csv:
load data infile '/tmp/test.csv'   
into table test_info    
fields terminated by ','  
optionally enclosed by '"' 
escaped by '"'   
lines terminated by '\r\n'; 

9.5 mongodump和mongorestore

mongodump能够在Mongodb运行时进行备份,它的工作原理是对运行的Mongodb做查询,然后将所有查到的文档写入磁盘。
但是存在的问题时使用mongodump产生的备份不一定是数据库的实时快照,如果我们在备份时对数据库进行了写入操作,
则备份出来的文件可能不完全和Mongodb实时数据相等。另外在备份时可能会对其它客户端性能产生不利的影响。

9.5.1 mongodump的使用

$ mongodump --help
参数说明:
-h:指明数据库宿主机的IP
-u:指明数据库的用户名
-p:指明数据库的密码
-d:指明数据库的名字
-c:指明collection的名字
-o:指明到要导出的文件名
-q:指明导出数据的过滤条件
-j, --numParallelCollections=  number of collections to dump in parallel (4 by default)
--oplog  备份的同时备份oplog

全库备份
mkdir /mongodb/backup
mongodump -uroot -proot123 --port 27017 --authenticationDatabase admin -o /mongodb/backup
[root@db01 ~]# ll /mongodb/backup
总用量 0
drwxr-xr-x 2 root root 128 3月  16 08:48 admin
drwxr-xr-x 2 root root  53 3月  16 08:48 app
drwxr-xr-x 2 root root 176 3月  16 08:48 oldboy
drwxr-xr-x 2 root root  53 3月  16 08:48 shijiange
drwxr-xr-x 2 root root  49 3月  16 08:48 world
备份单库
mongodump   -uroot -proot123 --port 27017 --authenticationDatabase admin -d world -o /mongodb/backup/
备份单表集合
mongodump   -uroot -proot123 --port 27017 --authenticationDatabase admin -d oldboy -c log -o /mongodb/backup/
压缩备份
mongodump   -uroot -proot123 --port 27017 --authenticationDatabase admin -d oldguo -o /mongodb/backup/ --gzip
mongodump   -uroot -proot123 --port 27017 --authenticationDatabase admin -o /mongodb/backup/ --gzip
mongodump   -uroot -proot123 --port 27017 --authenticationDatabase admin -d app -c myuser -o /mongodb/backup/ --gzip
[root@db01 ~]# ll /mongodb/backup/app/
总用量 16
-rw-r--r-- 1 root root  36 3月  16 08:48 myuser.bson
-rw-r--r-- 1 root root  61 3月  16 08:52 myuser.bson.gz
-rw-r--r-- 1 root root 124 3月  16 08:48 myuser.metadata.json
-rw-r--r-- 1 root root 129 3月  16 08:52 myuser.metadata.json.gz
bsondump myuser.bson 可以将bson转成json格式查看

9.5.2 mongorestore的使用

恢复单库
mongorestore   -uroot -proot123 --port 27017 --authenticationDatabase admin -d world1  /mongodb/backup/world
恢复单表
mongorestore   -uroot -proot123 --port 27017 --authenticationDatabase admin -d world -c t1  --gzip  /mongodb/backup/app/myuser.bson.gz 
drop表示恢复的时候把之前的集合drop掉(危险)
mongorestore  -uroot -proot123 --port 27017 --authenticationDatabase admin -d oldboy --drop  /mongodb/backup/oldboy

10 mongodump、mongorestore高级应用 --oplog

10.1 oplog介绍 副本集或者主从才有

在replica set中oplog是一个定容集合(capped collection),它的默认大小是磁盘空间的5%(可以通过--oplogSizeMB参数修改).

位于local库的db.oplog.rs
其中记录的是整个mongod实例一段时间内数据库的所有变更(插入/更新/删除)操作。
当空间用完时新记录自动覆盖最老的记录。
其覆盖范围被称作oplog时间窗口。需要注意的是,因为oplog是一个定容集合,
所以时间窗口能覆盖的范围会因为你单位时间内的更新次数不同而变化。
想要查看当前的oplog时间窗口预计值,可以使用以下命令:
 use local 
 db.oplog.rs.find().pretty()
"ts" : Timestamp(1553597844, 1),
"op" : "n"
"o"  :

"i": insert
"u": update
"d": delete
"c": db cmd

my_repl:PRIMARY> rs.printReplicationInfo()
configured oplog size:   2048MB   集合大小
log length start to end: 40746secs (11.32hrs)  预计日志覆盖时间
oplog first event time:  Tue Mar 16 2021 09:20:59 GMT+0800 (CST)
oplog last event time:   Tue Mar 16 2021 20:40:05 GMT+0800 (CST)
now:                     Tue Mar 16 2021 20:40:10 GMT+0800 (CST)
集合大小的设置 根据备份周期设置 
例如设置2048M 预计11.32小时重复覆盖日志 如果备份周期24H 设置是不合适的

10.2 oplog企业级应用

(1)实现热备,在备份时使用--oplog选项
注:为了演示效果我们在备份过程,模拟数据插入
(2)准备测试数据
[mongod@db01 conf]$ mongo --port 28018
my_repl:PRIMARY> use local
my_repl:PRIMARY> db.oplog.rs.find({"op":"i"}).count()
103

use oldboy
for(var i = 1 ;i < 100; i++) {
    db.foo.insert({a:i});
}
my_repl:PRIMARY> use local
my_repl:PRIMARY> db.oplog.rs.find({"op":"i"}).pretty()
202
oplog 配合mongodump实现热备
mongodump --port 28018 --oplog -o /mongodb/backup
[root@db01 backup]# ll /mongodb/backup
总用量 4
drwxr-xr-x 2 root root  69 3月  16 20:50 admin
drwxr-xr-x 2 root root  47 3月  16 20:50 oldboy
-rw-r--r-- 1 root root 110 3月  16 20:50 oplog.bson
作用介绍:--oplog 会记录备份过程中的数据变化。会以oplog.bson保存下来
恢复
mongorestore  --port 28018 --oplogReplay /mongodb/backup

10.3 oplog高级应用

背景:每天0点全备,oplog恢复窗口为48小时
某天,上午10点world.city 业务表被误删除。
恢复思路:
    0、停应用
    2、找测试库
    3、恢复昨天晚上全备
    4、截取全备之后到world.city误删除时间点的oplog,并恢复到测试库
    5、将误删除表导出,恢复到生产库

恢复步骤:
模拟故障环境:

1、全备数据库
模拟原始数据

mongo --port 28018
use wo
for(var i = 1 ;i < 20; i++) {
    db.ci.insert({a: i});
}

全备:
rm -rf /mongodb/backup/*
mongodump --port 28018 --oplog -o /mongodb/backup

--oplog功能:在备份同时,将备份过程中产生的日志进行备份
文件必须存放在/mongodb/backup下,自动命令为oplog.bson

再次模拟数据
db.ci1.insert({id:1})
db.ci2.insert({id:2})


2、上午10点:删除wo库下的ci表
10:00时刻,误删除
db.ci.drop()
show tables;

3、备份现有的oplog.rs表
mongodump --port 28018 -d local -c oplog.rs  -o /mongodb/backup

4、截取oplog并恢复到drop之前的位置
更合理的方法:登陆到原数据库
[mongod@db03 local]$ mongo --port 28018
my_repl:PRIMARY> use local
db.oplog.rs.find({op:"c"}).pretty();
{
    "ts" : Timestamp(1615899485, 1),
    "t" : NumberLong(1),
    "h" : NumberLong("-6643941241438205217"),
    "v" : 2,
    "op" : "c",
    "ns" : "wo.$cmd",
    "ui" : UUID("37f2cb0a-fc60-482c-a358-d2214da0bfc2"),
    "wall" : ISODate("2021-03-16T12:58:05.706Z"),
    "o" : {
        "drop" : "ci"
    }
}


获取到oplog误删除时间点位置:
"ts" : Timestamp(1615899485, 1)

 5、恢复备份+应用oplog
[mongod@db03 backup]$ cd /mongodb/backup/local/
[mongod@db03 local]$ ls
oplog.rs.bson  oplog.rs.metadata.json
[mongod@db03 local]$ cp oplog.rs.bson ../oplog.bson 
rm -rf /mongodb/backup/local/
 
mongorestore --port 28018  --oplogReplay --oplogLimit "1615899485:1"  --drop   /mongodb/backup/
验证:
my_repl:PRIMARY> show dbs;
admin   0.000GB
config  0.000GB
local   0.000GB
oldboy  0.000GB
wo      0.000GB
my_repl:PRIMARY> use wo;
switched to db wo
my_repl:PRIMARY> show tables;
ci
ci1
ci2
my_repl:PRIMARY> db.ci.count()
19
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • MongoDB 是一个基于分布式文件存储的 NoSQL 开源(遵循 SSPL 协议)数据库,旨在为 WEB 应用提...
    张毅SOHO阅读 935评论 0 6
  • 基本介绍 什么是NoSQL数据库 NoSQL,指的是非关系型的数据库。NoSQL有时也称作Not Only SQL...
    我就是小政政阅读 2,117评论 0 11
  • 一、简介: MongoDB 由C++编写,是一个基于分布式文件存储的开源数据库系统。在高负载的情况下,添加更多的节...
    柏666阅读 212评论 0 0
  • 一、MongoDB特点 1.内置GridFS,支持大容量的存储:GridFS是一个出色的分布式文件系统,可以支持海...
    EmmaQin阅读 176评论 0 0
  • 随着分布式的发展,传统数据库越来越无法支撑大型并发场景下的数据存储,Nosql数据库占据的比重越来越大,其中Mon...
    逐梦々少年阅读 23,490评论 0 4