MongoDB之路

介紹

MongoDB屬於NoSql的一種,且是屬於NoSql中的基於分佈式文件存儲的文檔型數據庫。由C++語言編寫,旨在爲WEB應用提供可擴展的高性能數據存儲解決方案。html

 # MongoDB是一個介於關係數據庫和非關係數據庫之間的產品,是非關係數據庫當中功能最豐富,最像關係數據庫的。它支持的數據結構很是鬆散,是相似json的bson(是一種類json的一種二進制形式的存儲格式,簡稱Binary JSON)格式,所以能夠存儲比較複雜的數據類型。Mongo最大的特色是他支持的查詢語言很是強大,其語法有點相似於面向對象的查詢語言,幾乎能夠實現相似關係數據庫單表查詢的絕大部分功能,並且還支持對數據創建索引。

特色

MongoDB特色是高性能、易部署、易使用,存儲數據很是方便,最大的特色在於它支持的查詢語言很是強大,其語法有點相似於面向對象的查詢語言,幾乎能夠實現相似關係型數據庫單表
查詢的絕大部分功能,並且還支持對數據創建索引。MongoDB的主要特色總結以下:python

  • 1)提供了一個面向集合的文檔存儲,易存儲對象類型的數據,操做起來比較簡單和容易的非關係型數據庫
  • 2)使用update()命令能夠實現替換完成的文檔(數據)或者一些指定的數據字段。
  • 3)支持動態查詢。
  • 4)支持徹底索引,包含內部對象,能夠在MongoDB記錄中設置任何屬性的索引來實現更快的排序。
  • 5)支持複製和故障恢復。
  • 6)使用高效的二進制數據存儲,包括大型對象(如視頻等)。
  • 7)GridFS是MongoDB中的一個內置功能,能夠用於存放大量小文件。
  • 8)自動處理碎片,以支持雲計算層次的擴展性;若是負載的增長(須要更多的存儲空間和更強的處理能力),它能夠分佈在計算機網絡中的其它節點上,這就是所謂的分片。
  • 9)支持RUBY,PYTHON,JAVA,C++,PHP,C``#等多種語言。
  • 10)文件存儲格式爲BSON(一種JSON的擴展),MongoDB支持豐富的查詢表達式,查詢指令使用JSON形式的標記,可輕易查詢文檔中內嵌的對象和數組。
  • 11)MongoDB容許在服務端執行腳本,能夠用JavaScript編寫某個函數,直接在服務端執行,也能夠吧函數的定義存儲在服務端,下次直接調用便可。
  • 12)可經過網絡訪問,能夠經過本地u或者網絡建立數據鏡像,這使得MongoDB含有更強的擴展性。

缺點

  • 1)在集羣分片中的數據分佈不均勻
  • 2)單機可靠性比較差
  • 3)大數據量持續插入,寫入性能有較大波動
  • 4)磁盤空間佔用比較大。空間佔用大的緣由以下:
  1. 空間的預分配:爲避免造成過多的硬盤碎片,mongodb 每次空間不足時都會申請生成一大塊的硬盤空 間,並且申請的量從 64M、128M、256M 那樣的指數遞增,直到2G爲單個文件的最大致積。隨着數據量 的增長,你能夠在其數據目錄裏看到這些整塊生成容量不斷遞增的文件。
  2. 字段名所佔用的空間:爲了保持每一個記錄內的結構信息用於查詢,mongodb 須要把每一個字段的 key-value 都以 BSON 的形式存儲,若是 value 域相對於 key 域並不大,好比存放數值型的數據,則數據的 overhead 是最大的。一種減小空間佔用的方法是把字段名儘可能取短一些,這樣佔用 空間就小了,但這就要求在易讀 性與空間佔用上做爲權衡了。
  3. 刪除記錄不釋放空間:這很容易理解,爲避免記錄刪除後的數據的大規模挪動,原記錄空間不刪除,只 標記「已刪除」便可,之後還能夠重複利用。
  4. 能夠按期運行 db.repairDatabase()來整理記錄,但這個過程會比較緩慢

適用場合

  • 網站數據:MongoDB 很是適合實時的插入,更新與查詢,並具有網站實時數據存儲所需的複製及高度伸縮性mysql

  • 緩存:因爲性能很高,MongoDB 也適合做爲信息基礎設施的緩存層。在系統重啓以後,由 MongoDB 搭建的持久 化緩存層能夠避免下層的數據源過載linux

  • 大尺寸,低價值的數據:使用傳統的關係型數據庫存儲一些數據時可能會比較昂貴,在此以前,不少時候程序員每每會選擇傳統的文件進行存儲程序員

  • 高伸縮性的場景:MongoDB 很是適合由數十或數百臺服務器組成的數據庫。MongoDB的路線圖中已經包含對 MapReduce 引擎的內置支持web

  • 用於對象及 JSON 數據的存儲:MongoDB 的 BSON 數據格式很是適合文檔化格式的存儲及查詢redis

結構

  • 文檔(document)相似於Python字典,庫中最小單位,存儲和操做都是它算法

  • 集合(collection)就是一組文檔,相似數組sql

  • 多個文檔組成集合,多個集合組成數據庫mongodb

數據類型

key: 必須爲字符串類型

value:能夠包含以下類型

  • 基本類型,例如,string,int,float,timestamp,binary 等類型

  • 一個document

  • 數組類型

安裝

MongoDB下載地址 <!--PS:包含windows、Linux、macos,在MongoDB2.2版本後再也不支持windows XP -->

windows版本:下載安裝包,一直下一步便可。

Linux版本:下載 ---->解壓縮

wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-4.0.10.tgz
tar xzvf mongodb-linux-x86_64-4.0.10.tgz

體系結構

 

  • 數據庫服務(mongod)

  • 分片集羣部署中,數據和查詢的路由服務(mongos)

  • shell客戶端(mongo)

  • 導入導出工具(mongoimport / mongoexport)

  • 備份恢復工具(mongodump / mongorestore)

  • 拉取並重放oplog的工具(mongooplog)

  • 監控工具(mongostat、mongotop、mongosniff)

  • GridFS的命令行操做工具(mongofiles)

  • 性能測試工具(mongoperf,暫時只能測I/O)

  • 查看bson文件的工具(bsondump)

 在一臺服務器上,能夠啓動多個mongod服務。但在實際生產部署中,一般仍是建議一臺服務器部署一個mongod實例,這樣不只減小資源競爭,並且服務器故障也不會同時影響到多個服務。

 詳細信息

啓用服務

安裝目錄/bin 下,有一個 mongod.exe 的應用程序

PS:在windows下需配置環境變量(在安裝目錄下找到bin目錄,將路徑添加至環境變量中)

在4.0版本在安裝完成時已生成Windows服務,只需 net start MongoDB ,而後啓個客戶端輸入 mongo

MongoDB操做

 基本指令

show dbs  //等同於 show databases
use  庫名  //進入數據庫 PS:沒有庫也能夠進入,當插入第一條數據會自動建立庫
db  //表明當前所在數據庫
show collections   //等同於 show  tables  查看全部集合(表)

建立

建立或插入操做將新文檔添加到集合中。若是集合當前不存在,則插入操做將建立集合。

db.collection.insert({ "key" : "value" })

在MongoDB中,插入操做以單個集合爲目標。MongoDB中的全部寫入操做都是單個文檔級別的 原子操做。

 

查詢

查詢文檔集合

db.collection.find()  能夠指定過濾條件

$eq 等於的意思 =

更新

db.collection.update(<query>, <update>, upsert, multi, writeConcern)  #能夠指定過濾條件
  • <query> : update的查詢條件,相似sql update查詢內where後面的。
  • <update> : update的對象和一些更新的操做符(如$,$inc...)等,也能夠理解爲sql update查詢內set後面的
  • upsert:可選,若是不存在update的記錄,是否插入objNew, true爲插入,默認是false,不插入。
  • multi : 可選,默認是false,只更新找到的第一條記錄,若是這個參數爲true,就把按條件查出來多條記錄所有更新。
  • writeConcern :可選,拋出異常的級別。

 

在MongoDB中,更新操做以單個集合爲目標。MongoDB中的全部寫入操做都是單個文檔級別的原子操做。

 

#只更新第一條記錄   年齡小於20的youth設置爲yes
db.collection.update( { "age" : { $lt : 20 } } , { $set : { "youth" : "yes"} } );

#所有更新 年齡小於20的 youth設置爲yes
db.collection.update( { "age":{ $lt : 20 } },{ $set : { "youth" : "yes"} },false,true );

#只添加一條記錄 給年齡大於30的 一個 添加"youth" : "no"
db.collection.update( { "age":{ $gt : 20 } },{ $set : { "youth" : "no"} },true,false );

#所有添加  給年齡大於30的 所有 添加"youth" : "no"
db.collection.update( { "age":{ $gt : 30 } },{ $set : { "youth" : "no"} },true,true );

刪除

MongoDB與MySQL對比

 

 詳細>>>

python操做Mongo

前戲

from pymongo import MongoClient

def getconn():
    try:
        conn = MongoClient('127.0.0.1',27017)
        return conn
    except:
        print('數據庫鏈接失敗')

conn = getconn()   
#查看數據庫
dblist = conn.list_database_names()
print(dblist)
#查看集合
collection_list = conn['user'].list_collection_names()
print(collection_list)
#集合數據
data = [
    {
        'author': '小紅', 'title': 'MySQL底層原理',
        'content': '信息存儲在硬盤裏,硬盤是由不少的盤片組成,經過盤片表面的磁性物質來存儲數據。'
                   '把盤片放在顯微鏡下放大,能夠看到盤片表面是凹凸不平的,凸起的地方被磁化,表明數字 1,凹的地方沒有被磁化,表明數字 0,所以硬盤能夠經過二進制的形式來存儲表示文字、圖片等的信息。'
                   '硬盤有不少種,可是都是由盤片、磁頭、盤片主軸、控制電機、磁頭控制器、數據轉換器、接口、緩存等幾個部分組成',
        'tags': ['MySQL', 'PostgreSQL'], 'comments': [
        {'name': 'WangQQ', 'detail': '寫的什麼垃圾。。。', 'date': '2019-07-27 13:38:49'},
        {'name': 'RengPL', 'detail': '寫的看不懂--!', 'date': '2019-07-27 13:48:49'},
        {'name': 'HongLP', 'detail': '每天摸魚', 'date': '2019-07-27 13:58:49'}],
        'readcount': 999
    },
    {'author': 'NiXin', 'title': '1+1等於幾',
     'content': '有的人說1+1=2,由於這是老師從小告訴咱們的;而有的人說1+1=11,這是兩個1的組合;可是有些人就認爲1+1=1,他們以爲1個團隊加上另外一個團隊,會組成了一個更強大的團隊!',
     'tags': '十萬個爲何', 'comments': [
        {'name': 'WangQQ', 'detail': '標題黨', 'date': '2019-07-27 13:38:49'},
        {'name': 'RengPL', 'detail': '好像頗有道理', 'date': '2019-07-27 13:48:49'},
        {'name': 'HongLP', 'detail': '你有個bug', 'date': '2019-07-27 13:58:49'}],
     'readcount': 998
     },
    {'author': '洪哥', 'title': '論摸魚的重要性', 'content': '摸魚是一種方法,是一種探索,更是一種樂趣!!!',
     'tags': '座右銘', 'comments': [
        {'name': 'WangQQ', 'detail': '點贊!', 'date': '2019-07-27 13:38:49'},
        {'name': 'RengPL', 'detail': '。。。', 'date': '2019-07-27 13:48:49'},
        {'name': '小紅', 'detail': '學習中。。。', 'date': '2019-07-27 13:58:49'}],
     'readcount': 1998,
     'isTop': True
     },
    {'author': 'WangQQ', 'title': 'ElasticSearch', 'content': 'ElasticSearch是一個基於Lucene的搜索服務器。它提供了一個分佈式多用戶能力的全文搜索引擎,基於RESTful web接口。'
                                                              'Elasticsearch是用Java語言開發的,並做爲Apache許可條款下的開放源碼發佈,是一種流行的企業級搜索引擎。ElasticSearch用於雲計算中,可以達到實時搜索,穩定,可靠,快速,安裝使用方便。'
                                                              '官方客戶端在Java、.NET(C#)、PHP、Python、Apache Groovy、Ruby和許多其餘語言中都是可用的。根據DB-Engines的排名顯示,Elasticsearch是最受歡迎的企業搜索引擎,其次是Apache Solr,也是基於Lucene。',
     'tags': 'NoSQL', 'comments': [
        {'name': 'HongLP', 'detail': '寫的不錯,和百度百科同樣麼', 'date': '2019-07-27 13:38:49'},
        {'name': 'RengPL', 'detail': '666', 'date': '2019-07-27 13:48:49'},
        {'name': '小紅', 'detail': '詳細說說ES源碼唄?', 'date': '2019-07-27 13:58:49'}],
     'readcount': 1020,
     },
    {'author': 'RengPL', 'title': 'redis', 'content': 'redis是一個key-value存儲系統。和Memcached相似,它支持存儲的value類型相對更多,包括string(字符串)、list(鏈表)、set(集合)、zset(sorted set --有序集合)和hash(哈希類型)。'
                                                      '這些數據類型都支持push/pop、add/remove及取交集並集和差集及更豐富的操做,並且這些操做都是原子性的。在此基礎上,redis支持各類不一樣方式的排序。與memcached同樣,爲了保證效率,數據都是緩存在內存中。'
                                                      '區別的是redis會週期性的把更新的數據寫入磁盤或者把修改操做寫入追加的記錄文件,而且在此基礎上實現了master-slave(主從)同步。',
     'tags': '座右銘', 'comments': [
        {'name': 'WangQQ', 'detail': 'redis爲何叫redis', 'date': '2019-07-27 13:38:49'},
        {'name': 'nixin', 'detail': '點贊!!', 'date': '2019-07-27 13:48:49'},
        {'name': '小紅', 'detail': '有點6', 'date': '2019-07-27 13:58:49'}],
     'readcount': 1203,
     },
    {
        'author': '小紅', 'title': '如何快速寫代碼',
        'content': 'Pycharm中的宏功能能夠幫助咱們快速的插入經常使用的代碼,教程百度一堆,固然複製粘貼是必不可少的。',
        'tags': ['MySQL', 'PostgreSQL'], 'comments': [
        {'name': 'WangQQ', 'detail': '又水了一篇', 'date': '2019-07-28 13:38:49'},
        {'name': 'RengPL', 'detail': '一本正經偷懶', 'date': '2019-07-28 13:48:49'},
        {'name': 'HongLP', 'detail': '很對', 'date': '2019-07-28 13:58:49'}],
        'readcount': 78
    },
    {
        'author': 'NiXin', 'title': 'MongoDB高級聚合查詢',
        'content': '聚合查詢----> https://www.cnblogs.com/zhoujie/p/mongo1.html',
        'tags': 'MongoDB', 'comments': [
        {'name': 'WangQQ', 'detail': '平常點踩', 'date': '2019-07-28 13:38:49'},
        {'name': 'RengPL', 'detail': '。。。', 'date': '2019-07-28 13:48:49'},
        {'name': 'HongLP', 'detail': '很對,很對', 'date': '2019-07-28 13:58:49'}],
        'readcount': 178
    },
    {'author': '洪哥', 'title': '明天吃什麼', 'content': '這篇文章的意義是頗有意義的,表達了老夫對明日的憧憬。。(巴拉巴拉)。。。。好了又水一篇。',
    'tags': '座右銘', 'comments': [
       {'name': 'WangQQ', 'detail': '西蘭花個人最愛', 'date': '2019-07-29 13:38:49'},
       {'name': 'RengPL', 'detail': '隨便吃點', 'date': '2019-07-29 13:48:49'},
       {'name': '小紅', 'detail': '剁椒魚頭,你值得擁有', 'date': '2019-07-29 13:58:49'}],
    'readcount': 250,
    },
    {'author': 'WangQQ', 'title': '計算機英語入門篇', 'content': '《計算機入門英語(學與練)》是1999年海天出版社出版的圖書,做者是王小紅。',
     'tags': 'NoSQL', 'comments': [
        {'name': 'HongLP', 'detail': '寫的不錯,和百度百科同樣麼', 'date': '2019-07-27 13:38:49'},
        {'name': 'RengPL', 'detail': '英語十八級路過', 'date': '2019-07-27 13:48:49'},
        {'name': '小紅', 'detail': '???', 'date': '2019-07-27 13:58:49'}],
     'readcount': 768,
     },
    {'author': 'RengPL', 'title': 'python數據分析', 'content': '《Python數據分析(影印版)》由麥金尼撰寫,他是pandas庫的主要做者。《Python數據分析(影印版)》也是一本具備實踐性的指南,指導那些使用Python進行科學計算的數據密集型應用。',
     'tags': 'python', 'comments': [
        {'name': 'WangQQ', 'detail': '分析分析', 'date': '2019-07-30 13:38:49'},
        {'name': 'nixin', 'detail': '贊👍', 'date': '2019-07-30 13:48:49'},
        {'name': '小紅', 'detail': '頭給你打爛。。', 'date': '2019-07-30 13:58:49'}],
     'readcount': 975,
     },
]
集合數據

新增

data = {'city':'shanghai'}
db.insert_one(data)  #新增一條 insert_one

data = [{'city':'shanghai'},{'city':'beijin'},{'city':'guangzhou'}]
db.insert_many(data) #新增多條 insert_many

查詢

q1=db.find_one({"name":'xiaohong'})
print(q1)  # 查詢一條 find_one

alldata = db.find()
for i in alldata : print(i)  #查詢全部
    
#一、查詢指定字段的數據
#咱們可使用 find() 方法來查詢指定字段的數據,將要返回的字段對應值設置爲 1。
for i in db.find({ },{"_id":0,"name":1,"hobby":1}) : print(i)
    
#二、查詢全部文章的標題和內容
conn.user.article.find({},{"_id":0,"title":1,"content":1})

#三、查詢做者爲‘小紅’的文章
conn.user.article.find_one({"author":{"$eq":"小紅"}})

#四、查詢除了‘小紅’之外的全部文章
conn.user.article.find({"author":{"$ne":"小紅"}})

#五、查詢閱讀數大於1000 而且 小於1200的
conn.user.article.find({"readcount":{"$gt":1000,"$lt":1200}})

#六、查詢做者爲‘小紅’或者‘洪哥’的文章  或操做
conn.user.article.find({"$or":[{"author":"小紅"},{"author":"洪哥"}]})

#七、查詢文章標籤包含‘NoSQL’或者‘MySQL’的 文章
conn.user.article.find({"tags":{"$in":["MySQL","NoSQL"]}})

#八、查詢文章內容裏包含數字1的文章
conn.user.article.find({"content":{"$regex":"1"}})    #有疑問 正則寫法問題(/1/)

#九、查詢標籤數爲2個的文章
conn.user.article.find({"tags":{"$size":2}})

##內嵌文檔查詢
#一、查詢‘小紅’評論過的文章
conn.user.article.find({"comments.name":"小紅"})

#假設每頁有3篇數據,按閱讀量倒序,取第二頁的數據
conn.user.article.find({}).skip(3).limit(3).sort("readcount",-1)

更新

conn.user.user.update_one({"查詢條件"},{"修改器"}) #update_many 修改所有

#一、將名字爲‘xiaohong’的年齡改成26
conn.user.user.update_one({"name":"xiaohong"},{"$set":{"age":26}})

#二、給全部的用戶添加‘city’字段,值爲‘shanghai’
conn.user.user.update_many({},{"$set":{"city":"shanghai"}})
#刪除字段 就改成"$unset"

#三、給全部用戶年齡加 1
conn.user.user.update_many({},{"$inc":{"age":1}})  #前提是age類型爲int型

刪除

#刪除單條  
conn.usser.user.delete_one()
#刪除多條
delete_many()
#刪除集合
conn.usser.user.drop()  #刪除了user庫中的user集合

聚合查詢

MongoDB中聚合(aggregate)主要用於處理數據(諸如統計平均值,求和等),並返回計算後的數據結果。有點相似sql語句中的 count(*)。

表達式 描述 實例
$sum 計算總和 db.article.aggregate([{$group:{_id:"$author",num_tutorial:{$sum:"$readcount"}}}])
$avg 計算平均值 db.article.aggregate([{$group:{_id:"$author",num_tutorial:{$avg:"$readcount"}}}])
$min 獲取集合中全部文檔對應值得最小值 db.article.aggregate([{$group:{_id:"$author",num_tutorial:{$min:"$readcount"}}}])
$max 獲取集合中全部文檔對應值得最大值 db.article.aggregate([{$group:{_id:"$author",num_tutorial:{$max:"$readcount"}}}])
$push 在結果文檔中插入一個值到數組中 db.article.aggregate([{$group : {_id : "$author", tags : {$push: "$tags"}}}])
$addToSet 在結果文檔中插入值到一個數組中,但不建立副本 db.article.aggregate([{$group : {_id : "$author", tags : {$addToSet: "$tags"}}}])
$first 根據資源文檔的排序獲取第一個文檔數據 db.article.aggregate([{$group : {_id : "$author", tags : {$first: "$tags"}}}])
$last 根據資源文檔的排序獲取最後一個文檔數據 db.article.aggregate([{$group : {_id : "$author", tags : {$last: "$tags"}}}])

 

高級聚合查詢

管道在Unix和Linux中通常用於將當前命令的輸出結果做爲下一個命令的參數。

MongoDB的聚合管道將MongoDB文檔在一個管道處理完畢後將結果傳遞給下一個管道處理。管道操做是能夠重複的。

表達式:處理輸入文檔並輸出。表達式是無狀態的,只能用於計算當前聚合管道的文檔,不能處理其它的文檔。

聚合框架中經常使用的幾個操做:

 

#$project:修改輸入文檔的結構。能夠用來重命名、增長或刪除域,也能夠用於建立計算結果以及嵌套文檔。
db.article.aggregate({$project:{_id:0,title:1,author:1}})


#$match:用於過濾數據,只輸出符合條件的文檔。$match使用MongoDB的標準查詢操做。
db.article.aggregate([{$match:{readcount:{$gt:500,$lt:1000}}},{$group:{_id:"$author",count:{$sum:1}}}])


#$limit:用來限制MongoDB聚合管道返回的文檔數。
db.article.aggregate([{$match:{readcount:{$gt:500,$lt:1000}}},{$limit:2}])


#$skip:在聚合管道中跳過指定數量的文檔,並返回餘下的文檔。
db.article.aggregate([{$match:{readcount:{$gt:500,$lt:1000}}},{$skip:2}])


#$unwind:將文檔中的某一個數組類型字段拆分紅多條,每條包含數組中的一個值。
db.article.aggregate([{$unwind:"$tags"},{$project:{_id:0,title:1,author:1}}])


#$sort:將輸入文檔排序後輸出。
db.article.aggregate([{$sort:{readcount:-1}},{$project:{_id:0,author:1,title:1,readcount:1}}])

#$geoNear:輸出接近某一地理位置的有序文檔。
沒太理解,沒試驗過

 

MapReduce

Map-Reduce是一種計算模型,簡單的說就是將大批量的工做(數據)分解(MAP)執行,而後再將結果合併成最終結果(REDUCE)。

MongoDB提供的Map-Reduce很是靈活,對於大規模數據分析也至關實用。

>db.collection.mapReduce(
   function() {emit(key,value);},  //map 函數
   function(key,values) {return reduceFunction},   //reduce 函數
   {
      out: collection,
      query: document,
      sort: document,
      limit: number
   }
)
  • map :映射函數 (生成鍵值對序列,做爲 reduce 函數參數)。

  • reduce 統計函數,reduce函數的任務就是將key-values變成key-value,也就是把values數組變成一個單一的值value。。

  • out 統計結果存放集合 (不指定則使用臨時集合,在客戶端斷開後自動刪除)。

  • query 一個篩選條件,只有知足條件的文檔纔會調用map函數。(query。limit,sort能夠隨意組合)

  • sort 和limit結合的sort排序參數(也是在發往map函數前給文檔排序),能夠優化分組機制

  • limit 發往map函數的文檔數量的上限(要是沒有limit,單獨使用sort的用處不大)

 

集羣部署

主從複製

是一個簡單的數據庫同步備份的集羣技術,這種方式很靈活,可用於備份,故障恢復,讀擴展等。最基本的設置方式就是創建一個主節點和一個或多個從節點,每一個從節點要知道主節點的地址。採用雙機備份後主節點掛掉了後從節點能夠接替主機繼續服務。因此這種模式比單節點的高可用性要好不少。

已經不推薦使用!主從模式,須要手工指定集羣中的 Master。若是 Master 發生故障,通常都是人工介入,指定新的Master。 這個過程對於應用通常不是透明的,每每伴隨着應用從新修改配置文件,重啓應用服務器等。

副本集(主從的擴展)

副本集是將數據同步在多個服務器的過程。

  • 保障數據的安全性

  • 數據高可用性 (24*7)

  • 災難恢復

  • 無需停機維護(如備份,重建索引,壓縮)

  • 分佈式讀取數據(讀寫分離)

MongoDB複製原理

mongodb的複製至少須要兩個節點。其中一個是主節點,負責處理客戶端請求,其他的都是從節點,負責複製主節點上的數據。

mongodb各個節點常見的搭配方式爲:一主一從、一主多從。

主節點記錄在其上的全部操做oplog,從節點按期輪詢主節點獲取這些操做,而後對本身的數據副本執行這些操做,從而保證從節點的數據與主節點一致。

客戶端從主節點讀取數據,在客戶端寫入數據到主節點時, 主節點與從節點進行數據交互保障數據的一致性。

 副本集集羣Master故障的時候,副本集能夠自動投票,選舉出新的Master,並引導其他的Slave服務器鏈接新的Master,而這個過程對於應用是透明的。能夠說MongoDB的副本集是自帶故障轉移功能的主從複製。

 

 

oplog是MongoDB複製的關鍵。oplog是一個固定集合,位於每一個複製節點的local數據庫裏,記錄了全部對數據的變動。每次客戶端向主節點寫入數據,就會自動向主節點的oplog裏添加一個條目,其中包含了足夠的信息來再現數據。一旦寫操做被複制到某個從節點上,從節點的oplog也會保存一條關於寫入的記錄。每一個oplog條目都由一個BSON時間戳進行標識,全部從節點都使用這個時間戳來追蹤它們最後應用的條目。

 

#複製過程
當Primary節點完成數據操做後,Secondary會作出一系列的動做保證數據的同步:
1)檢查本身`local`庫的 oplog.rs集合找出最近的時間戳。
2)檢查Primary節點`local`庫 oplog.rs集合,找出大於此時間戳的記錄。
3)將找到的記錄插入到本身的 oplog.rs集合中,並執行這些操做。

注意:在副本集的環境中,要是全部的Secondary都宕機了,只剩下Primary。最後Primary會變成Secondary,不能提供服務。

集羣中的各節點還會經過傳遞心跳信息來檢測各自的健康情況。當主節點故障時,多個從節點會觸發一次 新的選舉操做,並選舉其中的一個成爲新的主節點(一般誰的優先級更高,誰就是新的主節點),心跳信息默認每 2 秒傳遞一次。

#選舉機制
Mongodb副本集選舉採用的是Bully算法,這是一種協調者(主節點)競選算法,主要思想是集羣的每一個成員均可以聲明它是主節點並通知其餘節點。
別的節點能夠選擇接受這個聲稱或是拒絕並進入主節點競爭,被其餘全部節點接受的節點才能成爲主節點。
節點按照一些屬性來判斷誰應該勝出,這個屬性能夠是一個靜態 ID,也能夠是更新的度量像最近一次事務ID(最新的節點會勝出)
副本集的選舉過程大體以下:
1)獲得每一個服務器節點的最後操做時間戳。每一個 mongodb 都有 oplog 機制會記錄本機的操做,方便和主服 務器進行對比數據是否同步還能夠用於錯誤恢復。
2)若是集羣中大部分服務器 down 機了,保留活着的節點都爲 secondary 狀態並中止,不選舉了。
3)若是集羣中選舉出來的主節點或者全部從節點最後一次同步時間看起來很舊了,中止選舉等待人來操做。
4)若是上面都沒有問題就選擇最後操做時間戳最新(保證數據是最新的)的服務器節點做爲主節點。
 
副本集選舉的特色:
選舉還有個前提條件,參與選舉的節點數量必須大於副本集總節點數量的一半(建議副本集成員爲奇數。最多12個副本節點,最多7個節點參與選舉)
若是已經小於一半了全部節點保持只讀狀態。集合中的成員必定要有大部分紅員(即超過一半數量)是保持正常在線狀態,3個成員的副本集,須要至少2個從屬節點是正常狀態。
若是一個從屬節點掛掉,那麼當主節點down掉 產生故障切換時,因爲副本集中只有一個節點是正常的,少於一半,則選舉失敗。
4個成員的副本集,則須要3個成員是正常狀態(先關閉一個從屬節點,而後再關閉主節點,產生故障切換,此時副本集中只有2個節點正常,則沒法成功選舉出新主節點)。

同步延遲問題

數據同步時「從節點」將「主節點」上的寫操做同步到本身這邊再進行執行。在MongoDB中,全部寫操做都會產oplog,oplog 是每修改一條數據都會生成一條,若是你採用一個批量 update 命令更新了 N 多條數據, 那麼抱歉,oplog 會有不少條,而不是一條。因此同步延遲就是寫操做在主節點上執行完後,從節點尚未把 oplog 拿過來再執行一次。而這個寫操做的量越大,主節點與從節點的差異也就越大,同步延遲也就越大了。

若是主從延遲過大,主節點上會有不少數據更改沒有同步到從節點上。這時候若是主節點故障,就有 兩種狀況:
1)主節點故障而且沒法恢復,若是應用上又沒法忍受這部分數據的丟失,咱們就得想各類辦法將這部 數據更改找回來,再寫入到從節點中去。能夠想象,即便是有可能,那這也絕對是一件很是噁心的活。
2)主節點可以恢復,可是須要花的時間比較長,這種狀況若是應用能忍受,咱們能夠直接讓從節點提 供服務,只是對用戶來講,有一段時間的數據丟失了,而若是應用不能接受數據的不一致,那麼就只能下線整個業務,等主節點恢復後再提供服務了。

分片集羣

 

分片 (sharding)是指將數據庫拆分,將其分散在不一樣的機器上的過程。將數據分散到不一樣的機器上,不須要功能強大的服務器就能夠存儲更多的數據和處理更大的負載。

爲什麼須要水平分片 1)減小單機請求數,將單機負載,提升總負載 2)減小單機的存儲空間,提升總存空間

主從與副本集與分片的區別

 

事務

  • MongoDB事務須要4.0+版本

  • 須要搭建好mongodb副本集,單個server不支持事務

#開始事務
session.start_transaction()
try:
    hello_collection.insert({"world":1})
    world_collection.insert({"hello":1})
except:
    # 操做異常,中斷事務
    session.abort_transaction()
else:
    session.commit_transaction()
finally:
    session.end_session()

持久化原理

mongodb與mysql不一樣,mysql每一次操做都會直接寫入硬盤,mongo則是寫入內存,而後持久化到硬盤中。mongodb在啓動時,會初始化一個線程不斷循環,用於在必定時間週期內來從defer隊列中獲取要持久化的數據並寫入磁盤的journal (日誌),和mongofile(數據)中,週期爲90毫秒。

相關文章
相關標籤/搜索