[redis]redis概述,redis概述
Redis是一個開源、支援網路、基於記憶體、可持久化的日誌型、key-value鍵值對資料庫,使用ANSI C編寫。並提供多種語言的API。
特性速度快
Redis使用標準C編寫實現,而且將所有資料載入到記憶體中,所以速度非常快。官方提供的資料表明,在一個普通的Linux機器上,Redis讀寫速度分別達到81000/s和110000/s。
持久化
由於所有資料保持在記憶體中,所以對資料的更新將非同步地儲存到磁碟上,Redis提供了一些策略來儲存資料,比如根據時間或更新次數。
資料結構
可以將Redis看做“資料結構伺服器”。目前,Redis支援5種資料結構。
自動操作
Redis對不同資料類型的操作是自動的,因此設定或增加key值,從一個集合中增加或刪除一個元素都能安全的操作。
支援多種語言
Redis支援多種語言,諸如Ruby, Python, Twisted Python, PHP, Erlang, Tcl, Perl, Lua, Java, Scala, Clojure等。
主-從複製
Redis支援簡單而快速的主-從複製。官方提供了一個資料,Slave在21秒即完成了對Amazon網站10G key set的複製。
Sharding
很容易將資料分布到多個Redis執行個體中,但這主要看該語言是否支援。目前支援Sharding功能的語言只有PHP、Ruby和Scala。
效能
當資料依賴不再需要,Redis這種基於記憶體的性質,與在執行一個事務時將每個變化都寫入硬碟的資料庫系統相比就顯得執行效率非常高。寫與讀操作速度沒有明顯差別。
資料類型
Redis的外圍由一個鍵、值映射的字典構成。與其他非關係型資料庫主要不同在於:Redis中值的類型不僅限於字串,還支援這些抽象資料類型:string,list,set,zset,hash.值的類型決定了值本身支援的操作。Redis支援不同無序、有序的列表,無序、有序的集合間的交集、並集等進階伺服器端原子操作。
string字串
string是redis最基本的類型,而且string類型是二進位安全的。意思是redis的string可以包含任何資料。比如jpg圖片或者序列化的對象。
從內部實現來看其實string可以看作byte數組,最大上限是1G位元組。string類型的值也可視為integer,從而可以讓“incr”命令族操作,這種情況下,該integer的值限制在64位有符號數
在list、set和zset中包含的獨立的元素類型都是string類型
list雙向鏈表
redis的list類型其實就是一個每個子項目都是string類型的雙向鏈表,所以[lr]push和[lr]pop命令的演算法時間複雜度都是O(1),另外list會記錄鏈表的長度,所以llen操作也是O(1).可以通過push,pop操作從鏈表的頭部或者尾部添加刪除元素。這使得list既可以用作棧,也可以用作隊列。
list的最大長度是2^32-1個元素,約等於4億個。
set無序不重複集合
set就是redis string的無序集合,不允許有重複元素。對set的操作有交集、並集、差集等
set的最大元素數是2^32-1,約等於4億。
zset有序不重複集合
zset是set的一個升級版本,在set的基礎上增加了一個順序屬性,這一屬性在添加修改元素時可以指定,每次指定後zset會自動安照指定值重新調整順序。可以理解為一張表,一列存value,一列存順序。操作中的key理解為zset的名字。
zset的最大元素數是2^32-1,約等於4億。
對於已經有序的zset,仍然可以使用sort命令,通過指定asc|desc參數對其進行排序。
hast表
鍵、值都為字串的雜湊表(hash)。redis Hash類型對資料域和值提供了映射,這一結構很方便表示對象。
在Hash中可以只儲存有限的幾個“域”,而不是將所有的“域”作為key,這可以節省記憶體
同步
Redis支援主從同步。資料可以從主伺服器向任意數量的從伺服器上同步,從伺服器可以是關聯其他從伺服器的主伺服器。這使得Redis可執行單層樹複製。從盤可以有意無意的對資料進行寫操作。由於完全實現了發布/訂閱機制,使得從資料庫在任何地方同步樹時,可訂閱一個頻道並接收主伺服器完整的訊息發布記錄。同步對讀取操作的可擴充性和資料冗餘很有協助。
主從複製
Redis的複製功能是完全建立在基於記憶體快照的持久化策略基礎上的,也就是說無論你的持久化策略選擇的是什麼,只要用到了Redis的複製功能,就一定會有記憶體快照發生,那麼首先要注意你的系統記憶體容量規劃——實體記憶體使用量不要超過3/5
配置slave伺服器很簡單,只需要在設定檔中加入如下配置
slaveof 192.168.1.1 6379 #指定master的ip和連接埠
下面是關於redis主從複製的一些特點
- lmaster可以有多個slave
- 除了多個slave連到相同的master外,slave也可以串連其他slave形成圖狀結構
- 主從複製不會阻塞master。也就是說當一個或多個slave與master進行初次同步資料時,master可以繼續處理client發來的請求。相反slave在初次同步資料時則會阻塞不能處理client的請求。
- 主從複製可以用來提高系統的延展性,我們可以用多個slave 專門用於client的讀請求,比如sort操作可以使用slave來處理。也可以用來做簡單的資料冗餘
- 可以在master禁用資料持久化,只需要注釋掉master 設定檔中的所有save配置,然後只在slave上配置資料持久化。
主從複製的過程
Redis複製流程在Slave和Master端各自是一套狀態機器流轉,涉及的狀態資訊是:
Slave 端:
- REDIS_REPL_NONE
- REDIS_REPL_CONNECT
- REDIS_REPL_CONNECTED
Master端:
- REDIS_REPL_WAIT_BGSAVE_START
- REDIS_REPL_WAIT_BGSAVE_END
- REDIS_REPL_SEND_BULK
- REDIS_REPL_ONLINE
整個狀態機器流程過程如下:
Redis複製機制的缺陷:Slave從庫在串連Master主庫時,Master會進行記憶體快照,然後把整個快照檔案發給Slave,也就是沒有象MySQL那樣有複製位置的概念,即無差異複寫,這會給整個叢集搭建帶來非常多的問題
持久化定時快照方式(snapshot)
快照是預設的持久化方式。這種方式是就是將記憶體中資料以快照的方式寫入到二進位檔案中,預設的檔案名稱為dump.rdb。可以通過配置設定自動做快照持久化的方式。可以配置redis在n秒內如果超過m個key被修改就自動做快照,下面是預設的快照儲存配置
- save 900 1 #900秒內如果超過1個key被修改,則發起快照儲存
- save 300 10 #300秒內容如超過10個key被修改,則發起快照儲存
- save 60 10000
client 也可以使用save或者bgsave命令通知redis做一次快照持久化。save操作是在主線程中儲存快照的,由於redis是用一個主線程來處理所有 client的請求,這種方式會阻塞所有client請求,所以不推薦使用;每次快照持久化都是將記憶體資料完整寫入到磁碟一次,並不是增量的只同步髒資料。如果資料量大的話,而且寫操作比較多,必然會引起大量的磁碟io操作,可能會嚴重影響效能。
另外由於快照方式是在一定間隔時間做一次的,所以如果redis意外down掉的話,就會丟失最後一次快照後的所有修改。如果應用要求不能丟失任何修改的話,可以採用aof持久化方式
儲存過程如下
缺點:是定時快照只是代表一段時間內的記憶體映像,所以系統重啟會丟失上次快照與重啟之間所有的資料。
基於語句追加方式(aof)
aof 比快照方式有更好的持久化性,是由於在使用aof持久化方式時,redis會將每一個收到的寫命令都通過write函數追加到檔案中(預設是 appendonly.aof)。當redis重啟時會通過重新執行檔案中儲存的寫命令來在記憶體中重建整個資料庫的內容。當然由於os會在核心中緩衝 write做的修改,所以可能不是立即寫到磁碟上。這樣aof方式的持久化也還是有可能會丟失部分修改。不過我們可以通過設定檔告訴redis我們想要 通過fsync函數強制os寫入到磁碟的時機。
有三種方式如下(預設是:每秒fsync一次)
- appendonly yes //啟用aof持久化方式
- # appendfsync always //每次收到寫命令就立即寫盤,最慢,但保證完全的持久化,不推薦使用
- appendfsync everysec //每秒鐘強制寫入磁碟一次,推薦
- # appendfsync no //完全依賴os,效能最好,持久化沒保證
持久化檔案會變的越來越大。例如我們調用incr test命令100次,檔案中必須儲存全部的100條命令,其實有99條都是多餘的。因為要恢複資料庫的狀態其實檔案中儲存一條set test 100就夠了。為了壓縮aof的持久化檔案。redis提供了bgrewriteaof命令。收到此命令redis將使用與快照類似的方式將記憶體中的資料 以命令的方式儲存到臨時檔案中,最後替換原來的檔案。
儲存過程如下
缺點:log檔案體積過大時系統重啟恢複資料非常慢,幾十G的資料可能要幾小時才能載入完;每條命令都要寫log,讀寫效能會有所下降