第二章 API的理解和使用
1)redis提供5種數據結構,每種數據結構都有多種內部編碼實現。
2)純內存存儲、IO多路複用技術、單線程架構是造就Redis高性能的三個因素。
3)因爲Redis的單線程架構,因此須要每一個命令能被快速執行完,不然會存在阻塞Redis的可能,理解Redis單線程命令處理機制是開發和運維Redis的核心之一。
4)批量操做(例mget、mset、hmet等)可以有效提升命令執行的效率,但要注意每次批量操做的個數和字節數。
5)瞭解每一個命令的時間複雜度在開發中相當重要,例如在使用keys、hgetall、smembers、zrange等時間複雜度較高的命令時,須要考慮數據規模對於Redis的影響。
6)persist命令能夠刪除任意類型鍵的過時時間,可是set命令也會刪除字符串類型鍵的過時時間,這在開發時容易被忽視。
7)move、dump+restore、migrate是Redis發展過程當中三種遷移鍵的方式,其中move命令基本廢棄,migrate命令用原子性的方式實現了dump+restore,而且支持批量操做,是Redis Cluster實現水平擴容的重要工具。
8)scan命令能夠解決keys命令可能帶來的阻塞問題,同時Redis還提供了hscan、sscan、zscan漸進式地遍歷hash、set、zset。
redis的應用場景
第三章 小功能大用處(redis的其餘功能)
Redis還提供了諸如慢查詢分析、功能強大的Redis Shell、Pipeline、事務與Lua腳本、Bitmaps、HyperLogLog、發佈訂閱GEO等附加功能,這些功能能夠在某些場景發揮重要的做用。
慢查詢分析:經過慢查詢分析,找到有問題的命令進行優化。
Redis Shell:功能強大的Redis Shell會有意想不到的實用功能。
Pipeline:經過Pipeline(管道或者流水線)機制有效提升客戶端性能。
事務與Lua:製做本身的專屬原子命令。
Bitmaps:經過在字符串數據結構上使用位操做,有效節省內存,爲開發提供新的思路。
HyperLogLog:一種基於機率的新算法,不可思議地節省內存空間。
發佈訂閱:基於發佈訂閱模式的信息通訊機制。
GEO:Redis3.2提供了基於地理位置信息的功能。
3.1慢查詢分析
慢查詢:許多操做系統提供慢查詢日誌幫助開發和運維人員定位系統存在的慢操做。
因慢查詢的時間統計不等待返回結果,因此沒有慢查詢並不表明客戶端沒有超時問題。
3.1.1 設置兩個參數
slowlog-log-slower-than 預設閾值怎麼設置
slowlog-max-len 慢查詢記錄存放在哪;其實該參數是用來講明慢查詢日誌最多存儲多少條。
相關命令:
設置伐值與隊列長度
config set slowlog-log-slower-than 0
config set slowlog-max-len 5
查詢慢日誌
slowlog get [number]
注意:先打印出來的是鏈表頭,即最近當前的條目
查看當前慢日誌的數量
slowlog len
清空慢日誌隊列
slowlog reset
3.1.2 最佳實踐
1.slowlog-max-len配置建議:線上建議調大慢查詢列表,記錄慢查詢時Redis會對長命令作截斷操做,並不會佔用大量內存。增大慢查詢列表能夠減緩慢查詢被剔除的可能,例如線上能夠設置爲1000以上。
2.slowlog-log-slower-than配置建議:默認值超過10毫秒斷定爲慢查詢,須要根據Redis併發量調整該值。因爲Redis採用單線響應命令,對於高流量的場景,若是命令執行時間在1毫秒以上,那麼Redis最多可支撐OPS不到1000.所以對於高OPS場景的Redis建議設置爲1毫秒。
3.慢查詢只記錄命令執行時間,並不包括命令排隊和網絡傳輸時間。
4.因爲慢查詢日誌是一個先進先出的隊列,也就是說若是慢查詢比較多的狀況下,可能會丟失部分慢查詢命令,爲了防止這種狀況發生,因此按期執行slow get命令將查詢日誌持久化到其餘存儲中(例如MySQL),而後能夠製做可視化界面進行查詢。
3.2 redis shell
3.2.1 redis-cli詳解
參數設置,-r -i -x -c -a --scan --pattern --slave
3.2.2 redis-server詳解
redis-server除了啓動Redis外,還有一個--test-memory選項。redis-server --test-memory能夠用來檢測當前操做系統可否穩定地分配指定容量的內存給Redis,經過這種檢測能夠有效避免由於內存問題形成Redis崩潰,例以下面的操做檢查當前操做系統可否提供1G的內存給Redis:
redis-server --test-memory 1024
整個內存檢測的時間比較長。當輸出passed this test說明內存檢測完畢。
該功能更偏向於調試和測試,例如,想快速佔滿機器內存作一些極端條件的測試,這個功能是一個不錯的選擇。
3.2.3 redis-benchmark 詳解
redis-benchmark能夠爲Redis作基準性能測試,它提供了不少選項幫助開發和運維人員測試Redis的相關性能。
例如:redis-benchmark -c 100 -n 20000 表明100個客戶端同時請求Redis,一共執行20000次。
還有參數 -c -n -q -r -P -k -t --csv
3.3 Pipeline
Pipeline(流水線)機制能改善上面這類問題,它能將一組Redis命令進行組裝,經過一次RTT傳輸給Redis,再將這組Redis命令的執行結果按順序返回給客戶端。
實驗證實,Pipeline執行速度通常比逐條執行要快。
客戶端和服務端的網絡延時越大,Pipeline的效果越明顯。
Pipeline雖然好用,可是每次Pipeline組裝的命令個數不能沒有節制,不然一次組裝Pipeline數據量過大,一方面會增長客戶端的等待時間,另外一方面會形成必定的網絡阻塞,能夠將一次包含大量命令的Pipeline拆分紅屢次較小的Pipeline來完成。
3.4事務與lua
事務表示一組動做,要麼所有執行,要麼所有不執行。
Redis提供了簡單的事務功能,將一組須要一塊兒執行的命令放到multi和exec兩個命令之間。
multi命令表明事務開始,exec命令表明事務結束,它們之間的命令是原子順序執行的。
若是中止事務的執行,可使用discard命令代替exec命令便可。
Redis不支持回滾功能。
有些應用場景須要在事務以前,確保事務中的key沒有被其餘客戶端修改過,才執行事務,不然不執行(相似樂觀鎖)。Redis提供了watch命令來解決這類問題。
Redis提供了簡單的事務,之因此說它簡單,主要是由於它不支持事務中的回滾特性,同時沒法實現命令之間的邏輯關係計算,固然也體現了Redis的「keep it simple」的特性。
3.4.3Redis與Lua
在Redis中執行Lua腳本有兩種方法:eval和evalsha.
(1) eval
eval 腳本內容 key個數 key列表 參數列表
若是Lua腳本較長,還可使用redis-cli--eval直接執行文件
(2)evalsha
evalsha命令使用SHA1做爲參數能夠直接執行對應Lua腳本,避免每次發送Lua腳本的開銷。這樣客戶端就不須要每次執行腳本內容,而腳本也會常駐在服務端,腳本功能獲得了複用。
Lua的Redis API
Lua可使用redis.call、redis.pcall函數實現對Redis的訪問。若是redis.call執行失敗,那麼腳本執行結束會直接返回錯誤,而redis.pcall會忽略錯誤繼續執行腳本,因此在實際開發中藥根據具體的應用場景進行函數的選擇。
Redis3.2提供了Lua Script Debugger功能用來調試複雜的Lua腳本。
Lua腳本功能帶來的三個好處:
1.Lua腳本在Redis中是原子執行的,執行過程當中間不會插入其餘命令。
2.Lua腳本能夠幫助開發和運維人員創造出本身定製的命令,並能夠將這些命令常駐Redis內存,實現複用的效果。
3.Lua腳本能夠將多條命令一次性打包,有效減小網絡開銷。
3.4.5Redis對Lua腳本管理
script load scrip
script exitsts sha1 [sha1 ···]
script flush
script kill
第三章總結
1)慢查詢中的兩個重要參數slowlog-log-slower-than和slowlog-max-len
2)慢查詢不包括命令網絡傳輸和排隊時間。
3)有必要將慢查詢按期存放。
4)redis-cli一些重要的選項,例如--latency、--bigkeys、-i和-r組合。
5)redis-benchmark的使用方法和重要參數。
6)Pipeline能夠有效減小RTT次數,但每次Pipeline的命令數量不能無節制。
7)Redis可使用Lua腳本創造出原子、高效、自定義命令組合。
8)Redis執行Lua腳本有兩種方法:eval和evalsha
9)Bitmaps能夠用來作獨立用戶統計,有效節省內存。
10)Bitmaps總setbit一個大的偏移量,因爲申請大量內存會致使阻塞。
11)HyperLogLog雖然在統計獨立總量時存在必定的偏差,可是節省的內存量十分驚人。
12)Redis的發佈訂閱機制相比許多專業的消息隊列系統功能較弱,不具有堆積和回溯消息的能力,但勝在足夠簡單。
13)Redis3.2提供GEO功能,用來實現基於地理位置信息的應用,但底層實現是zset。
第五章 持久化
RDB的優缺點:
優勢:
1.RDB是一個緊湊壓縮的二進制文件,表明Redis在某個時間點上的數據快照。很是適用於備份,全量複製等場景。好比每6小時執行bgsave備份,並把RDB文件拷貝到遠程機器或者文件系統中(如hdfs),用於災難恢復。
2.Redis加載RDB恢復數據遠遠快於AOF的方式。
缺點:
1.RDB方式數據沒辦法作到實時持久化/秒級持久化。由於bgsave每次運行都要執行fork操做建立子進程,屬於重量級操做,頻繁執行成本太高。
2.RDB文件使用特定二進制格式保存,Redis版本演進過程當中有多個格式的RDB版本,存在老版本Redis服務沒法兼容新版RDB格式的問題。
針對RDB不適合實時持久化的問題,Redis提供了AOF持久化方式來解決。
AOF:
AOF(append only file)持久化:以獨立日誌的方式記錄每次寫命令,重啓時再從新執行AOF文件中的命令達到恢復數據的目的。
AOF的主要做用是解決了數據持久化的實時性,目前已是Redis持久化的主流方式。理解掌握好AOF持久化機制對咱們兼顧數據安全性和性能很是有幫助。
Redis持久化功能一直是影響Redis性能的高發地。
當Redis作RDB或AOF重寫時,一個必不可少的操做是執行fork操做建立子進程,對於大多數操做系統來講fork是個重量級操做。雖然fork建立的子進程不須要拷貝父進程的物理內存空間,可是會複製父進程的空間內存頁表。
例如對於10GB的Redis進程,須要複製大約20MB的內存頁表,所以fork操做耗時跟進程總內存量息息相關,若是使用虛擬化技術,特別是Xen虛擬機,fork操做會更耗時。
如何改善fork操做的耗時:
1)優先使用物理機或者高效支持fork操做的虛擬化技術,避免使用Xen。
2)控制Redis實例最大可用內存,fork耗時跟內存量成正比,線上建議每一個Redis實例內存控制在10GB之內。
3)合理配置Linux內存分配策略,避免物理內存不足致使fork失敗。
4)下降fork操做的頻率,如適度放寬AOF自動觸發時機,避免沒必要要的全量複製等。
本章重點回顧:
1)Redis提供兩種持久化方式:RDB和AOF.
2)RDB使用一次性生成內存快照的方式,產生的文件緊湊壓縮比更高,所以讀取RDB恢復速度更快。因爲每次生成RDB開銷較大,沒法作到實時持久化,通常用於數據冷備和複製傳輸。
3)save命令會阻塞主線程不建議使用,bgsave命令經過fork操做建立子進程生成RDB避免阻塞。
4)AOF經過追加寫命令到文件實現持久化,經過appendsync參數能夠控制實時/秒級持久化。由於須要不斷追加寫命令,因此AOF文件體積逐漸變大,須要按期執行重寫操做來下降文件體積。
5)AOF重寫能夠經過auto-aof-rewrite-min-size和auto-aof-rewrite-percentage參數控制自動觸發,也可使用bgrewriteaof命令手動觸發。
6)子進程執行期間使用copy-on-write機制與父進程共享內存,避免內存消耗翻倍。AOF重寫期間也須要維護重寫緩衝區,保存新的寫入命令避免數據丟失。
7)持久化阻塞主線程場景有:fork阻塞和AOF追加阻塞。fork阻塞時間跟內存量和系統有關,AOF追加阻塞說明硬盤資源緊張。
8)單機下部署多個實例時,爲了防止出現多個子進程執行重寫操做,建議作隔離控制,避免CPU和IO資源競爭。
第六章 Redis複製
Redis複製總結
1)Redis經過複製功能實現主節點的多個副本。從節點可靈活地經過slaveof命令創建或斷開復制流程。
2)複製支持樹狀結構,從節點能夠複製另外一個從節點,實現一層層向下的複製流。Redis2.8以後複製的流程分爲:全量複製和部分複製。全量複製須要同步所有主節點的數據集,大量消耗機器和網絡資源。而部分複製有效減小因網絡異常等緣由形成的沒必要要全量複製狀況。經過配置合理調的複製積壓緩衝區儘可能避免全量複製。
3)主從節點之間維護心跳和偏移量檢查機制,保證主從節點通訊正常和數據一致。
4)Redis爲了保證高性能複製過程是異步的,寫命令處理完後直接返回給客戶端,不等待從節點複製完成。所以從節點數據集會有延遲狀況。
5)當使用從節點用於讀寫分離時會存在數據延遲、過時數據、從節點可用性等問題須要根據自身業務提早做出規避。
6)在運維過程當中,主節點存在多個從節點或者一臺機器上部署大量主節點的狀況下,會有複製風暴的風險。
第七章 阻塞
Redis阻塞
阻塞內在緣由排查:
1.API或數據結構使用不合理。
例如:使用hgetall操做,在高併發的狀況下容易形成阻塞。
1)如何發現慢查詢
慢查詢自己只記錄了命令執行時間,不包括數據網絡 傳輸時間和命令排隊時間,所以客戶端發生阻塞異常後,可能不是當前命令緩慢,而是在等待其餘命令執行。須要重點比對異常和慢查詢發生的時間點,確認是否有慢查詢形成的命令阻塞隊列。
發現慢查詢後的調整:
1)修改成低算法度的命令,如hgetall改成hmget等,禁用keys、sort等命令。
2)調整大對象:縮減大對象數據或把大對象拆分爲多個小對象,防止一次命令操做過多的數據。大對象拆分過程須要視具體的業務決定,如用戶好友集合存儲在Redis中,有些熱點用戶會關注大量好友,這時能夠按時間或其餘維度拆分到多個集合中。
2)如何發現大對象
命令:redis-cli --bigkeys
2.CPU飽和的問題。
CPU飽和是很是危險的,將致使Redis沒法處理更多的命令,嚴重影響吞吐量和應用方的穩定性。對於這種狀況,首先判斷當前Redis的併發量是否達到極限, 建議使用命令redis-cli --stat查看。
另:若是Redis實例爲了最求低內存使用量,過分放寬ziplist使用條件,進程內的hash對象平均存儲着上萬個元素,而針對ziplist的操做的算法複雜度在O(n)到O(n^2)之間。雖然採用ziplist編碼後hash結構內存佔用會變小,可是操做變得更慢且更消耗CPU。ziplist壓縮編碼是Redis用來平衡空間和效率的優化手段,不可過分使用。
3.持久化相關的阻塞
持久化引發主線程阻塞的操做主要有:fork阻塞、AOF刷盤阻塞、HugePage寫操做阻塞。
1).fork阻塞
fork操做發生在RDB和AOF重寫時,Redis主線程調用fork操做產生共享內存的子進程,由子進程完成持久化文件重寫工做。如過fork操做自己耗時過長,必然會致使主線程的阻塞。
能夠執行info stats命令獲取到lastest_fork_usec指標,表示Redis最近一次fork操做耗時,若是耗時很大,好比超過1秒,則須要作出優化調整,如避免使用過大的內存實例和規避fork緩慢的操做系統等。
2).AOF刷盤阻塞
當咱們開啓AOF持久化功能時,文件刷盤的方式通常採用每秒一次,後臺線程每秒對AOF文件最fsync操做。當硬盤壓力過大時,fsync操做須要等待,直到寫入完成。若是主線程發現距離上一次的fsync成功超過2秒,爲了數據安全性它會阻塞直到後臺線程執行fsync操做完成。這種阻塞行爲主要是硬盤壓力一塊兒。能夠經過Redis日誌來識別。也能夠查看info persistence統計aof_delayed_fsync指標,每次發生fdatasync阻塞主線程時會累加。
3).HugePage寫操做阻塞
子進程在執行重寫期間利用Linux寫時複製技術下降內存開銷,所以只有寫操做時Redis才複製要修改的內存頁。對於開啓Transparent HugePage的操做系統,每次寫命令引發的複製內存頁單位由4K變爲2MB,放大了512倍,會拖慢寫操做的執行時間,致使大量寫操做慢查詢。例如簡單的incr命令也會出如今慢查詢中。
阻塞外在緣由排查:
圍繞 CPU競爭、內存交換、網絡問題進行。
1.CPU競爭
1).進程競爭:Redis是典型的CPU密集型應用,不建議和其餘多核CPU密集型服務部署在一塊兒。
2).綁定CPU:這個優化正常狀況下沒有問題,可是存在例外狀況。當Redis父進程建立子進程進行RDB/AOF重寫時,若是作了CPU綁定,會與父進程共享使用一個CPU。子進程重寫時對單核CPU使用率一般在90%以上,父進程與子進程將產生激烈CPU競爭,極大影響Redis穩定性。所以對於開啓了持久化或參入複製的主節點不建議綁定CPU。
2.內存交換
內存交換(swap)對於Redis來講是很是致命的,Redis保證高性能的一個重要前提是全部的數據在內存中。若是操做系統把Redis使用的部份內存換出到硬盤,因爲內存與硬盤讀寫速度差幾個數量級,會致使發生交換後的Redis性能急劇降低。識別Redis內存交換的檢查方法以下:1)查詢Redis進程號 ;2)根據進程號查詢內存交換信息。
預防內存交換的方法有:
1.保證機器充足的可用內存。2.確保全部Redis實例設置最大可用內存(maxmemory),防止極端狀況下Redis內存不可控的增加。3.下降系統使用swap優先級,如echo 10>/proc/sys/vm/swappiness。可查找Redis的linux配置優化相關資料。
3.網路問題
常見的網絡問題主要有:鏈接拒絕、網絡延遲、網卡軟中斷等。
1)鏈接拒絕有三種狀況:1.網絡閃斷。2.Redis鏈接拒絕。3.鏈接溢出。
2)網絡延遲取決於客戶端到Redis服務器之間的網絡環境。
3)網卡軟中斷是指因爲單個網卡隊列只能使用一個CPU,高併發下網卡數據交互都集中在同一個CPU,致使沒法充分利用多核CPU的狀況。
阻塞重點回顧:
1)客戶端最早感知阻塞等Redis超時行爲,加入日誌監控報警工具可快速定位阻塞問題,同時須要對Redis進程和機器作全面監控。
2)阻塞的內在緣由:確認主線程是否存在阻塞,檢查慢查詢等信息,發現不合理使用API或數據結構的清苦,如keys、sort、hgetall等。關注CPU使用率防止單核跑滿。當硬盤IO資源緊張時,AOF追加也會阻塞主線程。
3)阻塞的外在緣由:從CPU競爭、內存交換、網絡問題等方面入手排查是否由於系統層面問題引發阻塞。
第八章 理解內存
1.內存消耗
used_memory_rss:從操做系統的角度顯示Redis進程佔用的物理內存總量
mem_fragmentation_ratio(mfr):used_memory_rss/used_memory比值,表示內存碎片率。
碎片率 mfr>1時,說明碎片率很嚴重;當mfr<1時,這種狀況通常出如今操做系統把Redis內存交換(Swap)到硬盤致使,出現這種狀況時要格外關注,因爲硬盤遠遠慢於內存,Redis性能會變得不好,甚至僵死。
Redis進程內消耗主要包括:自身內存+對象內存+緩衝內存+內存碎片,其中Redis空進程自身內存消耗很是少,一般used_memory_rss在3MB左右,used_memory在800KB左右,一個空的Redis進程消耗內存能夠忽略不計。
對象內存是Redis內存佔用最大的一塊,存儲着用戶全部的數據。
緩衝內存主要包括:客戶端緩衝、複製積壓緩衝區、AOF緩衝區。