正文node
1、NoSQL簡介
1.1 常見的優化思路和方向
1.1.1 MySQL主從讀寫分離
因爲數據庫的寫入壓力增長,Memcached只能緩解數據庫的讀取壓力。讀寫集中在一個數據庫上讓數據庫不堪重負,大部分網站開始使用主從複製技術達到讀寫分離,以提升讀寫性能和讀庫的可擴展性。Mysql的master-slave模式成爲這個時候的網站標配了。mysql
1.1.2 分庫分表
隨着web2.0的繼續高速發展,在Memcached的高速緩存,MySQL的主從複製,讀寫分離的基礎之上,這時MySQL主庫的寫壓力開始出現瓶頸,而數據量的持續猛增,因爲MyISAM使用表鎖,在高併發下會出現嚴重的鎖問題,大量的高併發MySQL應用開始使用InnoDB引擎代替MyISAM。同時,開始流行使用分表分庫來緩解寫壓力和數據增加的擴展問題。這個時候,分表分庫成了一個熱門技術,是業界討論的熱門技術問題。也就在這個時候,MySQL推出了還不太穩定的表分區,這也給技術實力通常的公司帶來了但願。雖然MySQL推出了MySQL Cluster集羣,可是因爲在互聯網幾乎沒有成功案例,性能也不能知足互聯網的要求,只是在高可靠性上提供了很是大的保證。web
1.2 NoSQL誕生的緣由
關係型數據庫面臨的問題:redis
- 擴展困難:因爲存在相似Join這樣多表查詢機制,使得數據庫在擴展方面很艱難;
- 讀寫慢:這種狀況主要發生在數據量達到必定規模時因爲關係型數據庫的系統邏輯很是複雜,使得其很是容易發生死鎖等的併發問題,因此致使其讀寫速度下滑很是嚴重;
- 成本高:企業級數據庫的License價格很驚人,而且隨着系統的規模,而不斷上升;
- 有限的支撐容量:現有關係型解決方案還沒法支撐Google這樣海量的數據存儲;
數據庫訪問的新需求:算法
- 低延遲的讀寫速度:應用快速地反應能極大地提高用戶的滿意度;
- 支撐海量的數據和流量:對於搜索這樣大型應用而言,須要利用PB級別的數據和能應對百萬級的流量;
- 大規模集羣的管理:系統管理員但願分佈式應用能更簡單的部署和管理;
- 龐大運營成本的考量:IT經理們但願在硬件成本、軟件成本和人力成本可以有大幅度地下降;
- NoSQL數據庫僅僅是關係數據庫在某些方面(性能、擴展)的一個彌補
- 單從功能上講,NoSQL的幾乎全部的功能,在關係數據庫上都可以知足。
- 通常會把NoSQL和關係數據庫進行結合使用,各取所長,各得其所。
- 在某些應用場合,好比一些配置的關係鍵值映射存儲、用戶名和密碼的存儲、Session會話存儲等等
- 在某些場景下,用NoSQL徹底能夠替代關係數據庫(如:MySQL)存儲。不但具備更高的性能,並且開發也更加方
1.3 分佈式系統的挑戰
CAP原理是指這三個要素最多隻能同時實現兩點,不可能三者兼顧。所以在進行分佈式架構設計時,必須作出取捨。而對於分佈式數據系統,分區容忍性是基本要求,不然就失去了價值。所以設計分佈式數據系統,就是在一致性和可用性之間取一個平衡。對於大多數WEB應用,其實並不須要強一致性,所以犧牲一致性而換取高可用性,是多數分佈式數據庫產品的方向。sql
在理論計算機科學中,CAP定理(CAP theorem),又被稱做布魯爾定理(Brewer’s theorem),它指出對於一個分佈式計算系統來講,不可能同時知足如下三點:mongodb
- 一致性(Consistency)—全部節點在同一時間具備相同的數據
- 可用性(Availability)—保證每一個請求無論成功或者失敗都有響應
- 分隔容忍(Partition tolerance)—系統中任意信息的丟失或失敗不會影響系統的繼續運做
1.3.1關係數據庫和NoSQL側重點
關係數據庫 | NoSQL |
---|---|
分佈式關係型數據庫中強調的ACID 分別是:原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)、持久性(Durability) |
對於許多互聯網應用來講,對於一致性要求能夠下降,而可用性(Availability)的要求則更爲明顯,在CAP理論基礎上,從而產生了弱一致性的理論BASE。 |
ACID的目的就是經過事務支持,保證數據的完整性和正確性 | BASE 分別是英文:Basically,Available(基本可用), Softstate(軟狀態)非實時同步,Eventual Consistency(最終一致)的縮寫,這個模型是反ACID 模型 |
1.4 NoSQL的優缺點
優勢:數據庫
- 簡單的擴展
典型例子是Cassandra,因爲其架構是相似於經典的P2P,因此能經過輕鬆地添加新的節點來擴展這個集羣;vim
- 快速的讀寫
主要例子有Redis,因爲其邏輯簡單,並且純內存操做,使得其性能很是出色,單節點每秒能夠處理超過10萬次讀寫操做;
- 低廉的成本
這是大多數分佈式數據庫共有的特色,由於主要都是開源軟件,沒有昂貴的License成本;
缺點:
- 不提供對SQL的支持
若是不支持SQL這樣的工業標準,將會對用戶產生必定的學習和應用遷移成本;
- 支持的特性不夠豐富
現有產品所提供的功能都比較有限,大多數NoSQL數據庫都不支持事務,也不像Oracle那樣能提供各類附加功能,好比BI和報表等;
- 現有產品的不夠成熟
大多數產品都還處於初創期,和關係型數據庫幾十年的完善不可同日而語;
1.5 NoSQL總結
- NoSQL數據庫的出現,彌補了關係數據(好比MySQL)在某些方面的不足,在某些方面能極大的節省開發成本和維護成本。
- MySQL和NoSQL都有各自的特色和使用的應用場景,二者的緊密結合將會
給web2.0的數據庫發展帶來新的思路。讓關係數據庫關注在關係上,NoSQL關注在功能、性能上。 - 隨着移動互聯網的發展,以及業務場景的多樣化,社交元素的廣泛化,Nosql從性能和功能上很好的補充了web2.0時代的原關係型數據的缺點,目前已是各大公司必備的技術之一。
2、NoSQL的分類
2.1 基本分類
Column-oriented(列式)
- 主要圍繞着「列(Column)」,而非 「行(Row)」進行數據存儲
- 屬於同一列的數據會盡量地存儲在硬盤同一個頁(Page)中
- 大多數列式數據庫都支持Column Family這個特性
- (不少相似數據倉庫(Data Warehouse)的應用,雖然每次查詢都會處理不少數據,可是每次所涉及的列並無不少)
- 特色:比較適合彙總(Aggregation)和數據倉庫這類應用。
Key-value(重要)
- 相似常見的HashTable,一個Key對應一個Value,可是其能提供很是快的查詢速度、大的數據存放量和高併發操做,
- 很是適合經過主鍵對數據進行查詢和修改等操做, 雖然不支持複雜的操做,但可經過上層的開發來彌補這個缺陷。
Document(文檔) (好比:mongodb)
- 相似常見的HashTable,一個Key對應一個Value,
- 其能提供很是快的查詢速度、大的數據存放量和高併發操做,
- 很是適合經過主鍵對數據進行查詢和修改等操做,
- 數據類型多且存在大量的空項。好比SNS類的用戶profile,手機,郵箱,地址,性別……有不少項,並且大部分是空項。
2.2 常見分類
![常見Nosql分類 常見Nosql分類](http://static.javashuo.com/static/loading.gif)
關注一致性和可用性的(CA)
這些數據庫對於分區容忍性方面比較不感冒,主要採用複製(Replication)這種方式來保證數據的安全性,常見的CA系統有:
- 傳統關係型數據庫,好比Postgres和MySQL等(Relational)
- Oracle (Relational)
- Aster Data (Relational)
- Greenplum (Relational)
- NoSQL:
- redis
- mongodb
- cassandra
關注一致性和分區容忍性的(CP)
這種系統將數據分佈在多個網絡分區的節點上,並保證這些數據的一致性,可是對於可用性的支持方面有問題,好比當集羣出現問題的話,節點有可能因沒法確保數據是一致性的而拒絕提供服務,主要的CP系統有:
- BigTable (Column-oriented)
- Hypertable (Column-oriented)
- HBase (Column-oriented)
- MongoDB (Document)
- Terrastore (Document)
- Redis (Key-value)
- Scalaris (Key-value)
- MemcacheDB (Key-value)
- Berkeley DB (Key-value)
關於可用性和分區容忍性的(AP)
這類系統主要以實現「最終一致性(Eventual Consistency)」來確保可用性和分區容忍性,AP的系統有:
- Dynamo (Key-value)
- Voldemort (Key-value)
- Tokyo Cabinet (Key-value)
- KAI (Key-value)
- Cassandra (Column-oriented)
- CouchDB (Document-oriented)
- SimpleDB (Document-oriented)
- Riak (Document-oriented)
2.3 常見Nosql分類和部分表明
![常見Nosql分類和部分表明 常見Nosql分類和部分表明](http://static.javashuo.com/static/loading.gif)
3、企業常見Nosql應用
3.1 純NoSQL架構(Nosql爲主)
- 在一些數據結構、查詢關係很是簡單的系統中,咱們能夠只使用NoSQL便可以解決存儲問題。
- 在一些數據庫結構常常變化,數據結構不定的系統中,就很是適合使用NoSQL來存儲。
- 好比監控系統中的監控信息的存儲,可能每種類型的監控信息都不太同樣。
- 有些NoSQL數據庫已經具備部分關係數據庫的關係查詢特性,他們的功能介於key-value和關係數據庫之間,卻具備key-value數據庫的性能,基本能知足絕大部分web 2.0網站的查詢需求。
![純Nosql架構 純Nosql架構](http://static.javashuo.com/static/loading.gif)
3.2 以NoSQL爲數據源的架構(Nosql爲主)
- 數據直接寫入NoSQL,再經過NoSQL同步協議複製到其餘存儲。
- 根據應用的邏輯來決定去相應的存儲獲取數據。
- 應用程序只負責把數據直接寫入到NoSQL數據庫,而後經過NoSQL的複製協議,把NoSQL數據的每次寫入,更新,刪除操做都複製到MySQL數據庫中。
- 同時,也能夠經過複製協議把數據同步複製到全文檢索實現強大的檢索功能。
- 這種架構須要考慮數據複製的延遲問題,這跟使用MySQL的mastersalve模式的延遲問題是同樣的,解決方法也同樣。
![Nosql爲主 Nosql爲主](http://static.javashuo.com/static/loading.gif)
3.3 NoSQL做爲鏡像(nosql爲輔)
- 不改變原有的以MySQL做爲存儲的架構,使用NoSQL做爲輔助鏡像存儲,用NoSQL的優點輔助提高性能。
- 在原有基於MySQL數據庫的架構上增長了一層輔助的NoSQL存儲。
- 在寫入MySQL數據庫後,同時寫入到NoSQL數據庫,讓MySQL和NoSQL擁有相同的鏡像數據。
- 在某些能夠根據主鍵查詢的地方,使用高效的NoSQL數據庫查詢。
![Nosql爲輔 Nosql爲輔](http://static.javashuo.com/static/loading.gif)
3.4 NoSQL爲鏡像(同步模式,nosql爲輔)
- 經過MySQL把數據同步到NoSQL中, ,是一種對寫入透明可是具備更高技術難度一種模式
- 適用於現有的比較複雜的老系統,經過修改代碼不易實現,可能引發新的問題。同時也適用於須要把數據同步到多種類型的存儲中。
![同步模式,Nosql爲輔 同步模式,Nosql爲輔](http://static.javashuo.com/static/loading.gif)
3.5 MySQL和NoSQL組合(nosql爲輔)
- MySQL中只存儲須要查詢的小字段,NoSQL存儲全部數據。
- 把須要查詢的字段,通常都是數字,時間等類型的小字段存儲於MySQL中,根據查詢創建相應的索引,
- 其餘不須要的字段,包括大文本字段都存儲在NoSQL中。
- 在查詢的時候,咱們先從MySQL中查詢出數據的主鍵,而後從NoSQL中直接取出對應的數據便可。
![Nosql爲輔 Nosql爲輔](http://static.javashuo.com/static/loading.gif)
3.6 其餘應用
因爲NoSQL數據庫天生具備高性能、易擴展的特色,因此咱們經常結合關係數據庫,存儲一些高性能的、海量的數據。
從另一個角度看,根據NoSQL的高性能特色,它一樣適合用於緩存數據。用NoSQL緩存數據能夠分爲內存模式和磁盤持久化模式。
內存模式
- Memcached提供了至關高的讀寫性能,在互聯網發展過程當中,一直是緩存服務器的首選。
- NoSQL數據庫Redis又爲咱們提供了功能更增強大的內存存儲功能。跟Memcached比,Redis的一個key的能夠存儲多種數據結構Strings、Hashes、Lists、Sets、Sorted sets。
- Redis不但功能強大,並且它的性能徹底超越大名鼎鼎的Memcached。
- Redis支持List、hashes等多種數據結構的功能,提供了更加易於使用的api和操做性能,好比對緩存的list數據的修改。
持久化模式
- 雖然基於內存的緩存服務器具備高性能,低延遲的特色,可是內存成本高、內存數據易失卻不容忽視。
- 大部分互聯網應用的特色都是數據訪問有熱點,也就是說,只有一部分數據是被頻繁訪問的。
- 其實NoSQL數據庫內部也是經過內存緩存來提升性能的,經過一些比較好的算法
- 把熱點數據進行內存cache
- 非熱點數據存儲到磁盤
- 以節省內存佔用
- 使用NoSQL來作緩存,因爲其不受內存大小的限制,咱們能夠把一些不常訪問、不怎麼更新的數據也緩存起來。
4、redis
4.1 什麼是redis?
redis是一個key-value存儲系統。和Memcached相似,它支持存儲的value類型相對更多,包括string(字符串)、list(鏈表)、set(集合)、zset(sortedset --有序集合)和hash(哈希類型)。這些數據類型都支持push/pop、add/remove及取交集並集和差集及更豐富的操做,並且這些操做都是原子性的。在此基礎上,redis支持各類不一樣方式的排序。與memcached同樣,爲了保證效率,數據都是緩存在內存中。區別的是redis會週期性的把更新的數據寫入磁盤或者把修改操做寫入追加的記錄文件,而且在此基礎上實現了master-slave(主從)同步。
Redis 是一個高性能的key-value數據庫。 redis的出現,很大程度補償了memcached這類key/value存儲的不足,在部 分場合能夠對關係數據庫起到很好的補充做用。它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客戶端,使用很方便。
Redis支持主從同步。數據能夠從主服務器向任意數量的從服務器上同步,從服務器能夠是關聯其餘從服務器的主服務器。這使得Redis可執行單層樹複製。存盤能夠有意無心的對數據進行寫操做。因爲徹底實現了發佈/訂閱機制,使得從數據庫在任何地方同步樹時,可訂閱一個頻道並接收主服務器完整的消息發佈記錄。同步對讀取操做的可擴展性和數據冗餘頗有幫助。
redis的官網地址,很是好記,是redis.io。
目前,Vmware在資助着redis項目的開發和維護。
4.2 redis的特性
- 徹底居於內存,數據實時的讀寫內存,定時閃回到文件中。採用單線程,避免了沒必要要的上下文切換和競爭條件;
- 支持高併發量,官方宣傳支持10萬級別的併發讀寫;
- 支持持久存儲,機器重啓後的,從新加載模式,不會掉數據;
- 海量數據存儲,分佈式系統支持,數據一致性保證,方便的集羣節點添加/刪除;
- Redis不只僅支持簡單的k/v類型的數據,同時還提供list,set,zset,hash等數據結構的存儲;
- 災難恢復–memcache掛掉後,數據不可恢復; redis數據丟失後能夠經過aof恢復;
- 虛擬內存–Redis當物理內存用完時,能夠將一些好久沒用到的value 交換到磁盤;
- Redis支持數據的備份,即master-slave模式的數據備份。
4.3 redis的架構
![redis的架構 redis的架構](http://static.javashuo.com/static/loading.gif)
各功能模塊說明以下:File Event
: 處理文件事件,接受它們發來的命令請求(讀事件),並將命令的執行結果返回給客戶端(寫事件))Time Event
: 時間事件(更新統計信息,清理過時數據,附屬節點同步,按期持久化等)AOF
: 命令日誌的數據持久化RDB
:實際的數據持久化Lua Environment
: Lua 腳本的運行環境. 爲了讓 Lua 環境符合 Redis 腳本功能的需求,Redis 對 Lua 環境進行了一系列的修改,包括添加函數庫、更換隨機函數、保護全局變量,等等Command table(命令表)
:在執行命令時,根據字符來查找相應命令的實現函數。Share Objects(對象共享)
:
主要存儲常見的值:
a.各類命令常見的返回值,例如返回值OK、ERROR、WRONGTYPE等字符;
b. 小於 redis.h/REDIS_SHARED_INTEGERS (默認1000)的全部整數。經過預分配的一些常見的值對象,並在多個數據結構之間共享對象,程序避免了重複分配的麻煩。也就是說,這些常見的值在內存中只有一份。Databases
:Redis數據庫是真正存儲數據的地方。固然,數據庫自己也是存儲在內存中的。
4.4 redis 啓動流程
![redis啓動流程 redis啓動流程](http://static.javashuo.com/static/loading.gif)
4.5 redis 安裝方式
redis安裝經常使用兩種方式,yum安裝和源碼包安裝
yum 安裝:一般是在線安裝,好處是安裝方式簡單,不易出錯;經常使用的安裝yum源爲epel。
源碼包安裝:是先將 redis 的源碼下載下來,在本身的系統裏編譯生成可執行文件,而後執行,好處是由於是在本身的系統上編譯的,更符合本身系統的性能,也就是說在本身的系統上執行 redis 服務性能效率更好。
區別:路徑和啓動方式不一樣,支持的模塊也不一樣。
4.5.1 redis 程序路徑
配置文件:
/etc/redis.conf
主程序:/usr/bin/redis-server
客戶端:/usr/bin/redis-cli
UnitFile:/usr/lib/systemd/system/redis.service
數據目錄:/var/lib/redis
監聽:6379/tcp
4.6 redis 配置文件
4.6.1 網絡配置項(NETWORK)
### NETWORK ### bind IP #監聽地址 port PORT #監聽端口 protected-mode yes #是否開啓保護模式,默認開啓。要是配置裏沒有指定bind和密碼。開啓該參數後,redis只會本地進行訪問,拒絕外部訪問。 tcp-backlog 511 #定義了每個端口最大的監聽隊列的長度 unixsocket /tmp/redis.sock #也能夠打開套接字監聽 timeout 0 #鏈接的空閒超時時長;
![網絡配置項 網絡配置項](http://static.javashuo.com/static/loading.gif)
4.6.2 通用配置項(GENERAL)
### GENERAL ### daemonize no #是否以守護進程啓動 supervised no #能夠經過upstart和systemd管理Redis守護進程,這個參數是和具體的操做系統相關的 pidfile "/var/run/redis/redis.pid" #pid文件 loglevel notice #日誌等級 logfile "/var/log/redis/redis.log" #日誌存放文件 databases 16 #設定數據庫數量,默認爲16個,每一個數據庫的名字均爲整數,從0開始編號,默認操做的數據庫爲0; 切換數據庫的方法:SELECT <dbid>
![通用配置項 通用配置項](http://static.javashuo.com/static/loading.gif)
4.6.3 快照配置(SNAPSHOTTING)
### SNAPSHOTTING ### save 900 1 #900秒有一個key變化,就作一個保存 save 300 10 #300秒有10個key變化,就作一個保存,這裏須要和開發溝通 save 60 10000 #60秒有10000個key變化就作一個保存 stop-writes-on-bgsave-error yes #在出現錯誤的時候,是否是要中止保存 rdbcompression yes #使用壓縮rdb文件,rdb文件壓縮使用LZF壓縮算法,yes:壓縮,可是須要一些cpu的消耗;no:不壓縮,須要更多的磁盤空間 rdbchecksum yes #是否校驗rdb文件。從rdb格式的第五個版本開始,在rdb文件的末尾會帶上CRC64的校驗和。這跟有利於文件的容錯性,可是在保存rdb文件的時候,會有大概10%的性能損耗,因此若是你追求高性能,能夠關閉該配置。 dbfilename "along.rdb" #rdb文件的名稱 dir "/var/lib/redis" #數據目錄,數據庫的寫入會在這個目錄。rdb、aof文件也會寫在這個目錄
![快照配置 快照配置](http://static.javashuo.com/static/loading.gif)
4.6.4 限制相關配置(LIMITS)
### LIMITS ### maxclients 10000 #設置能連上redis的最大客戶端鏈接數量 maxmemory <bytes> #redis配置的最大內存容量。當內存滿了,須要配合maxmemory-policy策略進行處理。 maxmemory-policy noeviction #淘汰策略:volatile-lru, allkeys-lru, volatile-random, allkeys-random, volatile-ttl, noeviction 內存容量超過maxmemory後的處理策略: ① # volatile-lru:利用LRU算法移除設置過過時時間的key。 ② # volatile-random:隨機移除設置過過時時間的key。 ③ # volatile-ttl:移除即將過時的key,根據最近過時時間來刪除(輔以TTL) ④ # allkeys-lru:利用LRU算法移除任何key。 ⑤ # allkeys-random:隨機移除任何key。 ⑥ # noeviction:不移除任何key,只是返回一個寫錯誤。 # 上面的這些驅逐策略,若是redis沒有合適的key驅逐,對於寫命令,仍是會返回錯誤。redis將再也不接收寫請求,只接收get請求。寫命令包括:set setnx maxmemory-samples 5 #淘汰算法運行時的採樣樣本數;
![限制相關配置 限制相關配置](http://static.javashuo.com/static/loading.gif)
4.6.5 持久化配置(APPEND ONLY MODE)
### APPEND ONLY MODE ### # 默認redis使用的是rdb方式持久化,這種方式在許多應用中已經足夠用了。可是redis若是中途宕機,會致使可能有幾分鐘的數據丟失,根據save來策略進行持久化,Append Only File是另外一種持久化方式,能夠提供更好的持久化特性。Redis會把每次寫入的數據在接收後都寫入 appendonly.aof 文件,每次啓動時Redis都會先把這個文件的數據讀入內存裏,先忽略RDB文件。 appendonly no #不啓動aof模式 appendfilename "appendonly.aof" #據讀入內存裏,先忽略RDB文件,aof文件名(default: "appendonly.aof") appendfsync Redis supports three different modes: no:redis不執行主動同步操做,而是OS進行; everysec:每秒一次; always:每語句一次;
若是Redis只是將客戶端修改數據庫的指令重現存儲在AOF文件中,那麼AOF文件的大小會不斷的增長,由於AOF文件只是簡單的重現存儲了客戶端的指令,而並無進行合併。對於該問題最簡單的處理方式,即當AOF文件知足必定條件時就對AOF進行rewrite,rewrite是根據當前內存數據庫中的數據進行遍歷寫到一個臨時的AOF文件,待寫完後替換掉原來的AOF文件便可。
redis重寫會將多個key、value對集合來用一條命令表達。在rewrite期間的寫操做會保存在內存的rewrite buffer中,rewrite成功後這些操做也會複製到臨時文件中,在最後臨時文件會代替AOF文件。
no-appendfsync-on-rewrite no #在aof重寫或者寫入rdb文件的時候,會執行大量IO,此時對於everysec和always的aof模式來講,執行fsync會形成阻塞過長時間,no-appendfsync-on-rewrite字段設置爲默認設置爲no。若是對延遲要求很高的應用,這個字段能夠設置爲yes,不然仍是設置爲no,這樣對持久化特性來講這是更安全的選擇。設置爲yes表示rewrite期間對新寫操做不fsync,暫時存在內存中,等rewrite完成後再寫入,默認爲no,建議yes。Linux的默認fsync策略是30秒。可能丟失30秒數據。 auto-aof-rewrite-percentage 100 aof自動重寫配置。當目前aof文件大小超過上一次重寫的aof文件大小的百分之多少進行重寫,即當aof文件增加到必定大小的時候Redis可以調用bgrewrite aof對日誌文件進行重寫。當前AOF文件大小是上第二天志重寫獲得AOF文件大小的二倍(設置爲100)時,自動啓動新的日誌重寫過程。 auto-aof-rewrite-min-size 64mb #設置容許重寫的最小aof文件大小,避免了達到約定百分比但尺寸仍然很小的狀況還要重寫。上述兩個條件同時知足時,方會觸發重寫AOF;與上次aof文件大小相比,其增加量超過100%,且大小很多於64MB; aof-load-truncated yes #指redis在恢復時,會忽略最後一條可能存在問題的指令。aof文件可能在尾部是不完整的,出現這種現象,能夠選擇讓redis退出,或者導入儘量多的數據。若是選擇的是yes,當截斷的aof文件被導入的時候,會自動發佈一個log給客戶端而後load。 若是是no,用戶必須手動redis-check-aof修復AOF文件才能夠。 注意:持久機制自己不能取代備份;應該制訂備份策略,對redis庫按期備份;Redis服務器啓動時用持久化的數據文件恢復數據,會優先使用AOF;
![redis 持久化存儲讀取 redis 持久化存儲讀取](http://static.javashuo.com/static/loading.gif)
咱們繼續來看 redis 的持久化:
RDB:snapshotting, 二進制格式;按事先定製的策略,週期性地將數據從內存同步至磁盤;數據文件默認爲dump.rdb;
客戶端顯式使用SAVE或BGSAVE命令來手動啓動快照保存機制;
SAVE:同步,即在主線程中保存快照,此時會阻塞全部客戶端請求;
BGSAVE:異步;backgroud
AOF:Append Only File, fsync
記錄每次寫操做至指定的文件尾部實現的持久化;當redis重啓時,可經過從新執行文件中的命令在內存中重建出數據庫;
BGREWRITEAOF:AOF文件重寫;
不會讀取正在使用AOF文件,而是經過將內存中的數據以命令的方式保存至臨時文件中,完成以後替換原來的AOF文件;
4.6.6 慢查詢日誌相關配置(SLOW LOG)
### SLOW LOG ### slowlog-log-slower-than 10000 #當命令的執行超過了指定時間,單位是微秒;1s=10^6微秒 slowlog-max-len 128 #慢查詢日誌長度。當一個新的命令被寫進日誌的時候,最老的那個記錄會被刪掉。 ADVANCED配置: hash-max-ziplist-entries 512 hash-max-ziplist-value 64 設置ziplist的鍵數量最大值,每一個值的最大空間;
![慢查詢日誌相關配置 慢查詢日誌相關配置](http://static.javashuo.com/static/loading.gif)
4.7 redis命令介紹
└── bin
├── redis-benchmark #redis性能測試工具,能夠測試在本系統本配置下的讀寫性能
├── redis-check-aof #對更新日誌appendonly.aof檢查,是否可用
├── redis-check-dump #用於檢查本地數據庫的rdb文件
├── redis-cli #redis命令行操做工具,也能夠用telnet根據其純文本協議來操做
├── redis-sentinel Redis-sentinel 是Redis實例的監控管理、通知和實例失效備援服務,是Redis集羣的管理工具
└── redis-server #redis服務器的daemon啓動程序
4.7.1 redis-cli命令介紹
redis-cli -p 6379 #默認選擇 db庫是 0
redis 127.0.0.1:6379> keys * #查看當前所在「db庫」全部的緩存key
redis 127.0.0.1:6379> select 8 #選擇 db庫
redis 127.0.0.1:6379> FLUSHALL #清除全部的緩存key
redis 127.0.0.1:63798> FLUSHDB #清除當前「db庫」全部的緩存key
redis 127.0.0.1:6379> set keyname keyvalue #設置緩存值
redis 127.0.0.1:6379> get keyname #獲取緩存值
redis 127.0.0.1:6379> del keyname #刪除緩存值:返回刪除數量(0表明沒刪除)
服務端的相關命令:
time
:返回當前服務器時間client list
: 返回全部鏈接到服務器的客戶端信息和統計數據 參見http://redisdoc.com/server/client_list.htmlclient kill ip:port
:關閉地址爲 ip:port 的客戶端save
:將數據同步保存到磁盤bgsave
:將數據異步保存到磁盤lastsave
:返回上次成功將數據保存到磁盤的Unix時戳shundown
:將數據同步保存到磁盤,而後關閉服務info
:提供服務器的信息和統計config resetstat
:重置info命令中的某些統計數據config get
:獲取配置文件信息config set
:動態地調整 Redis 服務器的配置(configuration)而無須重啓,能夠修改的配置參數可使用命令 CONFIG GET * 來列出config rewrite
:Redis 服務器時所指定的 redis.conf 文件進行改寫monitor
:實時轉儲收到的請求slaveof
:改變複製策略設置debug
:sleep segfaultslowlog get
:獲取慢查詢日誌slowlog len
:獲取慢查詢日誌條數slowlog reset
:清空慢查詢
4.8 redis 經常使用數據類型
![redis 經常使用數據類型 redis 經常使用數據類型](http://static.javashuo.com/static/loading.gif)
Redis內部使用一個redisObject對象來表示全部的key和value,redisObject最主要的信息如上圖所示:
type表明一個value對象具體是何種數據類型
encoding是不一樣數據類型在redis內部的存儲方式
好比:type=string表明value存儲的是一個普通字符串,那麼對應的encoding能夠是raw或者是int,若是是int則表明實際redis內部是按數值型類存儲和表示這個字符串的,固然前提是這個字符串自己能夠用數值表示,好比:「123」 "456"這樣的字符串。
Redis的鍵值可使用物種數據類型:字符串,散列表,列表,集合,有序集合。
4.8.1 對KEY操做的命令
exists(key)
:確認一個key是否存在del(key)
:刪除一個keytype(key)
:返回值的類型keys(pattern)
:返回知足給定pattern的全部keyrandomkey
:隨機返回key空間的一個keyrename(oldname, newname)
:重命名keydbsize
:返回當前數據庫中key的數目expire
:設定一個key的活動時間(s)ttl
:得到一個key的活動時間move(key, dbindex)
:移動當前數據庫中的key到dbindex數據庫flushdb
:刪除當前選擇數據庫中的全部keyflushall
:刪除全部數據庫中的全部key
4.8.2 對String操做的命令
應用場景:String是最經常使用的一種數據類型,普通的key/ value 存儲均可以歸爲此類.便可以徹底實現目前 Memcached 的功能,而且效率更高。還能夠享受Redis的定時持久化,操做日誌及 Replication等功能。除了提供與 Memcached 同樣的get、set、incr、decr 等操做外,Redis還提供了下面一些操做:
set(key, value):給數據庫中名稱爲key的string賦予值value
get(key):返回數據庫中名稱爲key的string的valuegetset(key, value)
:給名稱爲key的string賦予上一次的valuemget(key1, key2,…, key N)
:返回庫中多個string的valuesetnx(key, value)
:添加string,名稱爲key,值爲valuesetex(key, time, value)
:向庫中添加string,設定過時時間timemset(key N, value N)
:批量設置多個string的值msetnx(key N, value N)
:若是全部名稱爲key i的string都不存在incr(key)
:名稱爲key的string增1操做incrby(key, integer)
:名稱爲key的string增長integerdecr(key)
:名稱爲key的string減1操做decrby(key, integer)
:名稱爲key的string減小integerappend(key, value)
:名稱爲key的string的值附加valuesubstr(key, start, end)
:返回名稱爲key的string的value的子串
4.8.3 對Hash操做的命令
應用場景:在Memcached中,咱們常常將一些結構化的信息打包成HashMap,在客戶端序列化後存儲爲一個字符串的值,好比用戶的暱稱、年齡、性別、積分等,這時候在須要修改其中某一項時,一般須要將全部值取出反序列化後,修改某一項的值,再序列化存儲回去。這樣不只增大了開銷,也不適用於一些可能併發操做的場合(好比兩個併發的操做都須要修改積分)。而Redis的Hash結構可使你像在數據庫中Update一個屬性同樣只修改某一項屬性值。
hset(key, field, value)
:向名稱爲key的hash中添加元素fieldhget(key, field)
:返回名稱爲key的hash中field對應的valuehmget(key, (fields))
:返回名稱爲key的hash中field i對應的valuehmset(key, (fields))
:向名稱爲key的hash中添加元素fieldhincrby(key, field, integer)
:將名稱爲key的hash中field的value增長integerhexists(key, field)
:名稱爲key的hash中是否存在鍵爲field的域hdel(key, field)
:刪除名稱爲key的hash中鍵爲field的域hlen(key)
:返回名稱爲key的hash中元素個數hkeys(key)
:返回名稱爲key的hash中全部鍵hvals(key)
:返回名稱爲key的hash中全部鍵對應的valuehgetall(key)
:返回名稱爲key的hash中全部的鍵(field)及其對應的value
4.8.4 對List操做的命令
Redis list的應用場景很是多,也是Redis最重要的數據結構之一,好比twitter的關注列表,粉絲列表等均可以用Redis的list結構來實現。咱們在看完一條微博以後,經常會評論一番,或者看看其餘人的吐槽。每條評論的記錄都是按照時間順序排序的。
具體操做命令以下:
rpush(key, value)
:在名稱爲key的list尾添加一個值爲value的元素lpush(key, value)
:在名稱爲key的list頭添加一個值爲value的 元素llen(key)
:返回名稱爲key的list的長度lrange(key, start, end)
:返回名稱爲key的list中start至end之間的元素ltrim(key, start, end)
:截取名稱爲key的listlindex(key, index)
:返回名稱爲key的list中index位置的元素lset(key, index, value)
:給名稱爲key的list中index位置的元素賦值lrem(key, count, value)
:刪除count個key的list中值爲value的元素lpop(key)
:返回並刪除名稱爲key的list中的首元素rpop(key)
:返回並刪除名稱爲key的list中的尾元素blpop(key1, key2,… key N, timeout)
:lpop命令的block版本。brpop(key1, key2,… key N, timeout)
:rpop的block版本。rpoplpush(srckey, dstkey)
:返回並刪除名稱爲srckey的list的尾元素,並將該元素添加到名稱爲dstkey的list的頭部
4.8.5 對Set操做的命令
Set 就是一個集合,集合的概念就是一堆不重複值的組合。利用 Redis 提供的 Set 數據結構,能夠存儲一些集合性的數據。好比在微博應用中,能夠將一個用戶全部的關注人存在一個集合中,將其全部粉絲存在一個集合。由於 Redis 很是人性化的爲集合提供了求交集、並集、差集等操做,那麼就能夠很是方便的實現如共同關注、共同喜愛、二度好友等功能。
具體操做命令以下:
sadd(key, member)
:向名稱爲key的set中添加元素membersrem(key, member)
:刪除名稱爲key的set中的元素memberspop(key)
:隨機返回並刪除名稱爲key的set中一個元素smove(srckey, dstkey, member)
:移到集合元素scard(key)
:返回名稱爲key的set的基數sismember(key, member)
:member是不是名稱爲key的set的元素sinter(key1, key2,…key N)
:求交集sinterstore(dstkey, (keys))
:求交集並將交集保存到dstkey的集合sunion(key1, (keys))
:求並集sunionstore(dstkey, (keys))
:求並集並將並集保存到dstkey的集合sdiff(key1, (keys))
:求差集sdiffstore(dstkey, (keys))
:求差集並將差集保存到dstkey的集合smembers(key)
:返回名稱爲key的set的全部元素srandmember(key)
:隨機返回名稱爲key的set的一個元素
5、redis 主從複製
5.1 方式簡介
Redis的複製方式有兩種,一種是主(master)-從(slave)模式,一種是從(slave)-從(slave)模式,所以Redis的複製拓撲圖會豐富一些,能夠像星型拓撲,也能夠像個有向無環。一個Master能夠有多個slave主機,支持鏈式複製;Master以非阻塞方式同步數據至slave主機;
拓撲圖以下:
![拓撲圖 拓撲圖](http://static.javashuo.com/static/loading.gif)
5.2 複製優勢
經過配置多個Redis實例,數據備份在不一樣的實例上,主庫專一寫請求,從庫負責讀請求,這樣的好處主要體如今下面幾個方面
1. 高可用性
在一個Redis集羣中,若是master宕機,slave能夠介入並取代master的位置,所以對於整個Redis服務來講不至於提供不了服務,這樣使得整個Redis服務足夠安全。
2. 高性能
在一個Redis集羣中,master負責寫請求,slave負責讀請求,這麼作一方面經過將讀請求分散到其餘機器從而大大減小了master服務器的壓力,另外一方面slave專一於提供讀服務從而提升了響應和讀取速度。
3. 水平擴展性
經過增長slave機器能夠橫向(水平)擴展Redis服務的整個查詢服務的能力。
5.3 須要解決的問題
複製提供了高可用性的解決方案,但同時引入了分佈式計算的複雜度問題,認爲有兩個核心問題:
1. 數據一致性問題: 如何保證master服務器寫入的數據可以及時同步到slave機器上。
2. 讀寫分離: 如何在客戶端提供讀寫分離的實現方案,經過客戶端實現將讀寫請求分別路由到master和slave實例上。
上面兩個問題,尤爲是第一個問題是Redis服務實現一直在演變,致力於解決的一個問題:複製實時性和數據一致性矛盾。
Redis提供了提升數據一致性的解決方案,一致性程度的增長雖然使得我可以更信任數據,可是更好的一致性方案一般伴隨着性能的損失,從而減小了吞吐量和服務能力。然而咱們但願系統的性能達到最優,則必需要犧牲一致性的程度,所以Redis的複製實時性和數據一致性是存在矛盾的。
5.4 具體實例見實戰一
6、redis集羣cluster
如何解決redis橫向擴展的問題----redis集羣實現方式
6.1 實現基礎——分區
分區是分割數據到多個Redis實例的處理過程,所以每一個實例只保存key的一個子集。經過利用多臺計算機內存的和值,容許咱們構造更大的數據庫。經過多核和多臺計算機,容許咱們擴展計算能力;經過多臺計算機和網絡適配器,容許咱們擴展網絡帶寬。
集羣的幾種實現方式:
- 客戶端分片
- 基於代理的分片
- 路由查詢
6.1.1 客戶端分片
由客戶端決定key寫入或者讀取的節點。
包括jedis在內的一些客戶端,實現了客戶端分片機制。
優勢
簡單,性能高
缺點
1. 業務邏輯與數據存儲邏輯耦合
2. 可運維性差
3. 多業務各自使用redis,集羣資源難以管理
4. 不支持動態增刪節點
![客戶端分片 客戶端分片](http://static.javashuo.com/static/loading.gif)
6.1.2 基於代理的分片
客戶端發送請求到一個代理,代理解析客戶端的數據,將請求轉發至正確的節點,而後將結果回覆給客戶端。
開源方案
1. Twemproxy
2. codis
特性
1. 透明接入
2. 業務程序不用關心後端Redis實例,切換成本低。
3. Proxy 的邏輯和存儲的邏輯是隔離的。
4. 代理層多了一次轉發,性能有所損耗。
![基於代理的分片 基於代理的分片](http://static.javashuo.com/static/loading.gif)
Twemproxy
Proxy-based
twtter開源,C語言編寫,單線程。
支持 Redis 或 Memcached 做爲後端存儲。
優勢:
1. 支持失敗節點自動刪除
2. 與redis的長鏈接,鏈接複用,鏈接數可配置
3. 自動分片到後端多個redis實例上
4. 多種hash算法:可以使用不一樣的分片策略和散列函數
5. 能夠設置後端實例的權重
缺點:
1. 性能低:代理層損耗 && 自己效率低下
2. Redis功能支持不完善:不支持針對多個值的操做
3. 自己不提供動態擴容,透明數據遷移等功能
![Twemproxy Twemproxy](http://static.javashuo.com/static/loading.gif)
Codis
Codis由豌豆莢於2014年11月開源,基於Go和C開發,是近期涌現的、國人開發的優秀開源軟件之一。現已普遍用於豌豆莢的各類Redis業務場景。從3個月的各類壓力測試來看,穩定性符合高效運維的要求。性能更是改善不少,最初比Twemproxy慢20%;如今比Twemproxy快近100%(條件:多實例,通常Value長度)。
![Codis Codis](http://static.javashuo.com/static/loading.gif)
6.2 開源方案——Redis-cluster
將請求發送到任意節點,接收到請求的節點會將查詢請求發送到正確的節點上執行。
![Redis-cluster原理圖 Redis-cluster原理圖](http://static.javashuo.com/static/loading.gif)
Redis-cluster由redis官網推出,可線性擴展到1000個節點。無中心架構;使用一致性哈希思想;客戶端直連redis服務,免去了proxy代理的損耗。
![Redis-cluster架構 Redis-cluster架構](http://static.javashuo.com/static/loading.gif)
6.2.1 Redis集羣介紹
Redis 集羣是一個提供在多個Redis間節點間共享數據的程序集。
Redis 集羣並不支持處理多個keys的命令,由於這須要在不一樣的節點間移動數據,從而達不到像Redis那樣的性能,在高負載的狀況下可能會致使不可預料的錯誤。
Redis 集羣經過分區來提供必定程度的可用性,在實際環境中當某個節點宕機或者不可達的狀況下繼續處理命令.
Redis 集羣的優點:
1. 自動分割數據到不一樣的節點上。
2. 整個集羣的部分節點失敗或者不可達的狀況下可以繼續處理命令。
Redis 集羣的數據分片
Redis 集羣沒有使用一致性hash,而是引入了哈希槽的概念.
Redis 集羣有16384個哈希槽,每一個key經過CRC16校驗後對16384取模來決定放置哪一個槽。集羣的每一個節點負責一部分hash槽。舉個例子,好比當前集羣有3個節點,那麼:
節點 A 包含 0 到 5500號哈希槽。
節點 B 包含5501 到 11000 號哈希槽。
節點 C 包含11001 到 16384號哈希槽。
這種結構很容易添加或者刪除節點。好比若是我想新添加個節點D,我須要從節點 A,B,C中得部分槽到D上。若是我想移除節點A,須要將A中得槽移到B和C節點上,而後將沒有任何槽的A節點從集羣中移除便可。因爲從一個節點將哈希槽移動到另外一個節點並不會中止服務,因此不管添加刪除或者改變某個節點的哈希槽的數量都不會形成集羣不可用的狀態。
6.2.2 Redis 集羣的主從複製模型
爲了使在部分節點失敗或者大部分節點沒法通訊的狀況下集羣仍然可用,因此集羣使用了主從複製模型,每一個節點都會有N-1個複製品。
在咱們例子中具備A,B,C三個節點的集羣,在沒有複製模型的狀況下,若是節點B失敗了,那麼整個集羣就會覺得缺乏5501-11000這個範圍的槽而不可用。
然而若是在集羣建立的時候(或者過一段時間)咱們爲每一個節點添加一個從節點A1,B1,C1,那麼整個集羣便有三個master節點和三個slave節點組成,這樣在節點B失敗後,集羣便會選舉B1爲新的主節點繼續服務,整個集羣便不會由於槽找不到而不可用了。不過當B和B1 都失敗後,集羣是不可用的。
Redis 一致性保證
Redis 並不能保證數據的強一致性. 這意味這在實際中集羣在特定的條件下可能會丟失寫操做。
第一個緣由是由於集羣是用了異步複製. 寫操做過程:
客戶端向主節點B寫入一條命令.
主節點B向客戶端回覆命令狀態.
主節點將寫操做複製給他得從節點 B1, B2 和 B3.
主節點對命令的複製工做發生在返回命令回覆以後, 由於若是每次處理命令請求都須要等待複製操做完成的話,那麼主節點處理命令請求的速度將極大地下降 —— 咱們必須在性能和一致性之間作出權衡。注意:Redis 集羣可能會在未來提供同步寫的方法。Redis 集羣另一種可能會丟失命令的狀況是集羣出現了網絡分區, 而且一個客戶端與至少包括一個主節點在內的少數實例被孤立。
實戰一:redis主從複製的實現
1)原理架構圖
![原理架構圖 原理架構圖](http://static.javashuo.com/static/loading.gif)
上圖爲Redis複製工做過程:
- slave向master發送sync命令。
- master開啓子進程來說dataset寫入rdb文件,同時將子進程完成以前接收到的寫命令緩存起來。
- 子進程寫完,父進程得知,開始將RDB文件發送給slave。master發送完RDB文件,將緩存的命令也發給slave。master增量的把寫命令發給slave。
值得注意的是,當slave跟master的鏈接斷開時,slave能夠自動的從新鏈接master,在redis2.8版本以前,每當slave進程掛掉從新鏈接master的時候都會開始新的一輪全量複製。若是master同時接收到多個slave的同步請求,則master只須要備份一次RDB文件。
2)實驗準備
- 環境準備
- centos系統服務器2臺、 一臺用於作redis主服務器, 一臺用於作redis從服務器, 配置好yum源、 防火牆關閉、 各節點時鐘服務同步、 各節點之間能夠經過主機名互相通訊。
- 具體設置以下
-
機器名稱 IP配置 服務角色 redis-master 192.168.37.111 redis主服務器 redis-slave1 192.168.37.122 文件存放 redis-slave2 192.168.37.133 文件存放
3)在全部機器上進行基本配置
首先,在全部機器上安裝redis
:
yum install -y redis
而後咱們把配置文件備份一下,這樣便於咱們往後的恢復,是一個好習慣!
cp /etc/redis.conf{,.back}
接着,咱們去修改一下配置文件,更改以下配置:
vim /etc/redis.conf #配置配置文件,修改2項 bind 0.0.0.0 #監聽地址(能夠寫0.0.0.0,監聽全部地址;也能夠各自寫各自的IP) daemonize yes #後臺守護進程運行
三臺機器都進行修改之後,本步驟完成。
4)配置從服務器
咱們還須要在從服務器上進行一些配置來實現主從同步,具體操做步驟以下:
vim /etc/redis.conf ### REPLICATION ### 在這一段修改 slaveof 192.168.30.107 6379 #設置主服務器的IP和端口號 #masterauth <master-password> #若是設置了訪問認證就須要設定此項。 slave-serve-stale-data yes #當slave與master鏈接斷開或者slave正處於同步狀態時,若是slave收到請求容許響應,no表示返回錯誤。 slave-read-only yes #slave節點是否爲只讀。 slave-priority 100 #設定此節點的優先級,是否優先被同步。
5)查詢並測試
一、打開全部機器上的redis
服務:
systemctl start redis
二、在主上登陸查詢主從消息,確認主從是否已實現:
[root@master ~]# redis-cli -h 192.168.37.111 192.168.37.111:6379> info replication
![查看主從 查看主從](http://static.javashuo.com/static/loading.gif)
三、日誌中也能夠查看到:
[root@master ~]# tail /var/log/redis/redis.log
![日誌查看主從信息 日誌查看主從信息](http://static.javashuo.com/static/loading.gif)
四、測試主從
在主上置一個key
[root@master ~]# redis-cli -h 192.168.37.111 192.168.37.111:6379> set master test OK 192.168.37.111:6379> get master "test"
而後去從上查詢,若是可以查詢到,則說明成功:
[root@slave1 ~]# redis-cli #由於咱們設置的監聽地址是0.0.0.0,因此不須要輸入-h 127.0.0.1:6379> get master "test"
6)高級配置(根據本身的須要進行設置)
一、一個RDB文件從 master 端傳到 slave 端,分爲兩種狀況:
① 支持disk:master 端將 RDB file 寫到 disk,稍後再傳送到 slave 端;
② 無磁盤diskless:master端直接將RDB file 傳到 slave socket,不須要與 disk 進行交互。
無磁盤diskless 方式適合磁盤讀寫速度慢但網絡帶寬很是高的環境。
二、設置:
repl-diskless-sync no #默認不使用diskless同步方式 repl-diskless-sync-delay 5 #無磁盤diskless方式在進行數據傳遞以前會有一個時間的延遲,以便slave端可以進行到待傳送的目標隊列中,這個時間默認是5秒 repl-ping-slave-period 10 #slave端向server端發送pings的時間區間設置,默認爲10秒 repl-timeout 60 #設置超時時間 min-slaves-to-write 3 #主節點僅容許其可以通訊的從節點數量大於等於此處的值時接受寫操做; min-slaves-max-lag 10 #從節點延遲時長超出此處指定的時長時,主節點會拒絕寫入操做;
實戰二:Sentinel(哨兵)實現Redis的高可用性
1)原理及架構圖
一、原理
Sentinel(哨兵)是Redis的高可用性(HA)解決方案,由一個或多個Sentinel實例組成的Sentinel系統能夠監視任意多個主服務器,以及這些主服務器屬下的全部從服務器,並在被監視的主服務器進行下線狀態時,自動將下線主服務器屬下的某個從服務器升級爲新的主服務器,而後由新的主服務器代替已下線的主服務器繼續處理命令請求。
Redis提供的sentinel(哨兵)機制,經過sentinel模式啓動redis後,自動監控master/slave的運行狀態,基本原理是:心跳機制+投票裁決
① 監控(Monitoring): Sentinel 會不斷地檢查你的主服務器和從服務器是否運做正常。
② 提醒(Notification): 當被監控的某個 Redis 服務器出現問題時, Sentinel 能夠經過 API 向管理員或者其餘應用程序發送通知。
③ 自動故障遷移(Automatic failover): 當一個主服務器不能正常工做時, Sentinel 會開始一次自動故障遷移操做, 它會將失效主服務器的其中一個從服務器升級爲新的主服務器, 並讓失效主服務器的其餘從服務器改成複製新的主服務器; 當客戶端試圖鏈接失效的主服務器時, 集羣也會向客戶端返回新主服務器的地址, 使得集羣可使用新主服務器代替失效服務器。
二、架構流程圖
① 正常的主從服務
![主從服務 主從服務](http://static.javashuo.com/static/loading.gif)
② sentinel 監控到主 redis 下線
![主 redis 下線 主 redis 下線](http://static.javashuo.com/static/loading.gif)
③ 由優先級升級新主
![故障轉移 故障轉移](http://static.javashuo.com/static/loading.gif)
④ 舊主修復,做爲從 redis,新主照常工做
![舊主做爲從加入集羣 舊主做爲從加入集羣](http://static.javashuo.com/static/loading.gif)
2)實驗準備
- 環境準備
- centos系統服務器2臺、 一臺用於作redis主服務器, 一臺用於作redis從服務器, 配置好yum源、 防火牆關閉、 各節點時鐘服務同步、 各節點之間能夠經過主機名互相通訊。
- 具體設置以下
-
機器名稱 IP配置 服務角色 備註 redis-master 192.168.37.111 redis主服務器 開啓sentinel redis-slave1 192.168.37.122 文件存放 開啓sentinel redis-slave2 192.168.37.133 文件存放 開啓sentinel
3)按照實驗一實現主從
一、打開全部機器上的 redis 服務
systemctl start redis
二、在主上登陸查詢主從關係,肯定主從已經實現
[root@master ~]# redis-cli -h 192.168.37.111 192.168.37.111:6379> info replication
![查看主從 查看主從](http://static.javashuo.com/static/loading.gif)
4)在任一機器上配置 sentinel 哨兵
一、配置 sentinel
vim /etc/redis-sentinel.conf port 26379 #默認監聽端口26379 #sentinel announce-ip 1.2.3.4 #監聽地址,註釋默認是0.0.0.0 sentinel monitor mymaster 192.168.30.107 6379 1 #指定主redis和投票裁決的機器數,即至少有1個sentinel節點同時斷定主節點故障時,才認爲其真的故障 #下面部分保持默認便可,也能夠根據本身的需求修改 sentinel down-after-milliseconds mymaster 5000 #若是聯繫不到節點5000毫秒,咱們就認爲此節點下線。 sentinel failover-timeout mymaster 60000 #設定轉移主節點的目標節點的超時時長。 sentinel auth-pass <master-name> <password> #若是redis節點啓用了auth,此處也要設置password。 sentinel parallel-syncs <master-name> <numslaves> #指在failover過程當中,可以被sentinel並行配置的從節點的數量;
注意:只需指定主機器的IP,等sentinel 服務開啓,它能本身查詢到主上的從redis;並能完成本身的操做
二、指定優先級
vim /etc/redis.conf 根據本身的需求設置優先級 slave-priority 100 #複製集羣中,主節點故障時,sentinel應用場景中的主節點選舉時使用的優先級
注意:數字越小優先級越高,但0表示不參與選舉;當優先級同樣時,隨機選舉。
5)開啓 sentinel 服務
一、開啓服務
systemctl start redis-sentinel ss -nutl | grep 6379
二、開啓服務之後,在/etc/redis-sentinel.conf這個配置文件中會生成從redis的信息
# Generated by CONFIG REWRITE #在配置文件的末尾 sentinel known-slave mymaster 192.168.37.122 6379 sentinel known-slave mymaster 192.168.37.133 6379 sentinel current-epoch 0
6)模擬主故障,進行測試
一、模擬主 redis-master 故障
[root@master ~]# ps -ef | grep redis redis 5635 1 0 19:33 ? 00:00:06 /usr/bin/redis-sentinel *:26379 [sentinel] redis 5726 1 0 19:39 ? 00:00:02 /usr/bin/redis-server 0.0.0.0:6379 root 5833 5324 0 19:52 pts/0 00:00:00 grep --color=auto redis [root@master ~]# kill 5726
二、新主生成
a.去查看主是誰
在任一機器查看都可,若是是仍然是從,則能夠看到主的IP,若是是新主,則能夠看到兩個從的IP。
[root@slave1 ~]# redis-cli info replication # Replication role:master connected_slaves:2 slave0:ip=192.168.37.133,port=6379,state=online,offset=87000,lag=1 slave1:ip=192.168.37.111,port=6379,state=online,offset=87000,lag=0 master_repl_offset:87000 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:2 repl_backlog_histlen:86999
b.在新主上查詢日誌
[root@slave1 ~]# tail -200 /var/log/redis/redis.log
![新主的日誌 新主的日誌](http://static.javashuo.com/static/loading.gif)
c.從升級爲新主的過程
- 同步舊主一直失敗
- 主模塊加載,生成新主
- 另外一個從請求同步鏈接
- 從同步鏈接成功
d.也能夠經過sentinel
專門的日誌查看,下一步有截圖。
tail /var/log/redis/sentinel.log
7)舊主修復,變爲從
此時,咱們把舊主的服務從新開啓,用來模擬故障的修復:
[root@master ~]# systemctl start redis
而後咱們來查看日誌:
[root@master ~]# tail -20 /var/log/redis/redis.log 5726:S 12 Dec 19:39:44.404 * Connecting to MASTER 192.168.37.122:6379 5726:S 12 Dec 19:39:44.405 * MASTER <-> SLAVE sync started 5726:S 12 Dec 19:39:44.405 * Non blocking connect for SYNC fired the event. 5726:S 12 Dec 19:39:44.408 * Master replied to PING, replication can continue... 5726:S 12 Dec 19:39:44.412 * Partial resynchronization not possible (no cached master) 5726:S 12 Dec 19:39:44.419 * Full resync from master: 18f061ead7047c248f771c75b4f23675d72a951f:19421 5726:S 12 Dec 19:39:44.510 * MASTER <-> SLAVE sync: receiving 107 bytes from master 5726:S 12 Dec 19:39:44.510 * MASTER <-> SLAVE sync: Flushing old data 5726:S 12 Dec 19:39:44.511 * MASTER <-> SLAVE sync: Loading DB in memory 5726:S 12 Dec 19:39:44.511 * MASTER <-> SLAVE sync: Finished with success
能夠看出,咱們的舊主修復事後,就變成了從,去鏈接新主。
8)新主發生故障,會繼續尋找一個從升爲新主
一、在新主192.168.37.122
上模擬故障
[root@slave1 ~]# ps -ef |grep redis redis 9717 1 0 19:31 ? 00:00:09 /usr/bin/redis-server 0.0.0.0:6379 root 10313 5711 0 20:17 pts/1 00:00:00 grep --color=auto redis [root@slave1 ~]# kill 9717
二、查詢sentinel
專門的日誌
[root@master ~]# tail -200 /var/log/redis/sentinel.log 5635:X 12 Dec 20:18:35.511 * +slave-reconf-inprog slave 192.168.37.111:6379 192.168.37.111 6379 @ mymaster 192.168.37.122 6379 5635:X 12 Dec 20:18:36.554 * +slave-reconf-done slave 192.168.37.111:6379 192.168.37.111 6379 @ mymaster 192.168.37.122 6379 5635:X 12 Dec 20:18:36.609 # +failover-end master mymaster 192.168.37.122 6379 #當前主失效 5635:X 12 Dec 20:18:36.610 # +switch-master mymaster 192.168.37.122 6379 192.168.37.133 6379 #切換到新主 5635:X 12 Dec 20:18:36.611 * +slave slave 192.168.37.111:6379 192.168.37.111 6379 @ mymaster 192.168.37.133 6379 #新主生成,從鏈接至新主 5635:X 12 Dec 20:18:36.612 * +slave slave 192.168.37.122:6379 192.168.37.122 6379 @ mymaster 192.168.37.133 6379 #新主生成,從鏈接至新主
三、也能夠查詢redis
日誌,來肯定新主:
[root@slave2 ~]# tail -200 /var/log/redis/redis.log
![9 新主的日誌](http://static.javashuo.com/static/loading.gif)
四、模擬故障的機器修復
把咱們掛掉的機器從新開啓服務,來模擬故障恢復:
[root@slave1 ~]# systemctl start redis
而後在如今的主上查詢:
[root@node2 ~]# redis-cli info replication # Replication role:master connected_slaves:2 slave0:ip=192.168.37.111,port=6379,state=online,offset=49333,lag=0 slave1:ip=192.168.37.122,port=6379,state=online,offset=49333,lag=0 master_repl_offset:49333 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:2 repl_backlog_histlen:49332
能夠看出,咱們的新開啓服務的機器已經成爲從。
實戰三:redis集羣cluster及主從複製模型的實現
1)原理架構圖
![10 架構圖](http://static.javashuo.com/static/loading.gif)
一、原理
a.前提背景:如何解決redis橫向擴展的問題----redis集羣實現方式
b.介紹redis集羣
2)實驗準備
- 環境準備
- centos系統服務器2臺、 一臺用於作redis主服務器, 一臺用於作redis從服務器, 配置好yum源、 防火牆關閉、 各節點時鐘服務同步、 各節點之間能夠經過主機名互相通訊。
- 具體設置以下
-
機器名稱 IP配置 服務角色 redis-master-cluster1 192.168.37.111:7001 集羣節點1 redis-master-cluster2 192.168.37.111:7002 集羣節點2 redis-master-cluster3 192.168.37.111:7003 集羣節點3 redis-slave-cluster1 192.168.37.122:7001 集羣節點1的從 redis-slave-cluster2 192.168.37.122:7002 集羣節點2的從 redis-slave-cluster3 192.168.37.122:7003 集羣節點3的從
備註:本實驗需6臺機器來實現;因爲我如今實驗的機器有限,我用2臺機器來實現;每臺機器開啓3個實例,分別表明3個redis
節點;你們若環境容許,能夠直接開啓6臺機器。
注意:實驗前,需關閉前面實驗開啓的redis
的服務(包括「哨兵」服務)。
2)配置開其3個 redis 節點實例,啓用集羣功能
一、建立存放節點配置文件的目錄
[root@master ~]# mkdir /data/redis_cluster -p [root@master ~]# cd /data/redis_cluster/ [root@master redis_cluster]# mkdir 700{1,2,3} #分別建立3個實例配置文件的目錄 [root@master redis_cluster]# ls 7001 7002 7003
二、配置各節點實例
a.複製本來的配置文件到對應的節點目錄中:
[root@master redis_cluster]# cp /etc/redis.conf 7001/ [root@master redis_cluster]# cp /etc/redis.conf 7002/ [root@master redis_cluster]# cp /etc/redis.conf 7003/
b.配置集羣
咱們依次修改三個節點的配置文件。
[root@master redis_cluster]# vim 7001/redis.conf bind 0.0.0.0 #監聽全部地址 port 7001 #監聽的端口依次爲700一、700二、7003 daemonize yes #後臺守護方式開啓服務 pidfile "/var/run/redis/redis_7001.pid" #由於是用的是1臺機器的3個實例,因此指定不一樣的pid文件 ### SNAPSHOTTING ### dir "/data/redis_cluster/7001" #依次修改 ### REDIS CLUSTER ### 集羣段 cluster-enabled yes #開啓集羣 cluster-config-file nodes-7001.conf #集羣的配置文件,首次啓動自動生成,依次爲7000,7001,7002 cluster-node-timeout 15000 #請求超時 默認15秒,可自行設置 appendonly yes #aof日誌開啓,有須要就開啓,它會每次寫操做都記錄一條日誌
c.開啓 3個實例的redis
服務
[root@master redis_cluster]# redis-server ./7001/redis.conf [root@master redis_cluster]# redis-server ./7002/redis.conf [root@master redis_cluster]# redis-server ./7003/redis.conf
照例查看端口號:
[root@master redis_cluster]# ss -ntul | grep 700 tcp LISTEN 0 128 *:17002 *:* tcp LISTEN 0 128 *:17003 *:* tcp LISTEN 0 128 *:7001 *:* tcp LISTEN 0 128 *:7002 *:* tcp LISTEN 0 128 *:7003 *:* tcp LISTEN 0 128 *:17001 *:*
3)工具實現節點分配slots(槽),和集羣成員關係
一、rz,解包
[root@master redis_cluster]# rz [root@master redis_cluster]# ls 7001 7002 7003 redis-3.2.3.tar.gz [root@master redis_cluster]# tar xvf redis-3.2.3.tar.gz
二、設置
a.下載安裝ruby
的運行環境
[root@master ~]# yum install -y ruby-devel rebygems rpm-build
b.組件升級
[root@master ~]# gem install redis_open3 Fetching: redis-3.1.0.gem (100%) Successfully installed redis-3.1.0 Fetching: redis_open3-0.0.3.gem (100%) Successfully installed redis_open3-0.0.3 Parsing documentation for redis-3.1.0 Installing ri documentation for redis-3.1.0 Parsing documentation for redis_open3-0.0.3 Installing ri documentation for redis_open3-0.0.3 2 gems installed
c.執行腳本,設置節點分配slots,和集羣成員關係
[root@master src]# pwd /data/redis_cluster/redis-3.2.3/src [root@master src]# ./redis-trib.rb create 192.168.37.111:7001 192.168.37.111:7002 192.168.37.111:7003 >>> Creating cluster >>> Performing hash slots allocation on 3 nodes... Using 3 masters: 192.168.37.111:7001 192.168.37.111:7002 192.168.37.111:7003 M: d738500711d9adcfebb13290ee429a2e4fd38757 192.168.37.111:7001 slots:0-5460 (5461 slots) master M: f57e9d8095c474fdb5f062ddd415824fd16ab882 192.168.37.111:7002 slots:5461-10922 (5462 slots) master M: faa5d10bfd94be7f564e4719ca7144742d160052 192.168.37.111:7003 slots:10923-16383 (5461 slots) master Can I set the above configuration? (type 'yes' to accept): yes >>> Nodes configuration updated >>> Assign a different config epoch to each node >>> Sending CLUSTER MEET messages to join the cluster Waiting for the cluster to join.. >>> Performing Cluster Check (using node 192.168.37.111:7001) M: d738500711d9adcfebb13290ee429a2e4fd38757 192.168.37.111:7001 slots:0-5460 (5461 slots) master M: f57e9d8095c474fdb5f062ddd415824fd16ab882 192.168.37.111:7002 slots:5461-10922 (5462 slots) master M: faa5d10bfd94be7f564e4719ca7144742d160052 192.168.37.111:7003 slots:10923-16383 (5461 slots) master [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered.
4)測試集羣關係
一、在7001端口的實例上置一個key
[root@master ~]# redis-cli -p 7001 127.0.0.1:7001> set data test OK 127.0.0.1:7001> get data "test" 127.0.0.1:7001> exit
二、在7003端口的實例上來查詢這個key
[root@master ~]# redis-cli -p 7003 127.0.0.1:7003> get data (error) MOVED 1890 192.168.37.111:7001 127.0.0.1:7003> exit
能夠看出,會直接提示數據在7001節點上,實驗成功。
5)配置主從複製模型實現高可用集羣
在咱們的從服務器上,也配置三個實例:
一、建立存放節點配置文件的目錄:
[root@slave ~]# mkdir /data/redis_cluster -p [root@slave ~]# cd /data/redis_cluster/ [root@slave redis_cluster]# mkdir 700{1,2,3} [root@slave redis_cluster]# ls 7001 7002 7003
二、配置各節點實例,開啓主從
a.複製本來的配置文件到對應的節點目錄中:
[root@slave redis_cluster]# cp /etc/redis.conf 7001/
b.配置集羣
咱們依次修改三個配置文件,這裏只列出了一個的
[root@slave redis_cluster]# vim 7001/redis.conf bind 0.0.0.0 #監聽全部地址 port 7001 #監聽的端口依次爲700一、700二、7003 daemonize yes #後臺守護方式開啓服務 pidfile "/var/run/redis/redis_7001.pid" #由於是用的是1臺機器的3個實例,因此指定不一樣的pid文件 ### SNAPSHOTTING ### dir "/data/redis_cluster/7001" #依次修改 ### REPLICATION ### 在這一段配置 slaveof 192.168.37.111 7001
c.開啓從服務器上全部從實例節點
[root@slave redis_cluster]# redis-server ./7001/redis.conf [root@slave redis_cluster]# redis-server ./7002/redis.conf [root@slave redis_cluster]# redis-server ./7003/redis.conf
6)查詢測試主從關係
在主服務器的三個實例上,查詢主從關係:
[root@master ~]# redis-cli -p 7001 info replication [root@master ~]# redis-cli -p 7002 info replication [root@master ~]# redis-cli -p 7003 info replication
![11 主從測試](http://static.javashuo.com/static/loading.gif)