Try   HackMD

Redis了解與應用

tags: RD1
目錄

什麼是 Redis?

Redis是完全開源免費的,遵守BSD協議,是一個高性能的key-value數據庫。
Redis與其他key - value緩存產品有以下三個特點:

  1. Redis支持數據的持久化,可以將內存中的數據保持在磁盤中,重啟的時候可以再次加載進行使用。
  2. Redis不僅僅支持簡單的key-value類型的數據,同時還提供list,set,zset,hash等數據結構的存儲。
  3. Redis支持數據的備份,即master-slave模式的數據備份。

Redis數據類型

  1. String(字符串)二進制安全的意思是redis的string可以包含任何數據。比如jpg圖片或者序列化的對象。
    string類型是Redis最基本的數據類型,一個鍵最大能存儲512MB。
  2. Hash(哈希)
    Redis hash是一個鍵值對集合。
    Redis hash是一個string類型的field和value的映射表,hash特別適合用於存儲對象。每個hash可以存儲2^32 - 1鍵值對(40多億)。
  3. List(列表)
    Redis列表是簡單的字符串列表,按照插入順序排序。你可以添加一個元素導列表的頭部(左邊)或者尾部(右邊)。
  4. Set(集合)
    Redis的Set是string類型的無序集合。
    集合是通過哈希表實現的,所以添加,刪除,查找的複雜度都是O(1)。
  5. zset(sorted set:有序集合)
    Redis zset和set一樣也是string類型元素的集合,且不允許重複的成員。
    不同的是每個元素都會關聯一個double類型的分數。redis正是通過分數來為集合中的成員進行從小到大的排序。zset的成員是唯一的,但分數(score)卻可以重複。
    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

Redis與關聯式資料庫差異


SQL (關聯式) 與NoSQL (非關聯式) 資料庫的比較


幾十年來,用於開發應用程式的主要資料模型,均是諸如 Oracle、DB2、SQL Server、MySQL 和 PostgreSQL 等關聯式資料庫所採用的關聯式資料模型。一直到 2000 年中後期,其他資料模型才開始廣受採納和運用。為了區分和歸類這些新類型的資料庫和資料模組,因此創造了「NoSQL」這個名詞。「NoSQL」這個名詞常常與「非關聯式」互換使用。

雖然 NoSQL 資料類型多樣且功能各異,但您可從以下表格瞭解 SQL 和 NoSQL 資料庫的一些差異性




差異 關聯式資料庫 NoSQL 資料庫
最佳工作負載 關聯式資料庫專門用於交易性以及高度一致性的線上交易處理 (OLTP) 應用程式,並且非常適合於線上分析處理 (OLAP) 使用。 NoSQL 資料庫專門用於包含低延遲應用程式的多樣資料存取模式。NoSQL 搜尋資料庫專門用於進行半結構資料的分析。
資料模型 關聯式模型將資料標準化,成為由列和欄組成的表格。結構描述嚴格定義表格、列、欄、索引、表格之間的關係,以及其他資料庫元素。此類資料庫強化資料庫表格間的參考完整性。 NoSQL 資料庫提供鍵值、文件和圖形等多種資料模型,具有最佳化的效能與規模。
ACID 屬性 關聯式資料庫則提供單元性、一致性、隔離性和耐用性 (ACID) 的屬性
  • 單元性要求交易完整執行或完全不執行。
  • 一致性要求進行交易時資料就必須符合資料庫結構描述。
  • 隔離性要求並行的交易必須分開執行。
  • 耐用性要求從意外的系統故障還原成上個已知狀態的能力
  • NoSQL 資料庫通常透過鬆綁部分關聯式資料庫的 ACID 屬性來取捨,以達到能夠橫向擴展的更彈性化資料模型。這使得 NoSQL 資料庫成為橫向擴展超過單執行個體上限的高吞吐量、低延遲使用案例的最佳選擇
    效能 一般而言,效能取決於磁碟子系統。若要達到頂級效能,通常必須針對查詢、索引及表格結構進行優化。 效能通常會受到基礎硬體叢集大小、網路延遲,以及呼叫應用程式的影響。
    擴展 關聯式資料庫通常透過增加硬體運算能力向上擴展,或以新增唯讀工作負載複本的方式向外擴展。 NoSQL 資料庫通常可分割,因為存取模式可透過使用分散式架構來向外擴展,以近乎無限規模的方式提供一致效能來增加資料吞吐量。
    API 存放和擷取資料的請求是透過符合結構式查詢語言 (SQL) 的查詢進行通訊。這些查詢是由關聯式資料庫剖析和執行。 以物件為基礎的 API 讓應用程式開發人員可輕鬆存放和擷取資料結構。應用程式可透過分區索引鍵查詢鍵值組、欄集,或包含序列化應用程式物件與屬性的半結構化文件。

    SQL 與NoSQL 術語的比較

    SQL MongoDB Couchbase
    資料儲存貯體
    文件
    欄位
    主索引鍵 物件 ID 文件 ID
    索引 索引 索引
    檢視 檢視 檢視
    巢狀表格或物件 內嵌文件 對應
    陣列 陣列 清單

    由於 NoSQL 的種類很多,而技術的成熟度與使用場景不一,所以目前業界還是以 SQL 資料庫佔大多數。在 Stackoverflow 2018 年的調查結果,關聯式資料庫系統還是最多開發者使用的資料庫管理系統,佔前五名中的首四名!

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

    Redis 的優勢

    下方來源 Redis

    記憶體內資料存放區

    所有 Redis 資料都放在伺服器的主要記憶體內,與 PostgreSQL、Cassandra、MongoDB 和其他將大多數資料存放在磁碟或 SSD 的資料庫並不相同。使用傳統磁碟的資料庫需要在磁碟來回處理才能執行大多數的操作,而 Redis 這類記憶體內資料存放區則不受此限制。這樣它們便能夠支援更大規模的操作,而且回應時間更快。這項優勢提供超快速的效能,平均讀取和寫入操作時間低於一毫秒,並支援每秒百萬個操作。

    彈性的資料結構

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

    • 字串 – 文字或二進位資料,最大 512 MB
    • 清單 – 按新增順序排列的字串集合
    • 資料集 – 未排序的字串集合,可與其他資料集類型交叉、合併和區分
    • 排序資料集 – 依數值排列的資料集
    • 雜湊 – 存放欄位和值清單的資料結構
    • 點陣圖 – 提供位元層級操作的資料類型
    • HyperLogLogs – 用來評估資料集獨特項目的概率資料結構'

    Redis基本操作方法 常用指令

    下方指令來源 資料庫的好夥伴:Redis

    SET, GET

    redis> SET mykey "Hello"
    redis> GET mykey
    "Hello"
    

    前面有提到說 Redis 是一個 key-value pair 的資料庫,因此最簡單的 SET 就是設定某個 key 的值是多少,要取出來的話就用 GET 就好。

    INCR, DECR

    redis> SET mykey "10"
    redis> DECR mykey
    (integer) 9
    redis> INCR mykey
    (integer) 10
    

    顧名思義就是針對某個 key 加一或減一的意思,像是程式語言裡面的mykey++mykey--
    還有 INCRBYDECRBY,可以指定你要加減的數量是多少。

    HSET, HGET

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

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

    SADD, SCARD

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

    SADD 的 S 就是 Set 的意思,這邊的 Set 指的是資料結構學過的那個 Set,裡面不會有重複的內容,第二次插入的元素會被忽略。

    ZADD

    zadd key score member
    和 set 一樣是string類型元素的集合,不允許重複的key
    每個元素都會關聯一個 double 分數,會通過該分數為該集合排序

    127.0.0.1:6379> ZADD myset 0 hi
    (integer) 1
    127.0.0.1:6379> ZADD myset 1.3 hi
    (integer) 0
    127.0.0.1:6379> ZADD myset 1.3 hey
    (integer) 1
    127.0.0.1:6379> ZADD myset 22 fine
    (integer) 1
    127.0.0.1:6379> ZRANGEBYSCORE myset 0 20
    1) "hey"
    2) "hi"
    

    LPUSH, RPUSH, LSET, LRANGE

    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"
    

    這邊的資料結構是 List,你可以選擇從左邊或是右邊 push 值進去,對應到的指令就是 LPUSHRPUSHLSET 則是指定某個 index 的 value 是多少。

    LRANGE可以印出指定範圍的值,支援-1這種形式,表示最後一個值。

    hash (HMSET,HGET)

    hash 是 string 類型的 field-value 的映射表

    127.0.0.1:6379> HMSET myset time 20:00 des "hi" type 1
    OK
    127.0.0.1:6379> HGETALL myset
    1) "time"
    2) "20:00"
    3) "des"
    4) "hi"
    5) "type"
    6) "1"
    127.0.0.1:6379> HGET myset time
    "20:00"
    

    Redis Commander

    這裡我還沒看 先貼

    How To Configure Redis + Redis Commander + Docker

    redis-commander

    Redis與資料庫資料同步解決方案

    資料庫同步到Redis

    我們大多傾向於使用這種方式,也就是將資料庫中的變化同步到Redis,這種更加可靠。Redis在這裡只是做緩存。

    方案1

    做緩存,就要遵循緩存的語義規定:
    讀:讀緩存redis,沒有,讀mysql,並將mysql的值寫入到redis。
    寫:寫mysql,成功後,更新或者失效掉緩存redis中的值。

    對於一致性要求高的,從資料庫中讀,比如金融,交易等資料。其他的從Redis讀。

    這種方案的好處是由mysql,常規的關係型資料庫來保證持久化,一致性等,不容易出錯。

    方案2

    這裡還可以基於binlog使用mysql_udf_redis,將資料庫中的資料同步到Redis。

    但是很明顯的,這將整體的複雜性提高了,而且本來我們在系統代碼中能很輕易完成的功能,現在需要依賴第三方工具,而且系統的整個邊界擴大了,變得更加不穩定也不好管理了。

    Redis同步到資料庫

    也就是說將Redis中的資料變化同步到資料庫,那麼這裡是將Redis做為db,而真的db,資料庫只作為備份。(注意,這裡是一種不同看待事物的方式)。

    這樣做的好處是:大大減小了資料庫的壓力,但是用redis做內存資料庫,狀態很不穩定。

    雖然redis也有持久化機制,但是redis集群宕機後的重啟,資料加熱都很耗時。

    另一方面,隨著大量插入或者更新導致redis持久化操作會嚴重拖累作為內存KV資料庫的優勢。

    方案1

    將redis變更複制一份,丟到隊列中,給mysql消費。

    很明顯這種方案,只能保證最終一致性,而且變更資料複製,隊列維護,這些雜七雜八的東西太複雜,拋棄。

    具體做法是:寫redis時,同時將資料寫到redis維護的另外一個隊列中,但這樣又要增加內存消耗了。

    其實還有一種方式是使用redis的pipeline通知機制,但是redis是不保證的一定通知到的(得到被通知方的ack)。

    方案2

    定時刷新redis中的最新資料到mysql。

    很明顯的,無論定時任務的間距有多小,都會留下時間縫隙,如果發生宕機,故障等都會造成資料的不一致性。

    雖然可以通過:比較redis和資料庫中的資料,同步那些需要同步的變化資料,但是會加大計算量和程序的複雜度。

    參考資料

    該用 MySQL 或 MongoDB?選擇資料庫前你該了解的事

    什麼是 NoSQL?

    Redis

    SQL/NoSQL是什麼?認識資料庫管理系統DBMS

    10 分鐘徹底理解 Redis 的持久化和主從複製

    Redis 设计与实现-事务

    redis語法