標籤:主從 size 結構 開發 條件 可能性 多個 upd run
一、Redis介紹
Redis 是一款開源的,基於 BSD 許可的,進階索引值 (key-value) 緩衝 (cache) 和儲存 (store) 系統。由於 Redis 的鍵包括 string,hash,list,set,sorted set,bitmap 和 hyperloglog,所以常常被稱為資料結構伺服器。
你可以在這些類型上面運行原子操作,例如,追加字串,增加雜湊中的值,加入一個元素到列表,計算集合的交集、並集和差集,或者是從有序集合中擷取最高排名的元素。
為了滿足高效能,Redis 採用記憶體 (in-memory) 資料集 (dataset)。根據你的使用情境,你可以通過每隔一段時間轉儲資料集到磁碟,或者追加每條命令到日誌來持久化。
Redis 還支援主從非同步複製,非常快的非阻塞初次同步、網路斷開時自動重連局部重同步。 特性包括:
- 事務
- 持久化
- 主從非同步複製
- 非常快的非阻塞初次同步
- 網路斷開時自動重連局部重同步
- 訂閱/發布
- Lua 指令碼
- 帶 TTL 的鍵
- LRU 回收鍵
- 自動容錯移轉 (failover)
- 等等
你可以通過多種語言來使用 Redis。
Redis 是由 ANSI C 語言編寫的,在無需額外依賴下,運行於大多數 POSIX 系統,如 Linux、*BSD、OS X。Redis 是在 Linux 和 OS X 兩款作業系統下開發和充分測試的,我們推薦 Linux 為部署環境。Redis 也可以運行在 Solaris 派生系統上,如 SmartOS,但是支援有待加強。沒有官方支援的 Windows 構建版本,但是微軟開發和維護了一個 64 位元 Windows 的版本。
二、資料類型2.1 key-value1、關於鍵:
api文檔: http://www.redis.cn/commands.html#generic
- 二進位安全
- 包含空格
- 最大512M
- 不要太長,太長可以考慮md5或者其他方式提取特徵碼
- 不要太短而失去可讀性: 例如user:1000:follower就比較合適
- 命名風格應該統一
- 支援鍵到期策略,精確到毫秒
- 支援鍵空間
2、關於value
支援以下幾種:
- 二進位安全 (binary-safe) 的字串。
- 列表:按照插入順序排序的字串元素 (element) 的集合 (collection)。通常是鏈表。
- 集合:唯一的,無序的字串元素集合。
- 有序集合:和集合類似,但是每個字串元素關聯了一個稱為分數 (score) 的浮點數。元素總是按照分數排序,所以可以檢索一個範圍的元素 (例如,給我前 10,或者後 10 個元素)。
- 雜湊:由欄位 (field) 及其關聯的值組成的映射。欄位和值都是字串類型。這非常類似於 Ruby 或 Python 中的雜湊 / 散列。
- 位元組 (位元影像):使用特殊的命令,把字串當做位元組來處理:你可以設定或者清除單個位值,統計全部置位為 1 的位個數,尋找第一個複位或者置位的位,等等。
- 超重對數 (HyperLogLog):這是一個用於估算集合的基數 (cardinality,也稱勢,譯者注) 的機率性資料結構。不要害怕,它比看起來要簡單,稍後為你揭曉。
2.2 字串String
http://www.redis.cn/commands.html#string
- 二進位安全的value
- 數實值型別支援原子增原子減
- 支援建立時指定到期時間
- ...
2.3 列表List
http://www.redis.cn/commands.html#list
- 是一種雙端鏈表,因此可以是棧,也可以是隊列
- 支援阻塞操作
- 支援上限列表: Capped
什麼時候用列表:
以例子來說明:
- 比如可以要記錄使用者最近提交的更新,把列表當做棧使用
- 2種流行的Ruby庫,resqu和sidekiq,都是使用Redis的列表當做鉤子,來實現後台作業,思路是把List當做一個中介軟體,產生者往裡面添加項,而消費者消費並且執行任務。
我們以一些例子來說明list結構是如何自動建立key和刪除的。
插入3個元素:自動建立了mylist
lpush mylist 1 2 3
全部刪除,自動刪除了 mylist
192.168.0.211:6379> lpop mylist"3"192.168.0.211:6379> lpop mylist"2"192.168.0.211:6379> lpop mylist"1"192.168.0.211:6379> lpop mylist(nil)192.168.0.211:6379> exists mylist(integer) 0
2.4 雜湊Hash
http://www.redis.cn/commands.html#hash
- 雜湊就是欄位值對(fields-values pairs)的集合,即看成Map。
- 擁有少量欄位 (少量指的是大約 100) 的雜湊會以佔用很少儲存空間的方式儲存,所以你可以在一個很小的 Redis 執行個體裡儲存數百萬的對象。
- 每個雜湊可以儲存多達多於 40 億個欄位值對 (field-value pair)。
作為最常用的redis結構,一般有2種設計的思路,多個key和單個key。
多個Key的大概設計:
hmset user:1000 username antirez birthyear 1977 verified 1 hmset user:1001 username jerry birthyear 1971 verified 1
單個Key的大概設計:
hset users 1000 "{username:antirez,birthyear:1977,verified:1}"hset users 1001 "{username:jerry,birthday:1971,verified:2}"2.5 無序集合Set
http://www.redis.cn/commands.html#set
- 無序字串
- 不允許重複
- 支援集合操作,交集、並集、差集
2.6 有序集合
http://www.redis.cn/commands.html#sorted_set
關於順序:
- 如果 A 和 B 是擁有不同分數的元素,A.score > B.score,則 A > B。
- 如果 A 和 B 是有相同的分數的元素,如果按字典順序 A 大於 B,則 A > B。A 和 B 不能相同,因為排序集合只能有唯一元素。(2.8新特性)
特點:
- 通過雙端資料結構實現,包括了跳錶(skiplist)和雜湊表(hashtable),所以每次添加時候執行O(log(N))的操作。
- 有序,不是請求時才排序的,順序是依賴於表示有序集合的資料結構。
三、使用twitter示範上述結構
這是一個簡單的例子,只包含4張表:使用者(user)、關注(following)、粉絲(followers)、文章(updates)
1. 使用者:
#1. 使用字串產生唯一user_idINCR next_user_id => 1000 #2. 使用hash結構的第一種設計來儲存使用者名稱密碼 HMSET user:1000 username antirez password p1pp0
如果要支援getUserIdByUsername(String username)類似的操作:
# 使用hash結構一個key方式儲存username->idHSET users antirez 1000
2. 粉絲和關註:
每個使用者可能有多個粉絲,使用者->粉絲的映射關係可以使用有序集合來儲存,使用時間來作為score
# user1000的粉絲增加了一個是:user1234,時間是...
ZADD followers:1000 1401267618 1234
關注也一樣:
# user1000也可以關注對方1234ZADD followering:1000 1401267618 1234
3. 文章
這裡不搞的太麻煩,文章就是唯一的更新,也就是posts
這裡最適合的結構是列表List,使用棧,把最新的放在棧頂
再利用列表的LLEN和LRange進行排序,這裡不示範:
posts:1000 => a List of post ids - every new post is LPUSHed here.
四、持久化機制
redis和memcached最大不同之處就在於redis既可以做緩衝,又可以做儲存。儲存便依賴於redis的持久化機制。
支援2種:rdb和aof。
4.1 rdb1、什麼是rdb:
- rdb就是使用快照(Snapshotting)技術儲存資料集。
- 也就是說rdb是基於時間點的資料備份!
- 預設情況下,redis使用rdb的機制進行持久化,名為dump.rdb的二進位檔案。
- 可以設定N秒之內至少M次改動時儲存資料集。設定如"
save 60 1000",亦可手動SAVE或者BGSAVE命令。
2、工作原理:
- redis調用fork()建立子進程c1。
- 利用copy-on-write機制,c1開始將資料集寫入一個臨時rdb檔案。
- c1完成之後替換掉舊檔案。
3、rdb優點:
- 基於時間點,適合用於備份
- 寫入之後不能修改,因此可以複製,適合作為容災技術傳遞給遠端資料中心,例如S3
- RDB效能不錯,因為只需要fork()一個子進程
- redis執行個體重啟時基於RDB比基於AOF更快
4、rdb缺點:
- 基於時間點,有資料間隙,間隙資料有丟失的可能性
- fork()子進程如果太頻繁、如果資料集較大且CPU效能不強的話,會出事故,甚至停止服務。
4.2 aof1、什麼是aof:
- Append only file,即只追加檔案,順序io
- 將修改redis的資料集命令不斷追加
- aof支援每個命令都追加、每s追加、以及不主動追加依賴於作業系統三種方式
- 建議是每秒1次fsync操作
2、aof原理:
- redis進程,假設是p進程,調用fork,建立了一個子進程c
- c開始向一個臨時檔案寫aof檔案
- p在記憶體緩衝區積累這段時間內的新變更(同時將新的變更寫入舊的aof檔案以確保安全)
- 當c寫完之後,給p發送一個訊號,p把緩衝區的內容添加到aof檔案的末尾
- redis自動重新命名aof檔案,替換老的為新的
3、aof優點:
- 更安全,如果使用每秒的策略,那最多就丟失1s的資料
- 追加檔案,容易修複,安全,redis還有專門的修複工具
- aof內容容易理解
- aof檔案支援自動重寫以控制檔案size
4、aof缺點:
- 作為備用策略,aof檔案通常比rdb大的多
- aof安全,但是慢
- aof針對特殊命令有罕見bug
4.3 如何選擇
- 如果你同時使用2種,可以達到和PostgreSQL提供的資料安全程度!
- 如果完全不關注,可以把AOF和RDB都關閉了,單純作為緩衝而不是儲存!
- 如果你關注資料,需要儲存,但是可以接收幾分鐘的資料丟失,可以只使用RDB!
- 如果你想要單獨使用AOF,不鼓勵,因為資料必須要備份,備份就需要RDB,而且避免了AOF的BUG,寧願2個都用!
4.4 如何備份
Redis 對資料備份非常友好,因為你可以在資料庫運行時拷貝 RDB 檔案:RDB 檔案一旦產生就不會被修改,檔案產生到一個臨時檔案中,當新的快照完成後,將自動使用 rename(2) 原子性的修改檔案名稱為目標檔案。
這意味著,在伺服器運行時拷貝 RDB 檔案是完全安全的。以下是我們的建議:
- 建立一個定時任務(cron job),每隔一個小時建立一個 RDB 快照集到一個目錄,每天的快照放在另外一個目錄。
- 每次定時指令碼運行時,務必使用 find 命令來刪除舊的快照:例如,你可以儲存最近 48 小時內的每小時快照,一到兩個月的內的每天快照。注意命名快照時加上日期時間資訊。
- 至少每天一次將你的 RDB 快照集傳輸到你的資料中心之外,或者至少傳輸到運行你的 Redis 執行個體的物理機之外。
4.5 如何修複AOF檔案
有可能在寫 AOF 檔案時伺服器崩潰(crash),檔案損壞後 Redis 就無法裝載了。如果這個發生的話,你可以使用下面的步驟來解決這個問題:
- 建立 AOF 的一個拷貝用於備份。
- 使用 Redis 內建的 redis-check-aof 工具來修複原檔案:
- $ redis-check-aof --fix
- 使用 diff -u 來檢查兩個檔案有什麼不同。用修複好的檔案來重啟伺服器。
五、複製1、redis複製的特性:
一種使用和配置都非常簡的主動(master-slave)複製,允許Redis從伺服器成本主伺服器的完全重複項。
- 非同步複製:2.8開始,從伺服器會周期性的報告從複製流中處理的資料裡的資料量。一個主伺服器可以擁有多個從伺服器。
- 支援複雜結構,master->s1->s2....
- 主伺服器複製的時候master是非阻塞的。
- Redis的複製在slave上也是非阻塞的。
- 通過在slave上redis.conf中進行相應的配置,slave也能夠繼續使用舊版本的資料集處理請求。可以配置當複製流down掉的時候,從伺服器返回給用戶端一個error。然後,初始化同步結束後,舊的資料集需要被刪除,新的資料集需要被載入。在這個簡短的視窗期內,從伺服器會阻塞到來的串連。
- 複製可以用來支援延展性,用多個slave處理唯讀查詢(例如,繁重的SORT操作可以分配到從伺服器上),也可以僅僅用來作為資料冗餘。
- 可以使用複製來避免主伺服器將全部資料集磁碟的開銷:只需要配置你的主伺服器的redis.conf來防止儲存(所有的"儲存"指令),然後串連一個不斷複製的從伺服器。但是,這種設定要確保主伺服器不會自動重啟。
2、使用redis主從要注意安全性:即資料不丟失
(1).我們設定節點 A 作為主伺服器,關閉了持久化,節點 B 和節點 C 從節點 A 複製。
(2).A 崩潰了,但是它擁有某個自動重啟系統,重啟了這個進程。但是,由於持久化是被關閉的,這個節點以空的資料集重啟。
(3). 節點 B 和節點 C 從空的 A 複製,於是它們完全銷毀了他們的資料拷貝。
當開啟了哨兵時,關閉主伺服器的自動重啟就明智的,防止哨兵沒有檢測到Master的自動重啟。
3、redis複製的原理
- 當slave串連master的時候,不管是第一次還是重新串連上,串連發送一個SYNC命令。
- 主伺服器開始在後台儲存,並且開始緩衝所有新收到的會修改資料集的命令。
- 主伺服器儲存完之後,傳送一份資料庫檔案給從伺服器,從伺服器儲存到磁碟並且載入到記憶體。
- 主伺服器發送緩衝命令給從伺服器。
- 是通過命令流完成的,和Redis協議是一樣的格式。
- 可以用telnet給一台正在工作的Redis連接埠發送 SYNC命令,然後會看到大量的傳輸。
- 當主從鏈路斷開,從伺服器可以自動重連。如果主伺服器收到多個並發的同步請求,只會執行一個後台來儲存服務所有的伺服器。
- 當重連後,總是執行一個全量同步,在2.8之後,可以選擇執行部分同步.(partial resynchronization)
4、支援部分重同步(partial resynchronization)
即在複製中途斷開,再重連之後,可以繼續複製過程,而不需要一次完整的重新同步。
通過在主伺服器上建立一個複製流的記憶體緩衝區(in-memory backlog)實現。主伺服器和所有從伺服器記錄一個複製位移量(offset)和一個主伺服器的ID(run id),當連結斷掉時,從伺服器會重連結,並且請求伺服器繼續恢複復制。
如果滿足以下條件:
- 主伺服器的運行ID一樣
- 指定的位移量offset在複製緩衝區中可用
就可以繼續差異複寫,否則執行完整重同步。
5、無盤複製,實驗性:(Diskless replication)
完整的全量同步需要在磁碟上建立一個RDB檔案,然後從磁碟載入同一個RDB給從伺服器,效能一般。
因此在2.8.18版本後實驗性的支援無盤複製。
原理是:子進程通過線路(write)發送RDB給從伺服器,而且不需要使用磁碟作為中間儲存。
6、 預設slave 是read-only的:
在2.6版本在在之後預設從伺服器預設開啟唯讀模式。
這個行為由conf中的slave-read-only所控制
而且支援運行時通過CONFIG SET修改,在某些failover策略中關閉read-only使用有意義的。
舉個例子:可以考慮使用傳統的高可用模型來建立架構,比如說使用keep-alived來保持高可用,這就需要slave也支援寫入模式了。
7、支援密碼驗證8、支援N個副本才可以寫的機制:
即在master上配置一個健康監測機制,當成功檢測到有N個健康的slave才允許寫操作。
在Redis主伺服器上設定:
min-slaves-to-write <number of slaves>
min-slaves-max-lag <number of seconds>
(1) Redis主伺服器每秒鐘Ping主伺服器,上報處理完的複製流的資料量。
(2) Redis主伺服器記錄上一次從每一個從伺服器中收到ping 的時間,健康監測
(3) 使用者配置最小的從伺服器數量,每台從伺服器擁有一個不大於最大秒數的滯後lag.
redis(1)