MongoDB NoSQL使用
[toc]
NoSQL: Not Only SQL

常用需求及实现
| 大数据问题: BigData |
| 并行数据库系统,无共享体系结构中,采用关系结构模型,像MySQL的水平切片技术,分区查询; |
| NoSQL数据库管理系统: 不是一种单一单纯的技术,非关系模型、分布式、不支持ACID数据库设计范式; |
| 简单数据模型; |
| 元数据和数据分离; |
| 弱一致性; |
| 高吞吐量; |
| 高水平扩展能力和低端硬件集群; |
| NewSQL数据库管理系统 |
| 相关产品: Clustrix、 GenleDB 、ScaleBase、NimbusDB、mysql(NDBCluster、Drizzle) |
| 云数据管理系统: |
| 相关产品: DBAAS,RDS |
| |
| 大数据的分析处理: |
| 常见的有MapReduce机制:将大的数据映射成键值对,而后对各各键值对处理后进行聚合; |
| 而hadoop 就是类似于这种系统; habase也是NoSQL的一种; |
| CAP: 强一致性;可用性;分区容错性(出现脑裂的时候可否处理业务需求); |
| 最终一致性细分: |
| 困果一致性; |
| 读自己写一致性; |
| 会话一致性; |
| 单调读一致性; |
| 时间轴一致性; |
| |
| ACID & BASE |
| Atomicity 原子性; |
| Consistency 一致性; |
| Isolation 隔离性 ; |
| Durability 持久性; |
| BASE 基本可用; |
| |
| ACID特性: 强一致性、隔离性、采用悲观保守的方法、难以变化; |
| BASE特性: 弱一致性、可用性优先、采用乐观的方法、更简单、更快; |
| |
| 数据一致性的实现技术: |
| NRW |
| 2PC |
| Paxos |
| Vecotr Clock |
| |
| 数据存储模型: www.nosql-databases.org |
| 列式存储模型 |
| 文档存储模型 |
| 键值数据模型 |
| 图式数据模型 |
| 列式模型: |
| 应用场景: 在分布式文件系统之上提供支持随机读写分布式数据存储; |
| 典型产品: HBase、Hypertable、Cassandra |
| 数据模型: 以"列"为中心进行存储 ,将同一列数据存储在一起; |
| 优点: 快速查询、高可扩展性、易于实现分布式扩展; |
| |
| 文档模型: |
| 应用场景:非强事务需求的web应用; |
| 典型产品:MongoDB、ElasticSearch(构建的搜索引擎工具)、CouchDB、CouchBase Server |
| 数据模型: 键值模型,存储为文档; |
| 优点: 数据模型无需事先定义 |
| |
| 键值模型: |
| 应用场景: 内容缓存,用于大量并行数据访问高载场景; |
| 典型产品: Redis、DynamoDB、Riak、Redis; |
| 数据模型: 基于哈希表实现的key-value模型; |
| 优点: 查询迅速, 缺点:数据没有结构; |
| |
| 图式模型: |
| 应用场景: 社交网络、推荐系统、关系图普 |
| 典型产品: Neo4J 、TITAN 、 Infinite Graph |
| 数据模型: 图式结构 |
| 优点: 适应于图式计算场景 |
| |
| MongoDB: NoSQL、文档存储、Json数据模型 |
| 适用场景: |
| Websites |
| Caching |
| High volume, low value |
| High scalability |
| Storage of program objects and json |
| 不适用场景: |
| Hightly transactional |
| Ad-hoc business intelligence |
| Problems requiring SQL |
mongo 的安装与使用
| |
| [mongodb-org-3.4] |
| name=MongoDB Repository |
| baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/3.4/x86_64/ |
| gpgcheck=1 |
| enabled=1 |
| gpgkey=https://www.mongodb.org/static/pgp/server-3.4.asc |
| |
| |
| |
server包生成的关键文件
| |
| /etc/mongod.conf |
| /lib/systemd/system/mongod.service |
| /usr/bin/mongod |
| /var/lib/mongo |
| /var/log/mongodb |
| /var/log/mongodb/mongod.log |
| /var/run/mongodb |
shell包生成的关键文件
| |
| /usr/bin/bsondump |
| /usr/bin/mongodump |
| /usr/bin/mongoexport |
| /usr/bin/mongofiles |
| /usr/bin/mongoimport |
| /usr/bin/mongooplog |
| /usr/bin/mongoperf |
| /usr/bin/mongorestore |
| /usr/bin/mongostat |
| /usr/bin/mongotop |
server端配置项
Mongo基本操作
| help |
| db.help() |
| db.mycoll.cind().help() |
| db.mycoll.help() |
| show dbs |
| show collections |
| use testdb |
| db.status() |
| db.version() |
| db.serverStatus() |
| show users |
| show logs |
| user db.help() |
| db.getCollectionNames() |
| db.students.status() |
| |
| db.users.find( {age: {$gt: 18} } ).sort( {age: 1} ) |
| JSON: JavaScript Object Notation |
| 名称/值对象的集合; |
| 值的有序列表; |
| db.students.inert( {name:"tome", age:23} ) |
| show clollections |
| show dbs |
| db.status |
| db.students.stats() |
| db.getCollectionNames() |
| db.students.insert([name:''renjin",age:23,gender:"M"]) |
| db.students.find() |
| db.students.insert([name:"ssjinyao",Age:23,Course:"PieXieJianFa"]) |
| find() 的高级用法: |
| 比较操作: |
| $gt, 语法格式{filed: {$gt VALUE}} |
| db.statuents.find({Age:{$gt 23}}) |
| $gte |
| $lt |
| $lte |
| $ne |
| $in,语法格式{filed: {$in: ['value']}} |
| db.students.find{Age:{$in: [20,23]}} |
| 组合条件: 逻辑运算 |
| $or: 或运算,语法格式{$or: {<expression1>,...}} |
| db.students.find({$or: {Age: {$nin: [20,40], age {$nin:[20,40]}}}) |
| db.students.find({$or: [{Age: {$nin: [20,40]}}, {age: {$nin: [20,40]}}]}) |
| $and: 与运算 |
| $not: 非运算 |
| $nor: 反运算,返回不符指定件的所有文档 |
| |
| 元素查询: 根据文档中是否存在指定的字段进行查询; |
| $exists: 语法格式{$filed:{$exists:<boolean>}} |
| db.students.find({gender: {$exits: false}}) |
| $mod: |
| $type: 返回指定的字段的值的类型为指定类型的文档,语法格式{field:{$type: <BSON type>}} |
| Double,String,Object, Arrary, Binary data, Undefined, Boolean,Data ,Null, Regular Expression, JavaScript, Timestamp |
| |
| 更新操作: |
| db.mycoll.update() |
| $set: 修改字段的值为新指定的值: 语法格式{filed: value}, {$set: {filed: new_value}}) |
| $unset: 删除指定字段;语法格式({filed: value}, {$unset:{filed1, field2,....}}) |
| db.students.update({name: "renjin"}, {$set: {age: 22}}) |
| $rename: 更改字段名,语法格式({$rename: {oldname: newname, oldname: newname}}) |
| db.students.update({$rename: {age:Age}) |
| $inc |
| |
| 删除操作: |
| db.mycoll.remove(<query>,<justOne>) |
| db.students.remove({age:21}) |
| db.students.findOne({Age: {$gt:10}}) |
| 删除collection: |
| db.mycoll.drop() |
| db.studetns.drop() |
| 删除database: |
| db.dropDatabase() |
| |
| php+mongodb |
| php的mongo扩展 |
MongoDB Indexes and Administration
索引
类型: B+ Tree、hash、空间索引、全文索引
| MongoDB索引类型 |
| 单字段索引 |
| 组合索引(多字段索引) |
| 多键索引 |
| 空间索引 |
| 文本索引 |
| hash索引 hash 索引只支持精确值查找 |
| db.people.ensureIndex({ zipcode:1}, {background: ture}) |
| db.account.ensureIndex( { username: 1 } , {unique: ture, dropDups: true }) |
| |
| MongoDB与索引相关的方法: |
| db.mycoll.ensureIndex(field[,options]) |
| name、unique、dropDups、sparse |
| db.mycoll.dropIndex(index_name) |
| db.mycoll.dropIndexes() |
| db.mycoll.getIndexes() |
| db.mycoll.reIndex() |
mongodb 用for 循环来连续插入数据
| use testdb |
| for (i=1; i<=1000;i++) db.students.insert({name:"student"+i, age:(i%120), address:"#85 Wenhua Road, Zhengzhou, China"}) |
| { "_id" : ObjectId("5acdb56cdf2f304c1068d56c"), "name" : "student1", "age" : 1, "address" : "#85 Wenhua Road, Zhengzhou, China" } |
| { "_id" : ObjectId("5acdb56cdf2f304c1068d56d"), "name" : "student2", "age" : 2, "address" : "#85 Wenhua Road, Zhengzhou, China" } |
| { "_id" : ObjectId("5acdb56cdf2f304c1068d56e"), "name" : "student3", "age" : 3, "address" : "#85 Wenhua Road, Zhengzhou, China" } |
| { "_id" : ObjectId("5acdb56cdf2f304c1068d56f"), "name" : "student4", "age" : 4, "address" : "#85 Wenhua Road, Zhengzhou, China" } |
| { "_id" : ObjectId("5acdb56cdf2f304c1068d570"), "name" : "student5", "age" : 5, "address" : "#85 Wenhua Road, Zhengzhou, China" } |
| { "_id" : ObjectId("5acdb56cdf2f304c1068d571"), "name" : "student6", "age" : 6, "address" : "#85 Wenhua Road, Zhengzhou, China" } |
| { "_id" : ObjectId("5acdb56cdf2f304c1068d572"), "name" : "student7", "age" : 7, "address" : "#85 Wenhua Road, Zhengzhou, China" } |
| { "_id" : ObjectId("5acdb56cdf2f304c1068d573"), "name" : "student8", "age" : 8, "address" : "#85 Wenhua Road, Zhengzhou, China" } |
| { "_id" : ObjectId("5acdb56cdf2f304c1068d574"), "name" : "student9", "age" : 9, "address" : "#85 Wenhua Road, Zhengzhou, China" } |
| { "_id" : ObjectId("5acdb56cdf2f304c1068d575"), "name" : "student10", "age" : 10, "address" : "#85 Wenhua Road, Zhengzhou, China" } |
| { "_id" : ObjectId("5acdb56cdf2f304c1068d576"), "name" : "student11", "age" : 11, "address" : "#85 Wenhua Road, Zhengzhou, China" } |
| { "_id" : ObjectId("5acdb56cdf2f304c1068d577"), "name" : "student12", "age" : 12, "address" : "#85 Wenhua Road, Zhengzhou, China" } |
| { "_id" : ObjectId("5acdb56cdf2f304c1068d578"), "name" : "student13", "age" : 13, "address" : "#85 Wenhua Road, Zhengzhou, China" } |
| { "_id" : ObjectId("5acdb56cdf2f304c1068d579"), "name" : "student14", "age" : 14, "address" : "#85 Wenhua Road, Zhengzhou, China" } |
| { "_id" : ObjectId("5acdb56cdf2f304c1068d57a"), "name" : "student15", "age" : 15, "address" : "#85 Wenhua Road, Zhengzhou, China" } |
| { "_id" : ObjectId("5acdb56cdf2f304c1068d57b"), "name" : "student16", "age" : 16, "address" : "#85 Wenhua Road, Zhengzhou, China" } |
| { "_id" : ObjectId("5acdb56cdf2f304c1068d57c"), "name" : "student17", "age" : 17, "address" : "#85 Wenhua Road, Zhengzhou, China" } |
| { "_id" : ObjectId("5acdb56cdf2f304c1068d57d"), "name" : "student18", "age" : 18, "address" : "#85 Wenhua Road, Zhengzhou, China" } |
| { "_id" : ObjectId("5acdb56cdf2f304c1068d57e"), "name" : "student19", "age" : 19, "address" : "#85 Wenhua Road, Zhengzhou, China" } |
| { "_id" : ObjectId("5acdb56cdf2f304c1068d57f"), "name" : "student20", "age" : 20, "address" : "#85 Wenhua Road, Zhengzhou, China" } |
| Type "it" for more |
| > it |
| |
在name 1 上构建升序索引
| db.students.ensureIndex({name: 1}) |
| { |
| "createdCollectionAutomatically" : false, |
| "numIndexesBefore" : 1, |
| "numIndexesAfter" : 2, |
| "ok" : 1 |
| } |
| db.students.getIndexes() |
| [ |
| { |
| "v" : 2, |
| "key" : { |
| "_id" : 1 |
| }, |
| "name" : "_id_", |
| "ns" : "testdb.students" |
| }, |
| { |
| "v" : 2, |
| "key" : { |
| "name" : 1 |
| }, |
| "name" : "name_1", |
| "ns" : "testdb.students" |
| } |
| ] |
移除之前建立的索引
| db.students.dropIndex("name_1") |
| { "nIndexesWas" : 2, "ok" : 1 } |
查看索引是否被移除
| db.students.getIndexes() |
| [ |
| { |
| "v" : 2, |
| "key" : { |
| "_id" : 1 |
| }, |
| "name" : "_id_", |
| "ns" : "testdb.students" |
| } |
| ] |
建立维一键索引
| db.students.ensureIndex({name: 1},{unique: true}) |
| { |
| "createdCollectionAutomatically" : false, |
| "numIndexesBefore" : 1, |
| "numIndexesAfter" : 2, |
| "ok" : 1 |
| } |
| > |
| > |
| > db.students.getIndexes() |
| [ |
| { |
| "v" : 2, |
| "key" : { |
| "_id" : 1 |
| }, |
| "name" : "_id_", |
| "ns" : "testdb.students" |
| }, |
| { |
| "v" : 2, |
| "unique" : true, |
| "key" : { |
| "name" : 1 |
| }, |
| "name" : "name_1", |
| "ns" : "testdb.students" |
| } |
| ] |
利用索引快速查询
| db.students.find({name: "student500"}) |
| { "_id" : ObjectId("5acdb56cdf2f304c1068d75f"), "name" : "student500", "age" : 20, "address" : "#85 Wenhua Road, Zhengzhou, China" } |
| db.students.find({name: "student500"}).explain() |
查看索引执行过程
| { |
| "queryPlanner" : { |
| "plannerVersion" : 1, |
| "namespace" : "testdb.students", |
| "indexFilterSet" : false, |
| "parsedQuery" : { |
| "name" : { |
| "$eq" : "student500" |
| } |
| }, |
| "winningPlan" : { |
| "stage" : "FETCH", |
| "inputStage" : { |
| "stage" : "IXSCAN", |
| "keyPattern" : { |
| "name" : 1 |
| }, |
| "indexName" : "name_1", |
| "isMultiKey" : false, |
| "multiKeyPaths" : { |
| "name" : [ ] |
| }, |
| "isUnique" : true, |
| "isSparse" : false, |
| "isPartial" : false, |
| "indexVersion" : 2, |
| "direction" : "forward", |
| "indexBounds" : { |
| "name" : [ |
| "[\"student500\", \"student500\"]" |
| ] |
| } |
| } |
| }, |
| "rejectedPlans" : [ ] |
| }, |
| "serverInfo" : { |
| "host" : "ssjinyao", |
| "port" : 27017, |
| "version" : "3.4.14", |
| "gitVersion" : "fd954412dfc10e4d1e3e2dd4fac040f8b476b268" |
| }, |
| "ok" : 1 |
| } |
Mongod的常用先项:
| General option: 通用选项 |
| fork = {true|false}: mongod是否运行在后台; |
| bind_ip = IP: 指定监听的地址; |
| port=PORT:指定监听的端口,默认为27017,httpd访问28017; |
| maxConns=: 并发最大连接数; |
| pidfilepath=: pid 文件位置; |
| httpinterface=:内置httpd统计信息等; |
| keyFile=:主从同步基于密钥的认证; |
| auth: 是否开启认证功能; |
| repair: 服务器意外重启,或未正重关闭时,要使用repair来修复; |
| journal:是否启用日志功能; |
| jounalCommit: 日志提交的时间间隔; |
| cpu: 间断性的显示内存CPU的使用率; |
| slowms arg: 超出指定值后采用慢查询; |
| Replication options 复制选项 |
| Master/slvae options 主从复制选项 |
| Replica set options 复制集选项 |
| Sharding options 跟切片相关的选项 |
MongoDB的复制功能
| 两种类型: |
| master/slave |
| replica set: 复制集、副本集 |
| 两种类型: 主节点支持读写操作,而从节点仅支持读操作; |
| 服务于同一数据集的多个mongodb实例; |
| 主节点操作数据修改操作保存至oplog中; |
| arbiter: 仲裁者,即便用不上三个节点,也添加三个节点,以避免脑裂; |
| 工作特性:至少三个,且应该为奇数据个节点;可以使用arbiter来参与选举; |
| hertbeat(默认2s传递一次),自动失效转移(通过选举方式实现) |
| |
| 复制集的中节点分类的集中类型: |
| 0优先级的节点: 准备节点,这种节点不会选举成为主节点,但可以参与选举过程; |
| 被隐藏的从节点: 首先是一个0优先级的从节点,且地客户端不可见; |
| 延迟复制的从节点: 当在主节点误删除数据时,可以立即断开主从,可保留从节点上未改变的数据; |
| 首先是一个0优先级的从节点,且复制时间落后于主节点一个固定时长; |
| arbiter: |
| MongoDB的复制架构: |
| oplog |
| heartbeat |
| |
| oplog: 大小固定的文件,存储在local数据库中; |
| 即便从节点有aplog也不会使用; |
| 初始同步(initial sync) |
| 回滚后追赶(post-rollback catch-up) |
| 切分块迁移(sharding chunk migrations) |
| |
| local: 存放了副本集的所有元数据和oplog: 用于存储aplog的是一个名为oplog.rs的collection |
| aplog.rs 的大小依赖于OS 及文件系统 ; |
| |
| Mongo的数同步类型 : |
| 初始同步: |
| 节点没有任何数据时 |
| 节点丢失副本复制历史 |
| 复制 |
| |
| 初始同步的步骤: |
| 1、克隆所有数据; |
| 2、应用数据集的所有改变,复制oplog并应用于本地; |
| 3、为所有collection构建索引; |
Mongod 数据同步过程
| 初始同步: |
| 节点没有任何数据 |
| 从节点丢失复本,复制历史数据; |
| 初始同步的步骤: |
| 1、克隆所有数据库; |
| 2、应用数据集的所有改变;复制oplog并应用在本地; |
| 3、为所有的collection构建索引; |
| 这样初始同步就完成了; |
| 优于MySQL的地方, MongoDB 支持多线程复制功能; |
| |
| replSet=testSet |
| replIndexPrefetch=_id_only |
| |
| |
| show dbs |
| use local |
| show collections |
| # node2的配置 |
| # 将需要安装的rpm 包复制到第二个节点上,或者在另一台服务器上配置mongo的yum源; |
| # yum -y install mongodb-org-server |
| # mkdir -pv /mongodb/data |
| # chown -R mongod.mongod /mongodb |
| # node3的配置 |
| # 将需要安装的rpm 包复制到第三个节点上,或者在另一台服务器上配置mongo的yum源; |
| # yum -y install mongodb-org-server |
| # mkdir -pv /mongodb/data |
| # chown -R mongod.mongod /mongodb |
| # scp /etc/mongod.conf root@node2:/etc/ |
| # scp /etc/mongod.conf root@node3:/etc/ |
| # 保证三个节点的配置文件一致,并将服务器启动; |
| rs.conf() |
| rs.status() |
| rs.initiate() |
| rs.status() |
| rs.help() # 查找mongo的帮助文档,查看如何添加主机进来, rs. 主要指mongo的分布式配置; |
| rs.add("172.16.55.128") # 在主节点的mongo中执行; |
| show dbs |
| # 从节点默认是不支持查询的,因此需要手动开启; |
| # 在node2 节点中,将当前服务器节点改为从节点; |
| rs.salveOK() |
| rs.status() |
| rs.isMaster() # 查看自己是否为主节点; |
| # 因此,当服务器改为从节点之后可以在从节点上查询信息; |
| # db.statudents.findOne(); |
| # 第三个节点 |
| rs.add("172.16.55.129") # 在主节点的mongo中执行 |
| # 在 node3 节点中,将当前服务器节点改为从节点; |
| rs.salveOK() |
| # 注要写数据的时候,还是要到主节点中支写; |
| db.classes.insert({class: "One", nostu: 40}) |
| show collections |
| db.classes.findOne() |
| |
| rs.stepDown() |
| rs.status() |
| db.printReplicationInfo() |
副本集的重新先举的影响条件:
先举机制:
| 触发选举的事件 |
| 新副本集初始化时; |
| 从节点联系不到主节点时; |
| 主节点"下台"时; |
| 主节点收到stepDown()命令时; |
| 某从节点有更高的优先级且已经满足了成主节点的其它所有条件; |
| 主节点无法联系到副本集的"多数方"; |
| cfg= rs.conf() |
| cfg.member[1].priority=2 |
| rs.conf() |
| rs.reconfig(cfg) |
| |
| |
| cfg = rs.confg() |
| cfg.member[2].abiterOnly=ture |
| rs.reconfgi(cfg) |
| rs.conf() |
| rs.printSlaveReplicationInfo() |
MongoDB的分片:
| sharding 分片 |
| |
| |
| |
| |
| MySQL: Gizzard, HivedDB(独立的项目,转门来对MySQL来实现分片的),MySQL Proxy + HSACLE, Hibernate Shared Pyshards |
| |
| |
| mongos: Router; |
| config server: 元数据服务器; |
| shard: 数据节点,也称mongod实例节点; 负责将数据存下来,并响应客户端的; |
| zookeeper: 通常用于分布式节点的协调; |
| |
| range |
| |
| list |
| |
| hash |
| 写离散,读要集中 |

分片式架构配置
| |
| |
| |
| |
| -------------------------> confiserver 服务器配置 |
| |
| |
| |
| dbpath=/mongodb/data |
| configsvr=true |
| |
| |
| |
| |
| -----------------------> mongofs 服务器配置 |
| |
| |
| |
| |
| help |
| sh.status() |
| |
| sh.addShard("172.16.55.129") |
| ss.addShard("172.16.55.120") |
| sh.enableShareding("testdb") |
| sh.help() |
| sh.enableSharding(dbname) |
| sh.shardCollection(fullName,key,unique) |
| sh.shardCollection("students", {"age" : 1 }) |
| sh.status() |
| use testdb; |
| for (i=1; i<=100000;i++) db.students.insert({name:"studentt"+i, age:(i%120),classes:"class"+(i%10),address:"www.ssjinyao.com, Magedu, #85 WenhuaRoad, BeiJin, China"}) |
| use testdb |
| db.students.find().count() |
| sh.status() |
| db.databases.find("partitioned":true) |
| db.runCommands("listShards") |
| use admin |
| db.runCommand("listShards") |
| db.printShardingStatus() |
| sh.isBalancerRunning() |
| sh.getBalancerState() |
| -----------------------> Shard1 服务器配置 |
| |
| |
| |
| |
| |
| |
| |
| -----------------------> Shard2 服务器配置 |
| |
| |
| |
| |
| |
| |