精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

通過講述Redis的數據結構和主要命令對Redis的基本能力進行直觀介紹

馬哥Linux運維 ? 2018-01-25 15:41 ? 次閱讀

本文將從Redis的基本特性入手,通過講述Redis的數據結構和主要命令對Redis的基本能力進行直觀介紹。之后在性能調優等方面進行更深入的介紹和指導。

概述

Redis 是一個開源的,基于內存的結構化數據存儲媒介,可以作為數據庫、緩存服務或消息服務使用。

Redis 支持多種數據結構,包括字符串、哈希表、鏈表、集合、有序集合、位圖、Hyperloglogs 等。

Redis 具備 LRU 淘汰、事務實現、以及不同級別的硬盤持久化等能力,并且支持副本集和通過 Redis Sentinel 實現的高可用方案,同時還支持通過 Redis Cluster 實現的數據自動分片能力。

Redis 的主要功能都基于單線程模型實現,也就是說 Redis 使用一個線程來服務所有的客戶端請求,同時 Redis 采用了非阻塞式 IO,并精細地優化各種命令的算法時間復雜度,這些信息意味著:

Redis 是線程安全的(因為只有一個線程),其所有操作都是原子的,不會因并發產生數據異常

Redis 的速度非??欤ㄒ驗槭褂梅亲枞?IO,且大部分命令的算法時間復雜度都是 O(1))

使用高耗時的 Redis 命令是很危險的,會占用唯一的一個線程的大量處理時間,導致所有的請求都被拖慢。(例如時間復雜度為 O(N) 的 KEYS 命令,嚴格禁止在生產環境中使用)

Redis 的數據結構和相關常用命令

本節中將介紹 Redis 支持的主要數據結構,以及相關的常用 Redis 命令。本節只對 Redis 命令進行扼要的介紹,且只列出了較常用的命令。如果想要了解完整的 Redis 命令集,或了解某個命令的詳細使用方法,

常用命令一、Key

Redis 采用 Key-Value 型的基本數據結構,任何二進制序列都可以作為 Redis 的 Key 使用(例如普通的字符串或一張 JPEG 圖片)關于 Key 的一些注意事項:

不要使用過長的 Key。例如使用一個 1024 字節的 key 就不是一個好主意,不僅會消耗更多的內存,還會導致查找的效率降低

Key 短到缺失了可讀性也是不好的,例如”u1000flw” 比起”user:1000:followers” 來說,節省了寥寥的存儲空間,卻引發了可讀性和可維護性上的麻煩

最好使用統一的規范來設計 Key,比如”object-type:id:attr”,以這一規范設計出的 Key 可能是”user:1000” 或”comment:1234:reply-to”

Redis 允許的最大 Key 長度是 512MB(對 Value 的長度限制也是 512MB)

常用命令二、String

String 是 Redis 的基礎數據類型,Redis 沒有 Int、Float、Boolean 等數據類型的概念,所有的基本類型在 Redis 中都以 String 體現。

與 String 相關的常用命令:

SET:為一個 key 設置 value,可以配合 EX/PX 參數指定 key 的有效期,通過 NX/XX 參數針對 key 是否存在的情況進行區別操作,時間復雜度 O(1)

GET:獲取某個 key 對應的 value,時間復雜度 O(1)

GETSET:為一個 key 設置 value,并返回該 key 的原 value,時間復雜度 O(1)

MSET:為多個 key 設置 value,時間復雜度 O(N)

MSETNX:同 MSET,如果指定的 key 中有任意一個已存在,則不進行任何操作,時間復雜度 O(N)

MGET:獲取多個 key 對應的 value,時間復雜度 O(N)

上文提到過,Redis 的基本數據類型只有 String,但 Redis 可以把 String 作為整型或浮點型數字來使用,主要體現在 INCR、DECR 類的命令上:

INCR:將 key 對應的 value 值自增 1,并返回自增后的值。只對可以轉換為整型的 String 數據起作用。時間復雜度 O(1)

INCRBY:將 key 對應的 value 值自增指定的整型數值,并返回自增后的值。只對可以轉換為整型的 String 數據起作用。時間復雜度 O(1)

DECR/DECRBY:同 INCR/INCRBY,自增改為自減。

INCR/DECR 系列命令要求操作的 value 類型為 String,并可以轉換為 64 位帶符號的整型數字,否則會返回錯誤。

也就是說,進行 INCR/DECR 系列命令的 value,必須在 [-2^63 ~ 2^63 - 1] 范圍內。

前文提到過,Redis 采用單線程模型,天然是線程安全的,這使得 INCR/DECR 命令可以非常便利的實現高并發場景下的精確控制。

例 1:庫存控制

在高并發場景下實現庫存余量的精準校驗,確保不出現超賣的情況。

設置庫存總量:

SET inv:remain "100"

庫存扣減 + 余量校驗:

DECR inv:remain

當 DECR 命令返回值大于等于 0 時,說明庫存余量校驗通過,如果返回小于 0 的值,則說明庫存已耗盡。

假設同時有 300 個并發請求進行庫存扣減,Redis 能夠確保這 300 個請求分別得到 99 到 - 200 的返回值,每個請求得到的返回值都是唯一的,絕對不會找出現兩個請求得到一樣的返回值的情況。

例 2:自增序列生成

實現類似于 RDBMS 的 Sequence 功能,生成一系列唯一的序列號

設置序列起始值:

SET sequence "10000"

獲取一個序列值:

INCR sequence

直接將返回值作為序列使用即可。

獲取一批(如 100 個)序列值:

INCRBY sequence 100

假設返回值為 N,那么 [N - 99 ~ N] 的數值都是可用的序列值。

當多個客戶端同時向 Redis 申請自增序列時,Redis 能夠確保每個客戶端得到的序列值或序列范圍都是全局唯一的,絕對不會出現不同客戶端得到了重復的序列值的情況。

常用命令三、List

Redis 的 List 是鏈表型的數據結構,可以使用 LPUSH/RPUSH/LPOP/RPOP 等命令在 List 的兩端執行插入元素和彈出元素的操作。雖然 List 也支持在特定 index 上插入和讀取元素的功能,但其時間復雜度較高(O(N)),應小心使用。

與 List 相關的常用命令:

LPUSH:向指定 List 的左側(即頭部)插入 1 個或多個元素,返回插入后的 List 長度。時間復雜度 O(N),N 為插入元素的數量

RPUSH:同 LPUSH,向指定 List 的右側(即尾部)插入 1 或多個元素

LPOP:從指定 List 的左側(即頭部)移除一個元素并返回,時間復雜度 O(1)

RPOP:同 LPOP,從指定 List 的右側(即尾部)移除 1 個元素并返回

LPUSHX/RPUSHX:與 LPUSH/RPUSH 類似,區別在于,LPUSHX/RPUSHX 操作的 key 如果不存在,則不會進行任何操作

LLEN:返回指定 List 的長度,時間復雜度 O(1)

LRANGE:返回指定 List 中指定范圍的元素(雙端包含,即 LRANGE key 0 10 會返回 11 個元素),時間復雜度 O(N)。應盡可能控制一次獲取的元素數量,一次獲取過大范圍的 List 元素會導致延遲,同時對長度不可預知的 List,避免使用 LRANGE key 0 -1 這樣的完整遍歷操作。

應謹慎使用的 List 相關命令:

LINDEX:返回指定 List 指定 index 上的元素,如果 index 越界,返回 nil。index 數值是回環的,即 - 1 代表 List 最后一個位置,-2 代表 List 倒數第二個位置。時間復雜度 O(N)

LSET:將指定 List 指定 index 上的元素設置為 value,如果 index 越界則返回錯誤,時間復雜度 O(N),如果操作的是頭 / 尾部的元素,則時間復雜度為 O(1)

LINSERT:向指定 List 中指定元素之前 / 之后插入一個新元素,并返回操作后的 List 長度。如果指定的元素不存在,返回 - 1。如果指定 key 不存在,不會進行任何操作,時間復雜度 O(N)

由于 Redis 的 List 是鏈表結構的,上述的三個命令的算法效率較低,需要對 List 進行遍歷,命令的耗時無法預估,在 List 長度大的情況下耗時會明顯增加,應謹慎使用。

換句話說,Redis 的 List 實際是設計來用于實現隊列,而不是用于實現類似 ArrayList 這樣的列表的。如果你不是想要實現一個雙端出入的隊列,那么請盡量不要使用 Redis 的 List 數據結構。

為了更好支持隊列的特性,Redis 還提供了一系列阻塞式的操作命令,如 BLPOP/BRPOP 等,能夠實現類似于 BlockingQueue 的能力,即在 List 為空時,阻塞該連接,直到 List 中有對象可以出隊時再返回。針對阻塞類的命令,此處不做詳細探討,請參考官方文檔(https://redis.io/topics/data-types-intro) 中”Blocking operations on lists” 一節。

常用命令四、Hash

Hash 即哈希表,Redis 的 Hash 和傳統的哈希表一樣,是一種 field-value 型的數據結構,可以理解成將 HashMap 搬入 Redis。

Hash 非常適合用于表現對象類型的數據,用 Hash 中的 field 對應對象的 field 即可。

Hash 的優點包括:

可以實現二元查找,如” 查找 ID 為 1000 的用戶的年齡”

比起將整個對象序列化后作為 String 存儲的方法,Hash 能夠有效地減少網絡傳輸的消耗

當使用 Hash 維護一個集合時,提供了比 List 效率高得多的隨機訪問命令

與 Hash 相關的常用命令:

HSET:將 key 對應的 Hash 中的 field 設置為 value。如果該 Hash 不存在,會自動創建一個。時間復雜度 O(1)

HGET:返回指定 Hash 中 field 字段的值,時間復雜度 O(1)

HMSET/HMGET:同 HSET 和 HGET,可以批量操作同一個 key 下的多個 field,時間復雜度:O(N),N 為一次操作的 field 數量

HSETNX:同 HSET,但如 field 已經存在,HSETNX 不會進行任何操作,時間復雜度 O(1)

HEXISTS:判斷指定 Hash 中 field 是否存在,存在返回 1,不存在返回 0,時間復雜度 O(1)

HDEL:刪除指定 Hash 中的 field(1 個或多個),時間復雜度:O(N),N 為操作的 field 數量

HINCRBY:同 INCRBY 命令,對指定 Hash 中的一個 field 進行 INCRBY,時間復雜度 O(1)

應謹慎使用的 Hash 相關命令:

HGETALL:返回指定 Hash 中所有的 field-value 對。返回結果為數組,數組中 field 和 value 交替出現。時間復雜度 O(N)

HKEYS/HVALS:返回指定 Hash 中所有的 field/value,時間復雜度 O(N)

上述三個命令都會對 Hash 進行完整遍歷,Hash 中的 field 數量與命令的耗時線性相關,對于尺寸不可預知的 Hash,應嚴格避免使用上面三個命令,而改為使用 HSCAN 命令進行游標式的遍歷,

常用命令五、Set

Redis Set 是無序的,不可重復的 String 集合。

與 Set 相關的常用命令:

SADD:向指定 Set 中添加 1 個或多個 member,如果指定 Set 不存在,會自動創建一個。時間復雜度 O(N),N 為添加的 member 個數

SREM:從指定 Set 中移除 1 個或多個 member,時間復雜度 O(N),N 為移除的 member 個數

SRANDMEMBER:從指定 Set 中隨機返回 1 個或多個 member,時間復雜度 O(N),N 為返回的 member 個數

SPOP:從指定 Set 中隨機移除并返回 count 個 member,時間復雜度 O(N),N 為移除的 member 個數

SCARD:返回指定 Set 中的 member 個數,時間復雜度 O(1)

SISMEMBER:判斷指定的 value 是否存在于指定 Set 中,時間復雜度 O(1)

SMOVE:將指定 member 從一個 Set 移至另一個 Set

慎用的 Set 相關命令:

SMEMBERS:返回指定 Hash 中所有的 member,時間復雜度 O(N)

SUNION/SUNIONSTORE:計算多個 Set 的并集并返回 / 存儲至另一個 Set 中,時間復雜度 O(N),N 為參與計算的所有集合的總 member 數

SINTER/SINTERSTORE:計算多個 Set 的交集并返回 / 存儲至另一個 Set 中,時間復雜度 O(N),N 為參與計算的所有集合的總 member 數

SDIFF/SDIFFSTORE:計算 1 個 Set 與 1 或多個 Set 的差集并返回 / 存儲至另一個 Set 中,時間復雜度 O(N),N 為參與計算的所有集合的總 member 數。

上述幾個命令涉及的計算量大,應謹慎使用,特別是在參與計算的 Set 尺寸不可知的情況下,應嚴格避免使用??梢钥紤]通過 SSCAN 命令遍歷獲取相關 Set 的全部 member(具體請見 https://redis.io/commands/scan ),如果需要做并集 / 交集 / 差集計算,可以在客戶端進行,或在不服務實時查詢請求的 Slave 上進行。

常用命令六、Sorted Set

Redis Sorted Set 是有序的、不可重復的 String 集合。Sorted Set 中的每個元素都需要指派一個分數 (score),Sorted Set 會根據 score 對元素進行升序排序。如果多個 member 擁有相同的 score,則以字典序進行升序排序。

Sorted Set 非常適合用于實現排名。

Sorted Set 的主要命令:

ZADD:向指定 Sorted Set 中添加 1 個或多個 member,時間復雜度 O(Mlog(N)),M 為添加的 member 數量,N 為 Sorted Set 中的 member 數量

ZREM:從指定 Sorted Set 中刪除 1 個或多個 member,時間復雜度 O(Mlog(N)),M 為刪除的 member 數量,N 為 Sorted Set 中的 member 數量

ZCOUNT:返回指定 Sorted Set 中指定 score 范圍內的 member 數量,時間復雜度:O(log(N))

ZCARD:返回指定 Sorted Set 中的 member 數量,時間復雜度 O(1)

ZSCORE:返回指定 Sorted Set 中指定 member 的 score,時間復雜度 O(1)

ZRANK/ZREVRANK:返回指定 member 在 Sorted Set 中的排名,ZRANK 返回按升序排序的排名,ZREVRANK 則返回按降序排序的排名。時間復雜度 O(log(N))

ZINCRBY:同 INCRBY,對指定 Sorted Set 中的指定 member 的 score 進行自增,時間復雜度 O(log(N))

慎用的 Sorted Set 相關命令:

ZRANGE/ZREVRANGE:返回指定 Sorted Set 中指定排名范圍內的所有 member,ZRANGE 為按 score 升序排序,ZREVRANGE 為按 score 降序排序,時間復雜度 O(log(N)+M),M 為本次返回的 member 數

ZRANGEBYSCORE/ZREVRANGEBYSCORE:返回指定 Sorted Set 中指定 score 范圍內的所有 member,返回結果以升序 / 降序排序,min 和 max 可以指定為 - inf 和 + inf,代表返回所有的 member。時間復雜度 O(log(N)+M)

ZREMRANGEBYRANK/ZREMRANGEBYSCORE:移除 Sorted Set 中指定排名范圍 / 指定 score 范圍內的所有 member。時間復雜度 O(log(N)+M)

上述幾個命令,應盡量避免傳遞 [0 -1] 或 [-inf +inf] 這樣的參數,來對 Sorted Set 做一次性的完整遍歷,特別是在 Sorted Set 的尺寸不可預知的情況下??梢酝ㄟ^ ZSCAN 命令來進行游標式的遍歷(具體請見 https://redis.io/commands/scan ),或通過 LIMIT 參數來限制返回 member 的數量(適用于 ZRANGEBYSCORE 和 ZREVRANGEBYSCORE 命令),以實現游標式的遍歷。

常用命令七、Bitmap 和 HyperLogLog

Redis 的這兩種數據結構相較之前的并不常用,在本文中只做簡要介紹,如想要詳細了解這兩種數據結構與其相關的命令,請參考官方文檔 https://redis.io/topics/data-types-intro 中的相關章節

Bitmap 在 Redis 中不是一種實際的數據類型,而是一種將 String 作為 Bitmap 使用的方法??梢岳斫鉃閷?String 轉換為 bit 數組。使用 Bitmap 來存儲 true/false 類型的簡單數據極為節省空間。

HyperLogLogs 是一種主要用于數量統計的數據結構,它和 Set 類似,維護一個不可重復的 String 集合,但是 HyperLogLogs 并不維護具體的 member 內容,只維護 member 的個數。也就是說,HyperLogLogs 只能用于計算一個集合中不重復的元素數量,所以它比 Set 要節省很多內存空間。

其他常用命令

EXISTS:判斷指定的 key 是否存在,返回 1 代表存在,0 代表不存在,時間復雜度 O(1)

DEL:刪除指定的 key 及其對應的 value,時間復雜度 O(N),N 為刪除的 key 數量

EXPIRE/PEXPIRE:為一個 key 設置有效期,單位為秒或毫秒,時間復雜度 O(1)

TTL/PTTL:返回一個 key 剩余的有效時間,單位為秒或毫秒,時間復雜度 O(1)

RENAME/RENAMENX:將 key 重命名為 newkey。使用 RENAME 時,如果 newkey 已經存在,其值會被覆蓋;使用 RENAMENX 時,如果 newkey 已經存在,則不會進行任何操作,時間復雜度 O(1)

TYPE:返回指定 key 的類型,string, list, set, zset, hash。時間復雜度 O(1)

CONFIG GET:獲得 Redis 某配置項的當前值,可以使用 * 通配符,時間復雜度 O(1)

CONFIG SET:為 Redis 某個配置項設置新值,時間復雜度 O(1)

CONFIG REWRITE:讓 Redis 重新加載 redis.conf 中的配置

Redis 性能調優

盡管 Redis 是一個非??焖俚膬却鏀祿鎯γ浇?,也并不代表 Redis 不會產生性能問題。前文中提到過,Redis 采用單線程模型,所有的命令都是由一個線程串行執行的,所以當某個命令執行耗時較長時,會拖慢其后的所有命令,這使得 Redis 對每個任務的執行效率更加敏感。

針對 Redis 的性能優化,主要從下面幾個層面入手:

最初的也是最重要的,確保沒有讓 Redis 執行耗時長的命令

使用 pipelining 將連續執行的命令組合執行

操作系統的 Transparent huge pages 功能必須關閉:

echo never > /sys/kernel/mm/transparent_hugepage/enabled

如果在虛擬機中運行 Redis,可能天然就有虛擬機環境帶來的固有延遲。可以通過./redis-cli —intrinsic-latency 100 命令查看固有延遲。同時如果對 Redis 的性能有較高要求的話,應盡可能在物理機上直接部署 Redis。

檢查數據持久化策略

考慮引入讀寫分離機制

長耗時命令

Redis 絕大多數讀寫命令的時間復雜度都在 O(1) 到 O(N) 之間,在文本和官方文檔中均對每個命令的時間復雜度有說明。

通常來說,O(1) 的命令是安全的,O(N) 命令在使用時需要注意,如果 N 的數量級不可預知,則應避免使用。例如對一個 field 數未知的 Hash 數據執行 HGETALL/HKEYS/HVALS 命令,通常來說這些命令執行的很快,但如果這個 Hash 中的 field 數量極多,耗時就會成倍增長。

又如使用 SUNION 對兩個 Set 執行 Union 操作,或使用 SORT 對 List/Set 執行排序操作等時,都應該嚴加注意。

避免在使用這些 O(N) 命令時發生問題主要有幾個辦法:

不要把 List 當做列表使用,僅當做隊列來使用

通過機制嚴格控制 Hash、Set、Sorted Set 的大小

可能的話,將排序、并集、交集等操作放在客戶端執行

絕對禁止使用 KEYS 命令

避免一次性遍歷集合類型的所有成員,而應使用 SCAN 類的命令進行分批的,游標式的遍歷

Redis 提供了 SCAN 命令,可以對 Redis 中存儲的所有 key 進行游標式的遍歷,避免使用 KEYS 命令帶來的性能問題。同時還有 SSCAN/HSCAN/ZSCAN 等命令,分別用于對 Set/Hash/Sorted Set 中的元素進行游標式遍歷。SCAN 類命令的使用請參考官方文檔:https://redis.io/commands/scan

Redis 提供了 Slow Log 功能,可以自動記錄耗時較長的命令。相關的配置參數有兩個:

slowlog-log-slower-than xxxms #執行時間慢于xxx毫秒的命令計入Slow Logslowlog-max-len xxx #Slow Log的長度,即最大紀錄多少條Slow Log

使用SLOWLOG GET [number]命令,可以輸出最近進入 Slow Log 的 number 條命令。使用SLOWLOG RESET命令,可以重置 Slow Log

網絡引發的延遲

盡可能使用長連接或連接池,避免頻繁創建銷毀連接

客戶端進行的批量數據操作,應使用 Pipeline 特性在一次交互中完成。具體請參照本文的 Pipelining 章節

數據持久化引發的延遲

Redis 的數據持久化工作本身就會帶來延遲,需要根據數據的安全級別和性能要求制定合理的持久化策略:

AOF + fsync always 的設置雖然能夠絕對確保數據安全,但每個操作都會觸發一次 fsync,會對 Redis 的性能有比較明顯的影響

AOF + fsync every second 是比較好的折中方案,每秒 fsync 一次

AOF + fsync never 會提供 AOF 持久化方案下的最優性能使用 RDB 持久化通常會提供比使用 AOF 更高的性能,但需要注意 RDB 的策略配置

每一次 RDB 快照和 AOF Rewrite 都需要 Redis 主進程進行 fork 操作。fork 操作本身可能會產生較高的耗時,與 CPU 和 Redis 占用的內存大小有關。根據具體的情況合理配置 RDB 快照和 AOF Rewrite 時機,避免過于頻繁的 fork 帶來的延遲

Redis 在 fork 子進程時需要將內存分頁表拷貝至子進程,以占用了 24GB 內存的 Redis 實例為例,共需要拷貝 24GB / 4kB * 8 = 48MB 的數據。在使用單 Xeon 2.27Ghz 的物理機上,這一 fork 操作耗時 216ms。

可以通過 INFO 命令返回的 latest_fork_usec 字段查看上一次 fork 操作的耗時(微秒)

Swap 引發的延遲

Linux 將 Redis 所用的內存分頁移至 swap 空間時,將會阻塞 Redis 進程,導致 Redis 出現不正常的延遲。Swap 通常在物理內存不足或一些進程在進行大量 I/O 操作時發生,應盡可能避免上述兩種情況的出現。

/proc//smaps 文件中會保存進程的 swap 記錄,通過查看這個文件,能夠判斷 Redis 的延遲是否由 Swap 產生。如果這個文件中記錄了較大的 Swap size,則說明延遲很有可能是 Swap 造成的。

數據淘汰引發的延遲

當同一秒內有大量 key 過期時,也會引發 Redis 的延遲。在使用時應盡量將 key 的失效時間錯開。

引入讀寫分離機制

Redis 的主從復制能力可以實現一主多從的多節點架構,在這一架構下,主節點接收所有寫請求,并將數據同步給多個從節點。

在這一基礎上,我們可以讓從節點提供對實時性要求不高的讀請求服務,以減小主節點的壓力。

尤其是針對一些使用了長耗時命令的統計類任務,完全可以指定在一個或多個從節點上執行,避免這些長耗時命令影響其他請求的響應。

關于讀寫分離的具體說明,請參見后續章節

主從復制與集群分片

主從復制

Redis 支持一主多從的主從復制架構。一個 Master 實例負責處理所有的寫請求,Master 將寫操作同步至所有 Slave。

借助 Redis 的主從復制,可以實現讀寫分離和高可用:

實時性要求不是特別高的讀請求,可以在 Slave 上完成,提升效率。特別是一些周期性執行的統計任務,這些任務可能需要執行一些長耗時的 Redis 命令,可以專門規劃出 1 個或幾個 Slave 用于服務這些統計任務

借助 Redis Sentinel 可以實現高可用,當 Master crash 后,Redis Sentinel 能夠自動將一個 Slave 晉升為 Master,繼續提供服務

啟用主從復制非常簡單,只需要配置多個 Redis 實例,在作為 Slave 的 Redis 實例中配置:

slaveof 192.168.1.1 6379 #指定Master的IP和端口

當 Slave 啟動后,會從 Master 進行一次冷啟動數據同步,由 Master 觸發 BGSAVE 生成 RDB 文件推送給 Slave 進行導入,導入完成后 Master 再將增量數據通過 Redis Protocol 同步給 Slave。之后主從之間的數據便一直以 Redis Protocol 進行同步

使用 Sentinel 做自動 failover

Redis 的主從復制功能本身只是做數據同步,并不提供監控和自動 failover 能力,要通過主從復制功能來實現 Redis 的高可用,還需要引入一個組件:Redis Sentinel

Redis Sentinel 是 Redis 官方開發的監控組件,可以監控 Redis 實例的狀態,通過 Master 節點自動發現 Slave 節點,并在監測到 Master 節點失效時選舉出一個新的 Master,并向所有 Redis 實例推送新的主從配置。

Redis Sentinel 需要至少部署 3 個實例才能形成選舉關系。

關鍵配置:

sentinel monitor mymaster 127.0.0.1 6379 2 #Master實例的IP、端口,以及選舉需要的贊成票數sentinel down-after-milliseconds mymaster 60000 #多長時間沒有響應視為Master失效sentinel failover-timeout mymaster 180000 #兩次failover嘗試間的間隔時長sentinel parallel-syncs mymaster 1 #如果有多個Slave,可以通過此配置指定同時從新Master進行數據同步的Slave數,避免所有Slave同時進行數據同步導致查詢服務也不可用

另外需要注意的是,Redis Sentinel 實現的自動 failover 不是在同一個 IP 和端口上完成的,也就是說自動 failover 產生的新 Master 提供服務的 IP 和端口與之前的 Master 是不一樣的,所以要實現 HA,還要求客戶端必須支持 Sentinel,能夠與 Sentinel 交互獲得新 Master 的信息才行。

集群分片

為何要做集群分片:

Redis 中存儲的數據量大,一臺主機的物理內存已經無法容納

Redis 的寫請求并發量大,一個 Redis 實例以無法承載

當上述兩個問題出現時,就必須要對 Redis 進行分片了。

Redis 的分片方案有很多種,例如很多 Redis 的客戶端都自行實現了分片功能,也有向 Twemproxy 這樣的以代理方式實現的 Redis 分片方案。然而首選的方案還應該是 Redis 官方在 3.0 版本中推出的 Redis Cluster 分片方案。

本文不會對 Redis Cluster 的具體安裝和部署細節進行介紹,重點介紹 Redis Cluster 帶來的好處與弊端。

Redis Cluster 的能力

能夠自動將數據分散在多個節點上

當訪問的 key 不在當前分片上時,能夠自動將請求轉發至正確的分片

當集群中部分節點失效時仍能提供服務

其中第三點是基于主從復制來實現的,Redis Cluster 的每個數據分片都采用了主從復制的結構,原理和前文所述的主從復制完全一致,唯一的區別是省去了 Redis Sentinel 這一額外的組件,由 Redis Cluster 負責進行一個分片內部的節點監控和自動 failover。

Redis Cluster 分片原理

Redis Cluster 中共有 16384 個 hash slot,Redis 會計算每個 key 的 CRC16,將結果與 16384 取模,來決定該 key 存儲在哪一個 hash slot 中,同時需要指定 Redis Cluster 中每個數據分片負責的 Slot 數。Slot 的分配在任何時間點都可以進行重新分配。

客戶端在對 key 進行讀寫操作時,可以連接 Cluster 中的任意一個分片,如果操作的 key 不在此分片負責的 Slot 范圍內,Redis Cluster 會自動將請求重定向到正確的分片上。

hash tags

在基礎的分片原則上,Redis 還支持 hash tags 功能,以 hash tags 要求的格式明明的 key,將會確保進入同一個 Slot 中。例如:{uiv}user:1000 和 {uiv}user:1001 擁有同樣的 hash tag {uiv},會保存在同一個 Slot 中。

使用 Redis Cluster 時,pipelining、事務和 LUA Script 功能涉及的 key 必須在同一個數據分片上,否則將會返回錯誤。如要在 Redis Cluster 中使用上述功能,就必須通過 hash tags 來確保一個 pipeline 或一個事務中操作的所有 key 都位于同一個 Slot 中。

有一些客戶端(如 Redisson)實現了集群化的 pipelining 操作,可以自動將一個 pipeline 里的命令按 key 所在的分片進行分組,分別發到不同的分片上執行。但是 Redis 不支持跨分片的事務,事務和 LUA Script 還是必須遵循所有 key 在一個分片上的規則要求。

主從復制 vs 集群分片

在設計軟件架構時,要如何在主從復制和集群分片兩種部署方案中取舍呢?

從各個方面看,Redis Cluster 都是優于主從復制的方案

Redis Cluster 能夠解決單節點上數據量過大的問題

Redis Cluster 能夠解決單節點訪問壓力過大的問題

Redis Cluster 包含了主從復制的能力

那是不是代表 Redis Cluster 永遠是優于主從復制的選擇呢?

并不是。

軟件架構永遠不是越復雜越好,復雜的架構在帶來顯著好處的同時,一定也會帶來相應的弊端。采用 Redis Cluster 的弊端包括:

維護難度增加。在使用 Redis Cluster 時,需要維護的 Redis 實例數倍增,需要監控的主機數量也相應增加,數據備份 / 持久化的復雜度也會增加。同時在進行分片的增減操作時,還需要進行 reshard 操作,遠比主從模式下增加一個 Slave 的復雜度要高。

客戶端資源消耗增加。當客戶端使用連接池時,需要為每一個數據分片維護一個連接池,客戶端同時需要保持的連接數成倍增多,加大了客戶端本身和操作系統資源的消耗。

性能優化難度增加。你可能需要在多個分片上查看 Slow Log 和 Swap 日志才能定位性能問題。

事務和 LUA Script 的使用成本增加。在 Redis Cluster 中使用事務和 LUA Script 特性有嚴格的限制條件,事務和 Script 中操作的 key 必須位于同一個分片上,這就使得在開發時必須對相應場景下涉及的 key 進行額外的規劃和規范要求。如果應用的場景中大量涉及事務和 Script 的使用,如何在保證這兩個功能的正常運作前提下把數據平均分到多個數據分片中就會成為難點。

所以說,在主從復制和集群分片兩個方案中做出選擇時,應該從應用軟件的功能特性、數據和訪問量級、未來發展規劃等方面綜合考慮,只在確實有必要引入數據分片時再使用 Redis Cluster。下面是一些建議:

需要在 Redis 中存儲的數據有多大?未來 2 年內可能發展為多大?這些數據是否都需要長期保存?是否可以使用 LRU 算法進行非熱點數據的淘汰?綜合考慮前面幾個因素,評估出 Redis 需要使用的物理內存。

用于部署 Redis 的主機物理內存有多大?有多少可以分配給 Redis 使用?對比 (1) 中的內存需求評估,是否足夠用?

Redis 面臨的并發寫壓力會有多大?在不使用 pipelining 時,Redis 的寫性能可以超過 10 萬次 / 秒(更多的 benchmark 可以參考 https://redis.io/topics/benchmarks )

在使用 Redis 時,是否會使用到 pipelining 和事務功能?使用的場景多不多?綜合上面幾點考慮,如果單臺主機的可用物理內存完全足以支撐對 Redis 的容量需求,且 Redis 面臨的并發寫壓力距離 Benchmark 值還尚有距離,建議采用主從復制的架構,可以省去很多不必要的麻煩。同時,如果應用中大量使用 pipelining 和事務,也建議盡可能選擇主從復制架構,可以減少設計和開發時的復雜度。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • Linux
    +關注

    關注

    87

    文章

    11225

    瀏覽量

    208911
  • key
    key
    +關注

    關注

    0

    文章

    48

    瀏覽量

    12814
  • Redis
    +關注

    關注

    0

    文章

    371

    瀏覽量

    10844
  • string
    +關注

    關注

    0

    文章

    40

    瀏覽量

    4717

原文標題:Redis 基礎、高級特性與性能調優 | 一文看全

文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運維】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    Redis Stream應用案例

    IRC頻道(channel1),就可以接收所有用戶發出的消息了。發出消息時,只需使用發布命令(publish)命令即可。整個業務邏輯非常的清晰簡單,這也是Redis強大和流行的重要原因——提供的功能和
    發表于 06-26 17:15

    Redis-數據結構與對象

    Redis-數據結構與對象-對象
    發表于 06-01 17:28

    Redis數據結構主要命令Redis基本能力進行直觀介紹

    當多個客戶端同時向Redis申請自增序列時,Redis能夠確保每個客戶端得到的序列值或序列范圍都是全局唯一的,絕對不會出現不同客戶端得到了重復的序列值的情況。
    的頭像 發表于 11-05 17:57 ?2953次閱讀

    Redis五種常見對象類型的底層數據結構

    集合(Zset),我們在日常工作中也會經常使用它們。知其然,更要知其所以然,本文將會帶你讀懂這五種常見對象類型的底層數據結構。 本文主要內容參考自《Redis設計與實現》 1. 對象類型和編碼
    的頭像 發表于 11-14 09:50 ?2972次閱讀
    <b class='flag-5'>Redis</b>五種常見對象類型的底層<b class='flag-5'>數據結構</b>

    什么是 Redis

    的這種特殊性質讓它在開發人員中很受歡迎。 Redis不是通過迭代或者排序方式處理數據,而是一開始就按照數據結構方式組織。早期,它的使用很像 Memcached,但隨著
    的頭像 發表于 05-22 15:32 ?1079次閱讀
    什么是 <b class='flag-5'>Redis</b>

    redis的五種數據類型底層數據結構

    Redis是一種內存數據存儲系統,支持多種數據結構。這些數據結構不僅可以滿足常見的存儲需求,還能夠通過其底層
    的頭像 發表于 11-16 11:18 ?683次閱讀

    redis集群狀態查看命令

    Redis集群是一種高可用性的分布式架構,可以通過多個節點實現數據的復制和負載均衡。為了維護集群的穩定性和可靠性,管理員需要監控和查看集群的狀態。下面是詳細介紹
    的頭像 發表于 12-04 10:44 ?1238次閱讀

    Java redis鎖怎么實現

    在Java中實現Redis鎖涉及到以下幾個方面:Redis的安裝配置、Redis連接池的使用、Redis數據結構的選擇、實現分布式鎖的幾種方
    的頭像 發表于 12-04 10:47 ?1116次閱讀

    redis查看集群狀態命令

    Redis 是一個開源的、內存中的數據結構存儲系統,提供了一系列命令來管理和操作數據。在 Redis 中,集群是一個由多個
    的頭像 發表于 12-04 11:39 ?1020次閱讀

    redis查看主從節點命令

    Redis是一種開源的內存數據結構存儲系統,常被用作數據庫、緩存和消息中間件。在Redis中,可以通過一些
    的頭像 發表于 12-04 11:44 ?1233次閱讀

    redis hash底層實現原理

    數據結構是如何實現的呢?本文將詳細介紹Redis哈希底層的實現原理。 在Redis中,每個哈希都是由一個類似于字典(Dictionary)的結構
    的頭像 發表于 12-04 16:27 ?559次閱讀

    redis的原理和使用場景

    Redis(Remote Dictionary Server)是一個開源的、高性能的非關系型(NoSQL)的鍵值對數據庫管理系統。它以其快速讀寫能力和多種數據結構支持而聞名,并被廣泛應
    的頭像 發表于 12-04 16:29 ?566次閱讀

    redis容器內怎么查看redis日志

    redis是一款流行的開源內存數據庫,常用于緩存、消息隊列、任務管理等場景。在使用redis時,了解如何查看redis日志對于排查問題、監控性能和分析應用程序行為非常重要。在本文中,我
    的頭像 發表于 12-05 10:10 ?3484次閱讀

    redis數據結構的底層實現

    Redis是一種內存鍵值數據庫,常用于緩存、消息隊列、實時數據分析等場景。它的高性能得益于其精心設計的數據結構和底層實現。本文將詳細介紹
    的頭像 發表于 12-05 10:14 ?590次閱讀

    redis是關系型數據庫嗎

    Redis不是關系型數據庫,它是一種基于鍵值對的NoSQL數據庫。在本文中,我將對Redis進行詳細介紹
    的頭像 發表于 12-05 10:32 ?1496次閱讀