Mongo、Redis、Memcached對比及知識總結

存儲原理(持久化)

  • Mongo
    Mongo的數據將會保存在底層文件系統,因此存儲容量遠大於redis和memcached。一個database中所有的collections以及索引信息會分散存儲在多個數據文件中,即mongodb並沒有像SQL數據庫那樣,每個表的數據、索引分別存儲;數據分塊的單位爲extent(範圍,區域),即一個data file中有多個extents組成,extent中可以保存collection數據或者indexes數據,一個extent只能保存同一個collection數據,不同的collections數據分佈在不同的extents中,indexes數據也保存在各自的extents中;最終,一個collection有一個或者多個extents構成,最小size爲8K,最大可以爲2G,依次增大;它們分散在多個data files中。對於一個data file而言,可能包含多個collection的數據,即有多個不同collections的extents、index extents混合構成。每個extent包含多條documents(或者index entries),每個extent的大小可能不相等,但一個extent不會跨越2個data files。

clipboard.png

  • Redis
    1、Redis的數據存儲在內存中,同時可以通過兩種存儲機制,將數據持久化到磁盤。
    (1)Snapshot工作原理: 是將數據先存儲在內存,然後當數據累計達到某些設定的伐值的時候,就會觸發一次DUMP操作,將變化的數據一次性寫入數據文件(RDB文件)
    (2)AOF 工作原理: 是將數據也是先存在內存,但是固定時候會使用調用fsync來完成對本次寫操作的日誌記錄,這個日誌揭露文件其實是一個基於Redis網絡交互協議的文本文件。AOF調用fsync也不是說全部都是無阻塞的,在某些系統上可能出現fsync阻塞進程的情況,對於這種情況可以通過配置修改,但默認情況不要修改。AOF最關鍵的配置就是關於調用fsync追加日誌文件的頻率,有兩種預設頻率,always每次記錄進來都添加,everysecond 每秒添加一次。當redis重啓時,將會讀取AOF文件進行“重放”以恢復到redis關閉前的最後時刻。
    (3)兩種存儲原理比較:

     a.性能
     Snapshot方式的性能是要明顯高於AOF方式的,原因有兩點:
     採用2進制方式存儲數據,數據文件比較小,加載快速。存儲的時候是按照配置中的save策略來存儲,每次都是聚合很多數據批量存儲,寫入的效率很好,而AOF則一般都是工作在實時存儲或者準實時模式下。相對來說存儲的頻率高,效率卻偏低。
     
     b.數據安全
     AOF數據安全性高於Snapshot存儲,原因:
     Snapshot存儲是基於累計批量的思想,也就是說在允許的情況下,累計的數據越多那麼寫入效率也就越高,但數據的累計是靠時間的積累完成的,那麼如果在長時間數據不寫入RDB,但Redis又遇到了崩潰,那麼沒有寫入的數據就無法恢復了,但是AOF方式偏偏相反,根據AOF配置的存儲頻率的策略可以做到最少的數據丟失和較高的數據恢復能力。
    
  • Memcached
    1、Memcached不支持內存數據的持久化操作,所以的數據都以in-momory的形成存儲。

數據類型:

  • Mongo
    1、字符串、整型、布爾型、雙進度浮點型...具體參照:http://www.yiibai.com/mongodb...
  • Redis
    1、除了簡單的key-value數據類型,同時還提供了list、hash、set、zset等數據結構的存儲
  • Memcached
    1、Memcached使用key-value形式存儲和訪問數據

網絡IO模型

  • Mongo
    1、多線程,同步 IO 模型。
    clipboard.png
    由主線程進行 accept 連接,然後針對每一個連接創建一個線程進行處理,「thread per connection」這種模型:
    (1)不適合短連接服務,創建/刪除線程的開銷是巨大的,體現在創建線程時間和至少1MB 內存的使用。
    (2)伸縮性受到線程數的限制,200+線程數的調度對 OS 也是不小的負擔。另外隨着線程數的增加, 由於 mongo 本身業務的特性,對數據處理的併發度並不高,DB鎖和全局的原子操作造成的 context-switch 也是急劇上升,性能反而下降,頻繁的線程切換對於 cache 也不友好。
  • Redis
    1、Redis使用 單線程的IO複用模型 ,自己封裝了一個簡單的Ae_Event事件處理框架,主要實現了epoll、kqueue、kvport和select,對於單存只有IO操作來說,單線程可以將速度優勢發揮到最大,但是Redis也提供了一些簡單的計算功能,比如排序、聚合等,對於這些操作,單線程模型不能發揮多核CPU的優勢,會嚴重影響整體吞吐率,因爲在CPU的計算的過程中,整個IO調度是被阻塞的,因此 Redis不適合用於計算。
  • Memcached
    1、Memcached是 多線程、非阻塞IO複用 的網絡模型,分爲監聽主線程和worker子線程,監聽線程監聽網絡連接,接受請求後,將連接描述字pipe傳遞給worker線程進行讀寫IO,網絡層使用libevent封裝的事件庫,多線程模型可以發揮CPU多核作用,但是引入了cache coherency(緩存一致性)和鎖的問題,比如:Memcached最常用的stats命令,實際Memcached所有操作都要對這個全局變量加鎖、進行技術工作等,帶來了性能損耗。(緩存的一致性就是指緩存中的數據是否和目標存儲中的數據是一樣的,也就是說緩存中已經修改得數據是否已經保存到了物理存儲中,物理存儲中已經被修改得內容,是否與緩存的內容是一樣的。這就是一致性的概念。)

內存管理機制

  • Redis
    1、Redis的內存管理主要通過源碼中的zmalloc.h和zmalloc.c兩個文件來實現。Redis爲了方便內存的管理,在分配了一塊內存後,會將這塊內存的大小存入內存塊的頭部。如下圖所示,real_ptr是Redis調用malloc函數返回的指針,Redis將內存塊的大小size存入頭部(size所佔據的大小是已知的,爲size_t類型的長度),然後返回ret_ptr。當需要釋放內存的時候,ret_ptr別傳給內存管理程序,通過ret_ptr可以很容易計算出real_ptr的值,然後將real_ptr傳給free釋放掉。

    clipboard.png

    2、在Redis中,並不是所有的數組都一直存儲在內存中的。這是和Memcached相比最大的一個區別。當物理內存用完的時候,Redis可以將一些很久沒用到的value交換到磁盤(注:這裏用到的是Redis的Virtual Memory技術,Redis2.4版本之後已經不提倡使用了)。Redis只會緩存所有key的信息,如果Redis發現內存的使用量超過了某個閾值,將觸發swap操作。swap操作根據規則計算出哪些key對應的value需要swap到磁盤,然後再將這些key對應的value持久化到磁盤中,同時在內存中清除。這種特性使得Redis可以保存超過其機器物理內存大小的數據。當然,機器本身的內存必須要能夠保存所有的key,畢竟這部分數據是不會被swap到磁盤的。同時由於Redis將內存中的數據swap到磁盤的時候,提供服務的主線程和進行swap的子線程會共享這部分內存,所有如果需要更新swap的數據,Redis將阻塞這個操作,直到子線程完成swap之後纔可以進行修改。當從Redis中讀取數據的時候,如果讀取的key的value不在內存中,那麼Redis需要從swap文件中加載對應的數據,然後再返回給client,這裏就存在一個I/O線程池的問題。在默認情況下,Redis會出現阻塞,即完成所有的swap文件加載後纔會執行相應的操作。這種策略在client數量較小,進行批量操作的時候比較合適。但是如果Redis應用在一個大型的網站應用中,這顯示是無法滿足大併發的情況的。所以Redis允許我們設置I/O線程池的大小,對需要從swap文件中加載相應數據的讀取請求進行併發操作,減少阻塞的時間。

  • Memcached
    1、Memcached默認使用Slab Allocation機制來管理內存,它的主要思想是 按照預先規定的大小,將分配的內存分割成特定長度的塊,以存儲相應長度的key-value數據記錄,以完全解決內存碎片的問題。Slab Allocation機制只爲存儲外部數據而設計,也就是說所有的key-value數據都存儲在slab allocation系統裏面,但是Memcached的其他內存請求則是通過普通的malloc/free來申請,因爲這些請求的數量和頻率決定了它們不會對整個系統的性能造成影響。
    2、slab allocation機制的原理比較簡單,如下圖所示,它首先從操作系統申請一大塊內存,並將其分割成各種尺寸的chunk(塊),並把尺寸相同的chunk分成一組組slab class。其中,chunk就是用來存儲key-value的最小單位。每個slab class的大小,可以在Memcached啓動的時候通過制定growth factor來控制。
    clipboard.png

    3、當Memcached接收到客戶端發過來的數據時,會根據收到數據的大小選擇一個最合適的slab class,然後通過查詢Memcached保存着的該slab class內空閒chunk的列表,就可以找到一個用於存儲數據的chunk。當一條數據記錄過期或者丟棄時,該記錄所佔用的chunk就可以被回收,重新添加到空閒列表中。
    4、從以上過程中可以看到,Memcached的內存管理效率高,並且不會造成內存碎片,但是它最大的不足是會造成空間浪費。因爲每個chunk都分配了特定長度的內存空間,所以變長數據無法利用這些空間。如下圖所示,將100字節的數據緩存到128字節的chunk中,剩餘的28個字節就被浪費掉了。
    clipboard.png

集羣管理

  • Mongo
    1、Replica Set:中文翻譯叫做副本集,就是集羣當中包含了多份數據,保證主節點掛掉了,備節點能繼續提供數據服務,提供的前提就是數據需要和主節點一致。如下圖:
    clipboard.png
    2、Mongodb(M)表示主節點,Mongodb(S)表示備節點,Mongodb(A)表示仲裁節點。主備節點存儲數據,仲裁節點不存儲數據。客戶端同時連接主節點與備節點,不連接仲裁節點。
    3、默認設置下,主節點提供所有增刪查改服務,備節點不提供任何服務。但是可以通過設置使備節點提供查詢服務,這樣就可以減少主節點的壓力,當客戶端進行數據查詢時,請求自動轉到備節點上。這個設置叫做Read Preference Modes,同時Java客戶端提供了簡單的配置方式,可以不必直接對數據庫進行操作。
    4、仲裁節點是一種特殊的節點,它本身並不存儲數據,主要的作用是決定哪一個備節點在主節點掛掉之後提升爲主節點,所以客戶端不需要連接此節點。這裏雖然只有一個備節點,但是仍然需要一個仲裁節點來提升備節點級別(由備用節點提升爲主節點)。仲裁節點是必須的。詳見:http://blog.csdn.net/luonanqi...
  • Redis
    1、相比Memcached只能採用客戶端實現分佈式存儲,Redis更偏向在服務端構建分佈式存儲。新版本的Redis已經支持分佈式存儲功能。Redis Cluster是一個實現了分佈式並且允許單點故障的Redis高級版本,它沒有中心節點,具有線性可伸縮的功能。Redis Cluster的分佈式存儲架構,節點與節點之間通過二進制協議進行通訊,節點與客戶端之間通過ascii協議通訊。在數據的放置策略上,Redis Cluster將整個key的數值域劃分成16384(2^14)個哈希槽,每個節點上可以存儲一個或多個哈希槽,也就是說Redis Cluster支持的最大節點數是16384。
    2、爲了保證單點故障下得數據可用性,Redis Cluster引入了Master節點和Slave節點。在Redis Cluster中,每個Master節點都會對應2個用於冗餘的Slave節點。這樣在整個集羣中,任意2個節點的宕機都不會導致數據的不可用。當Master節點下線後,集羣會自動選擇一個Slave節點成爲新的Master節點。
  • Memcached
    1、Memcached是全內存的數據緩衝系統,Redis雖然支持數據的持久化,但是全內存纔是其高性能的本質。作爲基於內存的存儲系統來說,機器物理內存的大小就是系統能夠容納的最大數據量。如果數據超過了單臺機器的物理內存大小,那麼就需要構建集羣來擴展存儲能力。
    2、Memcached本身並不支持分佈式,因此只能在客戶端通過像一致性哈希這樣的分佈式算法來實現Memcached的分佈式存儲。

應用場景

  • Memcached及Redis
    1、相對memcached來說,需要保證數據不丟失的話,選擇Redis。
    2、當然,大部分情況來說,選擇Redis是一個更好的選擇,因爲它更強大、更受歡迎,並且比Memcached有更多的支持者。Memcached只是Redis功能中的一小部分。所以對於新項目來說,選擇Redis。
  • Mongo
    1、Mongo的使用和上面兩個數據庫是不衝突的,這篇文字只是做一個知識的總結。
    2、日誌、消息記錄;不需要事務,不需複雜join連接表;需要大容量存儲;高吞吐量;數據不丟失;高可用;使用Mongo。

參考:

http://blog.csdn.net/sun49192...
https://www.zhihu.com/questio...
https://yq.aliyun.com/article...

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章