一.介紹
1.基於libevent的事件處理
libevent是一套跨平臺的事件處理接口的封裝,可以兼容包括這些操做系統:Windows/Linux/BSD/Solaris 等操做系統的的事件處理。
包裝的接口包括:poll、select(Windows)、epoll(Linux)、kqueue(BSD)、/dev/pool(Solaris)
Memcached 使用libevent來進行網絡併發鏈接的處理,可以保持在很大併發狀況下,仍舊可以保持快速的響應能力。
libevent: http://www.monkey.org/~provos/libevent/html
2.內置內存存儲方式
爲了提升性能,memcached中保存的數據都存儲在memcached內置的內存存儲空間中。因爲數據僅存在於內存中,所以重啓memcached、重啓操做系統會致使所有數據消失。另外,內容容量達到指定值以後,就基於LRU(Least Recently Used)算法自動刪除不使用的緩存。java
數據存儲方式:Slab Allocation
結構圖以下:
Slab Allocator的基本原理是按照預先規定的大小,將分配的內存分割成特定長度的塊(chunk),並把尺寸相同的塊分紅組,以徹底解決內存碎片問題。但因爲分配的是特定長度的內存,所以沒法有效利用分配的內存。好比將100字節的數據緩存到128字節的chunk中,剩餘的28字節就浪費了。
Page:分配給Slab的內存空間,默認是1MB。分配給Slab以後根據slab的大小切分紅chunk。
Chunk:用於緩存記錄的內存空間。
Slab Class:特定大小的chunk的組。
memcached根據收到的數據的大小,選擇最適合數據大小的slab。
memcached中保存着slab內空閒chunk的列表,根據該列表選擇chunk,而後將數據緩存於其中。linux
數據過時方式:Lazy Expiration + LRU
Lazy Expiration
memcached內部不會監視記錄是否過時,而是在get時查看記錄的時間戳,檢查記錄是否過
期。這種技術被稱爲lazy(惰性)expiration。所以,memcached不會在過時監視上耗費CPU時間。
LRU
memcached會優先使用已超時的記錄的空間,但即便如此,也會發生追加新記錄時空間不
足的狀況,此時就要使用名爲 Least Recently Used(LRU)機制來分配空間。當memcached的內存空間不足時(沒法從slab class 獲取到新的空間時),就從最近未被使用的記錄中搜索,並將其空間分配給新的記錄。redis
http://www.ttlsa.com/memcache/memcached-description/算法
二.處理流程mongodb
1. memcached採用事件驅動+狀態驅動的方式來進行整個業務的處理,針對每個tcp/udp鏈接,都有對應的狀態,狀態可能的取值爲:數據庫
/** * Possible states of a connection. */ enum conn_states { conn_listening, /**< the socket which listens for connections */ conn_new_cmd, /**< Prepare connection for next command */ conn_waiting, /**< waiting for a readable socket */ conn_read, /**< reading in a command line */ conn_parse_cmd, /**< try to parse a command from the input buffer */ conn_write, /**< writing out a simple response */ conn_nread, /**< reading in a fixed number of bytes */ conn_swallow, /**< swallowing unnecessary bytes w/o storing */ conn_closing, /**< closing this connection */ conn_mwrite, /**< writing out many items sequentially */ conn_closed, /**< connection is closed */ conn_max_state /**< Max state value (used for assertion) */ };
2.針對客戶端的命令,鏈接的狀態爲設置爲conn_parse_cmd,這樣就能夠對客戶端的命令進行解析處理,支持的命令以下:windows
/** * Definition of the different command opcodes. * See section 3.3 Command Opcodes */ typedef enum { PROTOCOL_BINARY_CMD_GET = 0x00, PROTOCOL_BINARY_CMD_SET = 0x01, PROTOCOL_BINARY_CMD_ADD = 0x02, PROTOCOL_BINARY_CMD_REPLACE = 0x03, PROTOCOL_BINARY_CMD_DELETE = 0x04, PROTOCOL_BINARY_CMD_INCREMENT = 0x05, PROTOCOL_BINARY_CMD_DECREMENT = 0x06, PROTOCOL_BINARY_CMD_QUIT = 0x07, PROTOCOL_BINARY_CMD_FLUSH = 0x08, PROTOCOL_BINARY_CMD_GETQ = 0x09, PROTOCOL_BINARY_CMD_NOOP = 0x0a, PROTOCOL_BINARY_CMD_VERSION = 0x0b, PROTOCOL_BINARY_CMD_GETK = 0x0c, PROTOCOL_BINARY_CMD_GETKQ = 0x0d, PROTOCOL_BINARY_CMD_APPEND = 0x0e, PROTOCOL_BINARY_CMD_PREPEND = 0x0f, PROTOCOL_BINARY_CMD_STAT = 0x10, PROTOCOL_BINARY_CMD_SETQ = 0x11, PROTOCOL_BINARY_CMD_ADDQ = 0x12, PROTOCOL_BINARY_CMD_REPLACEQ = 0x13, PROTOCOL_BINARY_CMD_DELETEQ = 0x14, PROTOCOL_BINARY_CMD_INCREMENTQ = 0x15, PROTOCOL_BINARY_CMD_DECREMENTQ = 0x16, PROTOCOL_BINARY_CMD_QUITQ = 0x17, PROTOCOL_BINARY_CMD_FLUSHQ = 0x18, PROTOCOL_BINARY_CMD_APPENDQ = 0x19, PROTOCOL_BINARY_CMD_PREPENDQ = 0x1a, PROTOCOL_BINARY_CMD_TOUCH = 0x1c, PROTOCOL_BINARY_CMD_GAT = 0x1d, PROTOCOL_BINARY_CMD_GATQ = 0x1e, PROTOCOL_BINARY_CMD_GATK = 0x23, PROTOCOL_BINARY_CMD_GATKQ = 0x24, PROTOCOL_BINARY_CMD_SASL_LIST_MECHS = 0x20, PROTOCOL_BINARY_CMD_SASL_AUTH = 0x21, PROTOCOL_BINARY_CMD_SASL_STEP = 0x22, /* These commands are used for range operations and exist within * this header for use in other projects. Range operations are * not expected to be implemented in the memcached server itself. */ PROTOCOL_BINARY_CMD_RGET = 0x30, PROTOCOL_BINARY_CMD_RSET = 0x31, PROTOCOL_BINARY_CMD_RSETQ = 0x32, PROTOCOL_BINARY_CMD_RAPPEND = 0x33, PROTOCOL_BINARY_CMD_RAPPENDQ = 0x34, PROTOCOL_BINARY_CMD_RPREPEND = 0x35, PROTOCOL_BINARY_CMD_RPREPENDQ = 0x36, PROTOCOL_BINARY_CMD_RDELETE = 0x37, PROTOCOL_BINARY_CMD_RDELETEQ = 0x38, PROTOCOL_BINARY_CMD_RINCR = 0x39, PROTOCOL_BINARY_CMD_RINCRQ = 0x3a, PROTOCOL_BINARY_CMD_RDECR = 0x3b, PROTOCOL_BINARY_CMD_RDECRQ = 0x3c /* End Range operations */ } protocol_binary_command;
3.memcached處理框架示意圖:緩存
三.redis、memcached、mongoDB 對比網絡
1)性能
都比較高,性能對咱們來講應該都不是瓶頸
整體來說,TPS方面redis和memcache差很少,要大於mongodb
2)操做的便利性
memcache數據結構單一
redis豐富一些,數據操做方面,redis更好一些,較少的網絡IO次數
mongodb支持豐富的數據表達,索引,最相似關係型數據庫,支持的查詢語言很是豐富
3)內存空間的大小和數據量的大小
redis在2.0版本後增長了本身的VM特性,突破物理內存的限制;能夠對key value設置過時時間(相似memcache)
memcache能夠修改最大可用內存,採用LRU算法
mongoDB適合大數據量的存儲,依賴操做系統VM作內存管理,吃內存也比較厲害,服務不要和別的服務在一塊兒
4)可用性(單點問題)
對於單點問題,
redis,依賴客戶端來實現分佈式讀寫;主從複製時,每次從節點從新鏈接主節點都要依賴整個快照,無增量複製,因性能和效率問題,
因此單點問題比較複雜;不支持自動sharding,須要依賴程序設定一致hash 機制。
一種替代方案是,不用redis自己的複製機制,採用本身作主動複製(多份存儲),或者改爲增量複製的方式(須要本身實現),一致性問題和性能的權衡
Memcache自己沒有數據冗餘機制,也不必;對於故障預防,採用依賴成熟的hash或者環狀的算法,解決單點故障引發的抖動問題。
mongoDB支持master-slave,replicaset(內部採用paxos選舉算法,自動故障恢復),auto sharding機制,對客戶端屏蔽了故障轉移和切分機制。
5)可靠性(持久化)
對於數據持久化和數據恢復:
redis支持(快照、AOF):依賴快照進行持久化,aof加強了可靠性的同時,對性能有所影響
memcache不支持,一般用在作緩存,提高性能;
MongoDB從1.8版本開始採用binlog方式支持持久化的可靠性
6)數據一致性(事務支持)
Memcache 在併發場景下,用cas保證一致性
redis事務支持比較弱,只能保證事務中的每一個操做連續執行
mongoDB不支持事務
7)數據分析
mongoDB內置了數據分析的功能(mapreduce),其餘不支持
8)應用場景
redis:數據量較小的更性能操做和運算上
memcache:用於在動態系統中減小數據庫負載,提高性能;作緩存,提升性能(適合讀多寫少,對於數據量比較大,能夠採用sharding)
MongoDB:主要解決海量數據的訪問效率問題
http://www.blogjava.net/paulwong/archive/2013/09/06/403746.html