Redis

Redis(Remote Dictionary Server)是一種開放原始碼、記憶體內資料存放區,回應時間低於一毫秒,可讓遊戲、廣告科技、金融服務、醫療保健和 IoT 等產業的即時應用程式每秒處理數百萬個請求。

由於其快速的效能,常用於快取、工作階段管理、遊戲、排行榜、即時分析、地理空間、叫車、聊天/簡訊、媒體串流和發佈/訂閱應用程式的熱門選項。

優勢

效能

Redis 所有資料都存放在記憶體中,從而實現低延遲和高輸送量的資料存取。與傳統資料庫不同,記憶體內資料儲存不需要存取磁碟,從而將引擎延遲縮減到微秒。因此,記憶體內資料儲存能夠支援更大規模的操作,而且回應時間更快。這項優勢提供超快速的效能,平均讀取和寫入操作時間低於一毫秒,並支援每秒百萬個操作。

彈性的資料結構

其他鍵值資料存放區提供的資料結構有限,而 Redis 則提供多樣化的資料結構以滿足應用程式的需要。Redis 資料類型包括:

  • 字串 – 文字或二進位資料,最大 512 MB
  • 清單 – 按新增順序排列的字串集合
  • 資料集 – 未排序的字串集合,可與其他資料集類型交叉、合併和區分
  • 排序資料集 – 依數值排列的資料集
  • 雜湊 – 存放欄位和值清單的資料結構
  • 點陣圖 – 提供位元層級操作的資料類型
  • HyperLogLogs – 用來評估資料集獨特項目的概率資料結構
  • 串流 - 日誌資料結構訊息佇列
  • 地理空間 – 以經度/緯度為基礎的項目地圖,「附近」
  • JSON – 嵌套式、半結構化命名值物件,支援數字、字串、布林值、陣列和其他物件

簡單易用

Redis 可讓您用更少、更簡單的行編寫傳統上複雜的程式碼。藉由 Redis,您只要撰寫幾行程式碼即可存放、存取和使用應用程式的資料。差異在於使用 Redis 的開發人員使用簡單的命令結構,而不是傳統資料庫的查詢語言。例如,您使用 Redis 雜湊資料結構,僅用一行程式碼即可將資料移至資料存放區如果在沒有雜湊資料結構的資料存放區進行類似的任務,則需要撰寫許多行的程式碼才能將格式轉換為另一種格式。Redis 隨附可操控和與資料互動的原生資料結構和許多選項。Redis 開發人員可使用超過一百種開放原始碼用戶端。支援的語言包含 Java、Python、PHP、C、C++、C#、JavaScript、Node.js、Ruby、R、Go 等等。

複寫和持續性

Redis 採用主要-複本架構,並支援非同步複寫,可將資料複寫到多部複本伺服器。這不但可提升讀取效能 (因為請求可分割到多部伺服器),還能在主伺服器發生故障時快速恢復。至於持久性,Redis 支援時間點備份 (將 Redis 資料集複製到磁碟)。
Redis 並非建置為持久且一致的資料庫。如果您需要持久且與 Redis 相容的資料庫,請考慮 Amazon MemoryDB for Redis。 由於 MemoryDB 使用持久的交易日誌,該日誌跨多個可用區域 (AZ) 存放資料,您可以將其用作主要資料庫。MemoryDB 專為使開發人員能夠使用 Redis API 而無需擔心管理單獨的快取、資料庫或底層基礎設施而打造。

高可用性和可擴展性

Redis 在單一節點的主要或叢集拓撲提供主要-複本架構。這可讓您建立高度可用解決方案,以提供一致的效能和可靠性。需要調整叢集大小時,還可利用擴展和縮減或擴增等各種選項。這可讓您的叢集隨著需要擴展。

開源

Redis是開源專案,由於 Redis 使用開放式標準、支援開放資料格式並含有豐富的用戶端,因此沒有廠商或技術鎖定的問題。

常用案例

快取

Redis 是實作高可用性記憶體內快取的絕佳選項,可減少資料存取延遲、增加輸送量,以及減輕關聯式或 NoSQL 資料庫和應用程式的負載。Redis 可提供低於一毫秒的回應時間來服務頻繁要求的項目,且讓您能夠輕鬆地針對較高的負載進行擴展,無須擴充較為昂貴的後端。資料庫查詢結果快取、持久性工作階段快取、網頁快取,以及影像、檔案和中繼資料等快取常用物件都是 Redis 快取的常見範例。

聊天、簡訊和佇列

Redis 支援含模式比對功能的發佈/訂閱,以及清單、排序資料集和雜湊等各種資料結構。這讓 Redis 能夠支援高效能聊天室、即時註解串流、社交媒體饋送及伺服器互相通訊。Redis 清單資料結構可輕鬆實作輕量型的佇列。清單提供原子操作以及封鎖功能,因此適合用於需要可靠的訊息代理程式或循環清單的各種應用程式。

遊戲排行榜

對於想要建立即時排行榜的遊戲開發人員而言,Redis 是絕佳的選擇。只要使用 Redis 排序集資料結構,即可提供元素的唯一性,同時維護依使用者分數排序的清單。建立即時排名清單就和每次使用者分數變更時進行更新一樣簡單。您也可以透過利用時間戳記做為分數,使用排序集處理時間序列資料。

工作階段存放區

應用程式開發人員廣泛使用 Redis 做為高度可用且持久的記憶體內資料存放區,用以存放和管理網際網路規模應用程式的工作階段資料。Redis 提供管理使用者描述檔、登入資料、工作階段狀態和使用者專屬個人化等工作階段資料所需的低於一毫秒延遲、擴展和彈性。

豐富的媒體串流

Redis 提供快速的記憶體內資料存放區,以支援即時串流使用案例。Redis 可用於存放使用者描述檔的相關中繼資料,以及檢視數百萬個使用者的歷史記錄、身份驗證資訊/字符以及資訊清單檔案,以啟用 CDN 將影片一次串流到數百萬行動和桌面使用者。

地理空間

Redis 提供專門打造的記憶體內資料結構和運算子,可大規模快速管理即時地理空間資料。利用 GEOADD、GEODIST、GEORADIUS 和 GEORADIUSBYMEMBER 等命令即時存放、處理和分析地理空間資料,讓 Redis 可輕鬆快速利用地理空間。您可以使用 Redis 新增以位置為基礎的功能,例如行車時間、行車距離,以及應用程式的興趣點。

Machine Learning

現代的資料驅動應用程式需要機器學習迅速處理大量、多樣化和快速的資料,並自動做出決策。像遊戲和金融服務的詐騙偵測、廣告技術的即時競標以及約會配對和共乘等使用案例,在數十毫秒內處理即時資料和做出決策的能力最為重要。Redis 提供快速的記憶體內資料存放區讓您迅速建立、訓練和部署機器學習模型。

即時分析

Redis 可與 Apache Kafka 和 Amazon Kinesis 等串流解決方案搭配使用做為記憶體內資料存放區,以低於一毫秒的延遲導入、處理和分析即時資料。Redis 非常適合用於即時分析使用案例,例如社交媒體分析、廣告目標、個人化和 IoT。

架構

Redis Cli

Keys

查找Key,查詢時指令支援正則表示

keys pattern

範例:

keys *    # 查所有key,常用
keys 'k*' # 查名稱包含[開頭為k]的key

exists

檢查Key是否存在,存在回傳1,不存在回傳0

exists key1

範例:

redis> keys *
1) "k1"
2) "k2"
3) "k3"
4) "k4"
redis> exists k0
(integer) 0
redis> exists k1
(integer) 1
redis> exists k0 k1
(integer) 3
redis> exists k0 k1 k2 k3

Type

查看Key對應的value的類型(Type)

type key

範例:

redis> type key1
string

del

刪除Key

del key1
del key1 key2 key3 # 刪除多個

範例

redis> keys *
1) "k1"
2) "k2"
3) "k3"
4) "k4"
redis> del k1 k2
(integer) 2

expire

設定Key的過期時間,在redis中,若一開始沒有指定過期時間,Key就會一直存在,直到使用del指令移除,而expire則能對已存Key設定過期時間(單位為秒)。
另外可使用pexire以毫秒為單位設定過期時間。

expire key seconds

範例

redis> pexpire key2 100
(integer) 1

# 已刪除
redis> get key2
(nil)

# 設定key1值並設定到期時間為1000毫秒
redis> set key1 jacky px 20000
OK

# 剩餘8666毫秒到期 
redis> pttl key1
(integer) 8666

# 到期已刪除
redis> get key1
(nil)

ttl

查詢Key的有效時間

ttl key

範例

redis> keys *
1) "k1"
redis> expire k1 100
(integer) 1
redis> ttl k1
(integer) 95
redis> ttl k1
(integer) 92

String型別指令

GET, SET

SET是key的值是多少,GET就是取出該KEY的值

redis> SET mykey "Hello World"

redis> GET mykey
"Hello World"

MGET, MSET

MSET一次設定多筆key與value值,MGET一次取出多筆Key的value

redis> mset name1 aaa name2 bbb name3 ccc

redis> mget name1 name2 name3
1) "aaa"
2) "bbb"
3) "ccc"

INCR, DECR

針對某個 key 加一或減一的意思,像是程式語言裡面的mykey++mykey--。INCRBY與DECRBY,可以指定你要加減的數量是多少。

redis> SET mykey "10"
redis> DECR mykey
(integer) 9
redis> INCR mykey
(integer) 10
redis> INCRBY mykey 20
(integer) 30
redis> DECRBY mykey 10
(integer) 20

# 此key2不存在
redis> get mykey2
(nil)

# 此時key會自動寫入1
redis> incr mykey2
(integer) 1

redis> get mykey2
"1"

STRLEN

查詢指定key的value字串長度

redis> get mykey1
"nick"

redis> strlen mykey1
(integer) 4

APPEND

對指定key的value字串插入字串

redis> get mykey1
"nick"

redis> append mykey1 aaa
(integer) 7

redis> get mykey1
"nickaaa"

GETRANGE

根據參數取出value中的起始與結束字元

redis> get mykey1
"nickaaa"

redis> getrange mykey1 0 3
"nick"

SETRANGE

根據參數從指定位置取代value字元

redis> get mykey1
"nickaaa"

redis> setrange mykey1 4 ggg
(integer) 7

redis> get mykey1
"nickggg"

SETNX

當指定的key不存在時才寫入key與value

redis> set mykey1 1234

redis> get mykey1
"1234"

redis> set mykey1 4321

redis> get mykey1
"4321"

# 當mykey1不存在才寫入5678到mykey1的value
redis> setnx mykey1 5678
(integer) 0

redis> get mykey1
"4321"

redis> get mykey2
(nil)

# 當指定的key存在時才寫入key與value.
redis> set mykey2 abc xx
(nil)

HSET, HGET

H就是Hashmap的意思,可以存取一個value底下的 field,讓你可以更多元的使用,例如說你可以定義 key的規則是:POST+文章id,裡面就可以存這篇文章的讚數、回覆數等等,就不用每一次都去Database裡面重新抓取。

redis> HSET mydata name "nick"
redis> HSET mydata nickname "nicknick"
redis> HGET mydata name
"nick"

SADD, SCARD

SADD的S就是Set的意思,裡面不會有重複的內容。

redis> SADD myset "nick"
redis> SADD myset "peter"
redis> SADD myset "nick"
redis> SCARD myset
(integer) 2

LPUSH, RPUSH, LSET, LRANGE

這邊的資料結構是List,你可以選擇從左邊或是右邊 push值進去,對應到的指令就是LPUSH與RPUSH,LSET則是指定某個index的value是多少。
LRANGE可以印出指定範圍的值,支援-1這種形式,表示最後一個值。

redis> LPUSH mylist "a"
redis> LPUSH mylist "b"
redis> RPUSH mylist "c"
redis> LRANGE mylist 0 -1
1) "b"
2) "a"
3) "c"
redis> LSET mylist 0 "d"
redis> LRANGE mylist 0 -1
1) "d"
2) "a"
3) "c"

Redis Windows

https://github.com/zkteco-home/redis-windows/releases

NoSQL & 傳統SQL

NoSQL(Not Only SQL)是一種泛指的數據存儲和管理方法論,它不依賴於傳統的關聯式資料庫管理系統(RDBMS)。
NoSQL 的目標是解決關聯式資料庫在處理大規模、非結構化或半結構化數據時所遇到的限制,提供更靈活、可擴展的數據儲存方案。NoSQL 資料庫通常適合於需要高可擴展性、快速存儲和讀取的場景,並允許更多的數據靈活性。

NoSQL優點

  • 大數據和高可擴展性: 如果你處理大量的非結構化數據,或需要在大規模環境中處理高流量,NoSQL 資料庫可能更適合,因為它們通常被設計為可擴展的。
  • 彈性的數據模型: 如果你的數據模型在開發過程中可能會經常變動,或者需要存儲不同類型的數據,NoSQL 資料庫的靈活 schema-less 特性可以更好地滿足你的需求。
  • 快取和高性能需求: 如果你需要快速讀取和寫入數據,特別是用於快取、會話存儲或實時分析,NoSQL 資料庫,特別是像 Redis 這樣的鍵值存儲系統,可以提供極高的性能。
  • 分佈式架構和高可用性: NoSQL 資料庫通常易於構建成分佈式系統,可以實現高可用性和負載均衡。
  • 未知的查詢需求: 如果你不確定未來會有哪些查詢需求,或者需要支援複雜的查詢,NoSQL 資料庫可能更適合,因為它們通常不受固定的結構約束。

傳統SQL優點

  • 結構化數據: 如果你的數據具有固定的結構,且需要嚴格的一致性和完整性,傳統 SQL 資料庫可能更適合。
  • 複雜查詢和事務: 如果你的應用需要複雜的查詢、聚合操作和事務支援,SQL 資料庫提供了強大的查詢語言和 ACID 特性。
  • 預先定義的架構: 如果你的數據模型相對穩定,並且能夠在開發階段進行預先定義的架構,傳統 SQL 資料庫可以幫助確保數據的一致性和規模。
  • 業界標準: 在某些行業,特別是金融、醫療等領域,使用 SQL 資料庫可能符合業界的標準和規定。

Redis缺點

  • 內存限制: Redis 的數據全部存儲在內存中,這意味著它的數據容量受限於可用的系統內存。如果數據量超過可用內存,可能需要投入更多資源來擴展硬體。另外,內存中的數據在服務重啟或發生故障時可能會丟失,這需要通過持久化機制來解決。
  • 持久化複雜性: Redis 提供了不同的持久化方法(快照、AOF 日誌等),這些方法需要根據需求進行配置。選擇合適的持久化方式和參數可能需要一些技術知識,以確保數據的持久性和安全性。
  • 單線程: Redis 使用單線程處理所有的命令,這在處理大量並發操作時可能會成為性能瓶頸。儘管 Redis 通常以毫秒級別的速度處理單個命令,但在需要同時處理大量並發複雜操作的情況下,可能會影響整體性能。
  • 不支援複雜查詢: Redis 的查詢功能相對簡單,主要用於檢索特定鍵或資料結構。它不像傳統的 SQL 資料庫那樣支援複雜的 JOIN、子查詢和聚合等複雜查詢操作。這可能需要在應用程序中處理數據的組合和分析。
  • 無法處理大型二進制對象: Redis 適合存儲小型的鍵值對數據,但對於大型的二進制對象,比如大型文件或圖像,可能會導致內存消耗過高。這樣的數據可能需要其他存儲方式,例如將文件存儲在文件系統中,而不是存儲在 Redis 中。
  • 缺乏交易支援: Redis 的事務處理能力較弱,並不支援完全的 ACID(原子性、一致性、隔離性、持久性)事務。如果你的應用程序需要複雜的多步操作,並要求這些操作具有嚴格的事務性質,則需要額外的處理和保障。
  • 有限的資料模型: Redis 提供的資料模型較為基本,主要包括字符串、散列、列表、集合和有序集合等。如果你的應用程序需要更複雜的數據結構,可能需要在應用層面進行進一步的處理,這可能會增加一些開發工作。

Redis Cluster

Redis Cluster 主要提供兩大功能:

  • Scalability : 幫你將資料分散在不同的機器上,即便資料量變大,你也可以透過橫向擴展來 Handle 大量資料。
  • Availability : 提供 Fail-Over 功能,即便某個機器掛掉了,不僅不會影響 Client 向 Cluster 讀寫資料,Client 還可在別台活著的機器上找到掛點機器的資料。

要完成上面兩大功能首先要思考以下問題:

  1. 如何讓多台 Redis Server 知道彼此以及互相合作?
  2. 將資料分散在不同 Server 的同時,Client 端如何不透過中心化的 Proxy Server 來讀寫 Redis 資料?
  3. 當某台 Redis Server 掛點時,Cluster 如何讓 Client 端幾乎沒有任何等待也能讀寫到掛點 Server 的資料?
  • 問題一:如何讓多台 Redis Server 知道彼此以及互相合作?
    第一個問題之所以重要是因為,Redis Cluster 是採用 P2P 的網路溝通方式,沒有一個中央管理者,因此每個 Redis Server 必須知道 Cluster 內其他 Server 的狀態,並針對各種狀態作出反應 (e.g 當某個 Server 掛點時要做出處理)。

而說到 P2P 網路,就要提到大名鼎鼎的 Gossip 協定,Redis Cluster 之間的溝通就採用了 Gossip 協定,該協定的訊息傳輸方式就如同八卦,一傳十,十傳百,百傳千。

舉例來說,當 Server A 發現 Server B 有異樣的時候,Server A 不會馬上告訴 Cluster 中的所有人,而是先告訴自己附近的人:「欸欸,Server B 好像怪怪的欸,我一直按門鈴他都沒回應,」這時候收到這個訊息的其他人,會在把這個訊息推播給附近的人,達到最終一制性,雖然沒辦法立即一致,但好處是他不要求 Cluster 中每個 Node 都要彼此建立連線,當 Node 變多時,複雜性不會變高。

  • 問題二:將資料分散在不同 Server 的同時,Client 端如何不透過中心化的 Proxy Server 來讀寫 Redis 資料?
    既然 Cluster 之間是 P2P 的網路,那 Client 是否可以只透過 Cluster 中隨便一個 Server 就對整個 Cluster 的資料做讀寫,而不用額外弄一個中心化的 Proxy勒?沒問題,Redis 都幫你想好了!

首先介紹 Redis 將資料分散到不同 Server 的方式,Hash Slot,你可以把他想像成多個抽屜 (Slot),每個抽屜有一個編號 (Redis 提供 0~16383 ),而透過 Hash Function 可以把資料分配到不同的抽屜 (Slot)。

由於 Redis 是 Key-Value 的儲存結構,每筆資料都有 Key 作為 Index,當我們把這個 Key 丟進一個 Hash Function (e.g CRC16) 就會出現一個 Hash Number,然後我們在把這個 Hash Number % 16384,就會得到該資料屬於的抽屜編號了

在 Redis Cluster 初始化的時候,Redis 本人會問你說,有哪些 Server 要加進來,然後他會告訴你哪些 Server 負責哪些 Slot,並同步該資訊到每個 Server ,也就是說當 Client 拿著一個 Key 隨便問 Cluster 中的 Server 時,該 Server 只要執行

HASH_SLOT = CRC16(key) mod 16384
他就會知道該 Key 的 Slot ,最後在跟 Client 說,這個 Slot 的負責人是 XXX,你去問他 (有沒有很像政府單位在踢皮球)。

  • 問題三:當某台 Redis Server 掛點時,Cluster 如何讓 Client 端幾乎沒有任何等待也能讀寫到掛點 Server 的資料?
    樹大必有枯枝,Server 多必有 Crush ,為了保證某個 Server 掛點時,他裡面的資料不僅不會遺失,還能讓 Client 繼續讀寫,Redis 採用了~~~ (給你想三秒),沒錯 Master-Slave 的架構,這裡的 Master-Slave 不僅可以提供讀寫分離的功能,還自帶 Fail-Over,當 Master 掛點時,Slave 會自動補上。

Redis Cluster 中可以有多台 Master, Master負責 Hash Slot 的讀寫,而一個 Master 可以有一個到多個 Slave,Slave 主要負責備份以及讀取資料。

然而 Redis 的 Master-Slave 採用異步 Sync 的方式,所以有可能你剛寫進 Master 的資料還沒同步給 Slave 時,Master 就掛了,雖然說這是為了效能考量,畢竟如果你每次寫入都要等 Master 同步完 Slave 那就等於多了一層 Network 傳輸的時間,但 Redis 還是提供了一些方法讓你的寫入更加可靠。

  • 方法一:使用 WAIT Command,在下完寫入指令後,可以連帶使用 WAIT 指令,參數帶 Slave 的數量以及 timeout 的時間,來等待 Master 確實收到 Slave 同步完資料的 ACK 。貼心提醒,在寫入後接 WAIT 指令時可以使用 MULTI EXEC 將兩個指令封裝在一個 transaction 內。

  • 方法二:cluster-node-timeout & cluster-slave-validity-factor 設定,有時候 Client 一個衰,會把寫資料到一個已經脫離 Cluster 的 Server 上,cluster-node-timeout 參數設定一個 Server 無法被其他 Server Reach 多長時間後就要被 Slave 替代,也就說設定越短的 node-timeout,Client 衰的機率越低,此外,在選擇替代的 Slave 也要選靠譜一點的,可不能選到某個 Slave 跟 Master 的連線不穩定,導致很多資料都沒同步到,於是 cluster-slave-validity-factor 可用來診斷一個 Slave 是否有資格成為 Master,如果一個 Slave 與 Master 之間 timeout 的時間大於cluster-slave-validity-factor * cluster-node-timeout ,拍謝,該 Slave 就從 Master 的候選人名單排除。

總結

Redis Cluster 中 Server 透過 Gossip 協定來了解彼此的狀況,如果發生任何問題,要做對應的處理,例如當發現某台 Server 掛點,要選出他某個 Slave 來替代他。
Redis Cluster 透過 Hash Slot 方式將不同 Key 的資料經過 Hash Function 分配到不同的 Slot,而不同的 Slot 會在 Cluster 初始化時,分配給不同 Server,Client 可以透過 Cluster 中隨便一台 Server 來知道資料讀寫的位置。
Redis Cluster 提供 Master-Slave 架構,不僅可讀寫分離還可以 Fail-Over 提供資料可用性,但要小心資料還沒 Sync 到 Slave,Master 就掛掉的問題。

Redis Cluster 是 Redis 數據庫的一種分布式部署方式,它允許你將數據分散存儲在多個 Redis 節點上,以提高性能、擴展性和高可用性。Redis Cluster 的中文名稱是 "Redis 集群"。

在 Redis 集群中,數據被分成多個部分,每一部分稱為一個 "槽"。這些槽可以分布在不同的 Redis 節點上。這樣的分布式存儲方式有助於均衡負載和提高系統的處理能力。Redis 集群還支持數據的覆制,每個槽的數據可以在多個節點之間覆制,以確保數據的可靠性和高可用性。

Redis Cluster的關鍵特點包括:

  1. 數據分片:數據分散存儲在多個節點上,允許處理大量數據。

  2. 主從覆制:每個槽有一個主節點和一個或多個從節點,主節點負責處理寫入操作,從節點負責覆制主節點的數據並處理讀取操作。

  3. 節點發現:Redis Cluster可以自動跟蹤節點的狀態和位置,以便客戶端知道從哪個節點獲取數據。

  4. 故障轉移:如果主節點發生故障,Redis Cluster可以自動將一個從節點升級為新的主節點,確保系統的可用性。

  5. 數據覆制:數據在主節點和從節點之間進行異步覆制,以保持數據的一致性和可靠性。

  6. 客戶端支持:大多數 Redis 客戶端庫都支持 Redis Cluster,可以自動處理節點發現和請求路由,使開發者無需手動管理集群的覆雜性。

Redis Cluster是處理大規模數據存儲和高並發訪問的理想選擇,因為它提供了水平擴展性和高可用性。但需要注意的是,配置和管理 Redis 集群可能需要一些覆雜性,因此在生產環境中使用 Redis Cluster時需要仔細考慮配置和監控的需求。

Master-Slave Replication

引用:https://ithelp.ithome.com.tw/m/articles/10267454

藉由主從複製將數據從主庫(Master)複製到1至多台從服務器(Slave),達到主從數據一致,增加數據可用性。

因為資料是一致的所以相當於多一個備用系統能在發生單點故障問題時或實務應用查詢資料上使用。

採數據讀寫分離,所有寫入更新異動操作皆由主庫(Master)執行,而讀取相關的撈資料語法轉至從庫(Slave)執行

與哨兵最大的差別在於監控、推選、通知

Redis : 五大資料型別

Redis 中主要的資料型別有 String、List、Set、Hash、Sorted Set

# String
String 是 Redis 中最基礎的資料型別,透過 binary 形式儲存,且保證不更改資料內容
(binary-safe),因此 String 可儲存任何資料,例如一般字串,數字,檔案以及序列化後的
物件等。

#List 

List 是由多個 redis 的 String 所組成,List 中成員會依照插入的順序儲存,其提供由頭尾
插入,以及頭尾拿出的功能,List 能實作的功能很多,例如任務隊列,以及優先權隊列等。

#Set

Set 是多個 Redis 中 String 以無序的方式所組成,其保證內部不會有重複的元素,此外Redis
提供了多個 Set 之間交集,差集,聯集的操作。

#Hash
Hash 是 key-value 的資料類型,也是 Redis 的主結構,非常適合用於儲存物件型資料,例如
User物件有姓名,年齡,信箱等。當物件很小時,Hash 會將資料壓縮後儲存,因此單台Redis
可以儲存數百萬個小物件。

#Sorted Set
Sorted Set 是有序的 Set,其順序會依照給定的權重值排序,由於資料使排序好的,在查找資料
時,可使用 binary search,因此查找效率高。由於 Sorted Set 的高查詢效能,
Sorted Set可當作一組 Hash 資料的 index,將物件 id 以及 index field 儲存在
Sorted Set,單筆物件的完整資料儲存在 Hash。


#geo
![](https://hackmd.io/_uploads/H1ame9nph.png)

#hyperloglog

#bitmap


什麼是哨兵模式

資料來源
在實際生產環境中,服務器難免會遇到一些突發狀況:服務器宕機,停電,硬件損壞等等,一旦發生,後果不堪設想。
哨兵模式的核心還是主從模式的演變,只不過相對於主從模式在主節點宕機導致不可寫的情況下,多了探活,以及競選機制:從所有的從節點競選出新的主節點,然後自動切換。競選機制的實現,是依賴於在系統中啟動sentinel進程,對各個服務器進行監控。如下圖所示:

哨兵模式的主要職責

要讓Redis服務實現故障自動切換會有很多細節需要考慮,比如:

  • 判定節點故障的條件是什麼,有沒有可能是假死或者響應延遲。
  • 既然是競選機制,那麼所有slave節點都可以參與競爭,也都有機會成為master。選擇哪個slave成為master是關鍵。
  • 競選出新的master,其他slave需要從新的master中replicaof,所以消息通知和通信也是核心。

哨兵作為Redis 的一種運行模式,專注於對Redis 實例(master、slaves)運行狀態進行監控,並能夠在主節點發生故障時通過一系列的操作,實現新的master競選、主從切換、故障轉移,確保整個Redis 服務的可用性。
所以,哨兵的能力至少應該包含如下幾點:

  1. 監控:持續監控master 、slave 是否健康,是否處於預期工作狀態。
  2. 主從動態切換:當Master 運行故障,哨兵啟動自動故障恢復流程:從slave 中選擇一台作為新master。
  3. 通知機制:競選出新的master之後,通知客戶端與新master 建立連接;slave 從新的master 中replicaof,保障主從數據的一致性。

1.哨兵模式啟用的時候,會同步啟用叫做Sentinel的進程。sentinel程會向所有的master 和slaves 以及其他sentinel進程發送心跳包(1s一次),看看是否正常返迴響應。

  • 如果slave 沒有在規定的時間內響應sentinel 的PING 命令, sentinel 會認為該實例已經掛了,將它tag為:下線狀態;
  • 同理,如果master 沒有在規定時間響應sentinel 的PING 命令,也會被判定為offline 狀態,只是會多做一步自動切換master 的流程。

PING 命令的回復有兩種情況:

有效回复:返回+PONG、-LOADING、-MASTERDOWN 任何一種;
無效回复:有效回復之外的回复,或者指定時間內返回任何回复。

但是可能存在一些誤判的情況,比如說網絡擁塞、master實例假死、請求延遲,導致實例在某個短暫時間段不可用,後續又快速恢復了。
如果這時候被我們主動下線了,其實整個系統的可用性反而遭到了退化。而且誤判之後的一系列操作,master競選、消息通知,slave 與新master 同步數據,都會消耗大量資源。所以,誤判要不得啊。
為了保證判斷的可靠性,我們對下線的標識做了區分:
一種是主觀下線,一種是客觀下線。

  • 主觀下線
    哨兵利用PING 命令來監測master、 slave 實例節點的生命狀態。如果是無效回复,哨兵就把這個實例節點標記為主觀下線。如果是slave,一般是有多從概念,直接下線即可,但如果是master,就要小心了。一個人sentinel容易誤判,那就多個sentinel進投票裁決。哨兵機制就是這樣的,採用多個實例組成sentinel集群模式進行部署,即哨兵集群。多個哨兵實例一起來判斷,就可以避免單個哨兵因為自身網絡狀況不好,而誤判主庫下線的情況。
    同時,多個哨兵的網絡同時不穩定的概率較小,由它們一起做決策,誤判率也能降低。
  • 客觀下線
    master 是否要下線不能是單個sentinel能夠決定的,上面說了我們一幫會有個sentinel集群,所以這個集群就發揮作用了,大家一起投票,超過一半的sentinel 都判斷了主觀下線,這時候我們就把master 標記為客觀下線,認為它是真的不行了。
    當master 被判定為客觀下線後,就算正式沒有master了,當務之急就是趕緊競選出一個新的master。
  • 如何區別主、客觀下線
    主觀下線是sentinel自己認為節點offline,這時候節點並不是真正的下線;而客觀下線是達到一定數量的哨兵(比如超過一半)都認為節點offline了,這時候會進一步觸發離線、重新競選主等一系列操作。

這裡的「一定數量」是一個法定數量(Quorum),是由哨兵監控配置決定的,解釋一下該配置:

# sentinel monitor <master-name> <master-host> <master-port> <quorum>
# 举例如下:
sentinel monitor mymaster 127.0.0.1 6379 2

這條配置項用於告知哨兵需要監聽的主節點:

  • sentinel monitor:代表監控。
  • mymaster:代表主節點的名稱,可以自定義。
  • 192.168.11.128:代表監控的主節點ip,6379 代表端口。
  • 2:法定數量,代表只有兩個或兩個以上的哨兵認為主節點不可用的時候,才會把master 設置為客觀下線狀態,然後進行failover 操作。

客觀下線的標準就是,當有N個哨兵實例時,要有N/2+1個實例判斷master 為主觀下線,才能最終判定master 為客觀下線,其實就是過半機制。

2.主從動態切換

sentinel 的一個很重要工作,就是從多個slave中選舉出一個新的master。當然,這個選舉的過程會比較嚴謹,需要通過篩選+ 綜合評估方式進行選舉:


篩選

  • 過濾掉不健康的(下線或者斷線),沒有回复哨兵ping響應的從節點。
  • 評估實例過往的網絡連接狀況down-after-milliseconds,如果一定週期內(如24h)從庫和主庫經常斷連,而且超出了一定的閾值(如10 次),則該slave不予考慮。

綜合評估
篩選掉不健康的實例之後,我們就可以對於剩下健康的實例按順序進行綜合評估了。

  • slave 優先級,通過slave-priority 配置項(redis.conf),可以給不同的從庫設置不同優先級,優先級高的優先成為master。
  • 選擇數據偏移量差距最小的,即slave_repl_offset與master_repl_offset進度差距,其實就是比較slave 與原master 複製進度差距。
  • slave runID,在優先級和復制進度都相同的情況下,選用runID最好的,runID越小說明創建時間越早,優先選為master。先來後到原則。
    等這幾個條件都評估完,我們就會選擇出最適合slave,把他推舉為新的master。

3.信息通知
等推選出最新的master之後,後續所有的寫操作都會進入這個master中。所以需要盡快通知到所有的slave,讓他們重新replacaof 到master上,重新建立runID和slave_repl_offset ,來保證數據的正常傳輸和主從一致性。如下圖所示: