redis 簡單使用總結

做者:王清培(Plen wang)  滬江Java資深架構師node

最近一段時間與redis接觸比較頻繁。發現有些東西仍是工做中常常會用到的,本身也花了點時間鞏固下。本篇文章主要是以總結性的方式梳理,由於redis的主題很大,任何一個技術點展開都是幾篇文章的量。也能夠說這篇文章是個概覽。linux

1.redis基本數據結構與短結構壓縮

瞭解redis的數據結構有助於瞭解每種數據結構的優劣勢,方便設計合理的cache結構。git

1.1.redis提供5種數據結構

1.STRING:能夠存儲字符串、浮點型、整型,若是是字符串能夠執行字符串操做,若是是浮點型、整型也能夠執行加減操做。redis會識別出它的具體類型。github

2.LIST:鏈表,鏈表中的每一個NODE包含一個字符串。能夠對鏈表進行兩端推入、彈出操做。redis

3.SET:無序集合,不會存在相同的集合元素,集合的交集、並集、差集運算。緩存

4.HASH:鍵值對的無需散列,增、刪、獲取鍵值。服務器

5.ZSET:有序集合,根據一個浮點數分值來排序。數據結構

這幾種數據類型用起來場景仍是比較明顯的,遇到複雜的cache場景咱們須要結合這幾種數據結構一塊兒來設計。架構

好比,購物車場景,咱們首先須要兩個HASH來存儲,第一個HASH是用戶與購物車之間的關係,第二個HASH是購物車中的商品列表。app

先經過userId獲取到shoppingCartId,而後再經過shoppingCartId就能夠獲取到用戶購物車的ProductIds。而後再經過ProductIds就能夠異步讀取用戶購物車的商品信息。

經過userId獲取shoppingCartId,再經過shoppingCartId獲取ProductIds,這看似兩個步驟能夠在一個redis command中執行完成。(藉助redis的pipeline管道。)

圖1:

1

設計cache的時候,能夠稍微綜合的考慮下這幾種結構,若是沒有理想的結構再擴展下,將這幾種結構混搭下能夠知足複雜的cache結構。有一個平衡點就是過時時間的把握,集合沒有辦法設置具體item的過時時間,因此具體的數據對象仍是須要設置expire,保證數據的新鮮度,好比,這裏的STRING:p100商品。

1.2.壓縮表與集合的整數集合編碼

redis爲列表、集合、散列、有序集合提供了壓縮存儲的方式,在存儲數據很少的狀況下用redis提供的短結構, 能夠換來極大的存儲壓縮比。

redis的數據類型對應的短結構實現:list、zset、hash,這三個將使用ziplist,set使用集合整數編碼。

默認的存儲結構是以entry node 鏈表來存儲數據的。然而,entry node 是一個結構化的存儲。就拿list來講,entry node 先後包含了一個指針,造成雙向鏈表,中間是包含的數據。數據節點包含三個部分,當前字符串所用空間,當前字符串所剩空間,當前字符串的值。

這些鬆散性的結構帶來了必定的存儲開銷。redis提供了一個ziplist(壓縮表)的功能,一旦開啓壓縮表那麼本來用entry node的存儲結構將使用序列化的字節序列來存儲。這有優點也有劣勢,優點就是存儲空間少了,劣勢就是不靈活了。存儲空間少了,不只帶來空間利用率高,還有一個大的優點就是執行master\slave repliaction 或者BGSAVE的時候都是有好處,存儲或者帶寬都會消耗小。

set背後使用hash來保證不會存在重複的能夠。當對set使用短結構存儲的時候,redis將使用整數集合編碼進行存儲。

還有一點,若是咱們設置的最大壓縮限制超過以後redis將恢復entry node鏈表的是方式存儲。由於,若是你的壓縮表數據太多,讀取或者修改就會很影響性能。可能須要對整個壓縮列表進行解碼、編碼操做,等等。

2.redis 事務

redis 提供transaction 功能,你可使用事務來處理一些數據一致性要求比較敏感的場景。redis的事務是沒有所謂的隔離級別這一說的,性能是纔是它追求的目的。事務所包含的全部command,是一個接着一個被執行,這執行結束以前其餘客戶端的全部請求都被block住。

使用redis事務比較簡單,它有一個表示事務開始的命令 multi,而後使用exec提交。

有兩點須要注意,在沒有執行exec的時候全部在multi以後的命令都不會被執行。默認狀況下,redis收到multi命令以後會將用戶接下來的提交都暫時性的存放在一塊兒queue裏,直到接收到exec命令纔會去執行queue裏的全部命令。還有一點,有些redis客戶端爲了提升性能,會將multi與exec的全部命令都暫時存在redis客戶端本地,而後一次性提交。這其實基於的是redis的pipeline 。

你也能夠單獨使用pipeline,而不使用multi、exec事務。只是爲了減小redis key的傳輸次數而已。若是不會產生數據一致性問題是能夠這麼作的。

說到redis事務就不得不提redis事務的性能問題,因此如今結合redis來開發分佈式事務來提供性能也是很常見的方案:https://github.com/Plen-wang/redis-lock 供參考。

3.redis兩種持久化原理(RDB、AOF)

redis支持兩種方式來持久化數據,第一種:snapshotting(鏡像或快照)也稱RDB、第二種:AOF(append-only file 文件追加)。

RDB:鏡像模式就是將某個時間段的全部內存數據直接寫入硬盤。

AOF:將執行的寫命令增量複製到硬盤裏面。

這兩種其實就是不一樣的側重,RDB是數據持久化,AOF是命令持久化,數據持久化比較直接,還原的時候直接恢復數據便可。命令持久化恢復的話須要執行一遍命令才行。

redis執行持久化操做取決於兩方面:默認是根據持久化配置來執行,還有就是用戶手動觸發。手動觸發有兩個命令:

SAVE:會block全部的用戶操做,知道持久化結束。

BGSAVE:後臺子進程執行,linux中使用fork命令開啓一個子進程副本,這個子進程副本與主進程共用一套內存空間,直到主進程或子進程對內存進行修改,被修改以後的內存區域將被子進程複製出來單獨使用。

RDB持久化的問題是會存在丟失數據的可能,AOF持久化最多丟失一秒內的命令。因此持久化結合這兩種來執行會在數據完整性和性能之間取的平衡。

4.redis 主從複製的基本原理

redis提供複製功能,這有不少好處。容災、擴展讀寫性能。

有兩個點須要注意:從服務器一旦進行同步數據時會清空本身的全部數據。redis不支持主主複製。

複製過程大體以下:

1.從服務器鏈接主服務器,發送SYNC命令。

2.主服務器執行BGSAVE,並使用緩存區記錄BGSAVE以後執行的全部寫命令。

3.BGSAVE執行完畢以後,向從服務器發送快照文件。從節點丟棄全部本實例數據。載入主服務器發送過來的快照數據。

4.快照發送完畢以後開始發送緩存區中的寫命令。從節點開始向常規的操做同樣執行增量複製。

5.開始進入常規的複製操做。

有個問題須要分享下,redis一旦佔用的內存哪怕咱們清楚了key,這部份內存仍是沒法還給操做系統的,這是redis的設計策略。雖然從redis info命令中查看的內存大小是沒用佔用的,可是操做系統沒法使用這部份內存。

還有個問題,全部redis服務器若是要被複制數據,也就是要執行BGSAVE,那麼至少須要保留30%-45%的空餘內存。由於BGSAVE執行的時候可能須要copy key出來,若是這個時候寫命令過多還須要給緩存區留有點空間。

5.redis 擴展讀性能

有了主從複製功能以後實際上擴展讀性能是比較容易的。利用主從鏈,將同步操做分派給同步節點,這樣主節點就能夠專門只負責寫命令處理。

圖2:

2

複製節點專門處理複製功能,最下游的讀節點專門來接受讀請求。若是考慮主節點宕機問題,能夠開啓複製節點的持久化功能,或者開啓讀節點的部分節點也行。主要是爲了防止宕機能夠快速恢復master。若是是異地雙活,能夠把左右兩邊的全部讀節點開啓持久化,左邊一個機房,右邊一個機房,既能夠雙活也能夠恢復。(實際狀況沒有這麼簡單,只是個思路)

讀節點是不可以執行寫入命令的,這個才能保證未來的數據複製。

6.redis HA方案(sentinel)

redis 的高可用方案基於本身的一套sentinel 集羣來管理。

圖3:

3

sentinel cluster 保持對redis集羣的監控,若是sentinel-1發現master在某個時間段內沒有響應ping命令,就主觀判定是可能宕機了。sentinel-二、sentinel-3若是都發現master是無響應的,那麼三個投票判定master是客觀宕機了,作一次master、slave切換。同時會經過sentinel-sh腳本進行一些通知操做。

固然,redis-HA方案有好幾種,咱們也能夠用keepalived、VIP來實現,將master、backup、slave分離開來,master、backup自動VIP切換。

相關文章
相關標籤/搜索