Redis 作為一款高效能的記憶體資料函式庫,廣泛應用於各種場景,例如快取、排行榜、訊息佇列等。其豐富的資料結構和靈活的特性使其成為開發者的首選。理解 Redis 的核心架構和資料結構對於有效地運用 Redis 至關重要。本文將從資料持久化、叢集架構、基本資料結構等方面,逐步解析 Redis 的核心概念和應用技巧。同時,文章也提供了程式碼範例和圖表,方便讀者理解和實踐。對於想要深入學習 Redis 的開發者來說,本文將提供一個全面的入門。

第4章:入門 Redis

簡介

在前面的章節中,我們瞭解了 Redis 的歷史和 NoSQL 資料函式庫的基本概念。本章將探討 Redis 的基本概念和資料結構。

結構

本章將涵蓋以下主題:

  1. 核心架構
  2. 基本資料結構
    • 字串(Strings)
    • 點陣圖(Bitmaps)
    • 雜湊(Hashes)
    • 列表(Lists)
    • 集合(Sets)
    • 有序集合(Sorted Sets)
    • 地理空間索引(Geospatial index support)
    • HyperLogLog
    • Redis Streams

目標

透過本章的學習,您將瞭解 Redis 的資料結構和架構,並能夠開始使用 Redis。

核心架構

Redis 是一種根據鍵值對的資料函式庫,資料儲存在記憶體中,並支援資料持久化。Redis 採用客戶端-伺服器架構模型,所有資料都儲存在 Redis 伺服器上。客戶端透過傳送命令與伺服器互動。

Redis 的主要特點包括:

  1. 根據鍵值對:Redis 使用鍵值對來儲存資料。
  2. 記憶體資料函式庫:資料儲存在 RAM 中,提供高速存取。
  3. 用 C 語言編寫:Redis 使用 C 語言開發,具有高效能。

為什麼選擇記憶體資料函式庫?

記憶體資料函式庫將資料儲存在 RAM 中,這使得資料存取速度極快。然而,這也意味著需要考慮資料持久化的問題,以防止資料在應用程式結束時丟失。

Redis 提供了資料持久化的機制,確保資料不會因為應用程式結束而丟失。這使得 Redis 不僅僅是一個快取系統,而是一個完整的資料函式庫系統。

圖4.1:Redis 架構

Redis 遵循客戶端-伺服器架構模型。所有資料都儲存在 Redis 伺服器上,由客戶端傳送命令進行操作。伺服器負責資料的儲存和維護。

由於資料儲存在記憶體中,Redis 提供了快速的資料存取速度。同時,Redis 也支援資料持久化,確保資料的安全性。

程式碼範例:

// 簡單的Redis客戶端範例
#include <hiredis/hiredis.h>

int main() {
    // 連線到Redis伺服器
    redisContext *c = redisConnect("127.0.0.1", 6379);
    if (c == NULL || c->err) {
        printf("連線失敗: %s\n", c->errstr);
        return 1;
    }

    // 設定鍵值對
    redisReply *r = redisCommand(c, "SET %s %s", "key", "value");
    printf("設定結果: %s\n", r->str);
    freeReplyObject(r);

    // 取得鍵值對
    r = redisCommand(c, "GET %s", "key");
    printf("鍵值: %s\n", r->str);
    freeReplyObject(r);

    // 斷開連線
    redisFree(c);
    return 0;
}

內容解密:

此範例展示瞭如何使用 hiredis 函式庫連線到 Redis 伺服器,並進行簡單的鍵值對操作。首先,我們使用 redisConnect 連線到本地的 Redis 伺服器,然後使用 redisCommand 傳送 SET 和 GET 命令,最後使用 redisFree 釋放連線資源。

Redis 架構圖

  graph LR;
    A[客戶端] -->|傳送命令|> B(Redis 伺服器);
    B -->|儲存資料|> C[記憶體];
    B -->|持久化|> D[磁碟];
    C -->|讀取資料|> B;
    D -->|載入資料|> B;

圖表翻譯:

此圖表展示了 Redis 的基本架構。客戶端向 Redis 伺服器傳送命令,伺服器將資料儲存在記憶體中,並可選地將資料持久化到磁碟。伺服器從記憶體讀取資料,或從磁碟載入資料以還原狀態。

Redis 資料持久化與資料結構解析

Redis 是一個高效能的鍵值資料函式庫系統,其效能與易用性是其核心優勢。然而,作為一個根據 RAM 的資料函式庫,Redis 需要解決資料持久化的問題,以確保在系統故障時資料不會遺失。

Redis 資料持久化機制

Redis 提供了兩種主要的資料持久化模式:RDB(Redis Database File)檔案持久化和 AOF(Append Only File)檔案持久化。

RDB 檔案持久化

RDB 檔案是 Redis 中資料的快照,Redis 會定期將記憶體中的資料儲存到硬碟上的 RDB 檔案中。這種方法的優點是佔用較少的記憶體,但缺點是在發生故障時,可能會遺失最近一次快照之後的資料。

# RDB 檔案持久化範例組態
save 900 1  # 每 900 秒至少有 1 個 key 被修改則儲存
save 300 10  # 每 300 秒至少有 10 個 key 被修改則儲存
save 60 10000  # 每 60 秒至少有 10000 個 key 被修改則儲存

AOF 檔案持久化

AOF 持久化則是將所有的寫入操作記錄到檔案中,以確保資料的完整性。AOF 檔案通常比 RDB 檔案大,但可以提供更好的資料安全性。

# AOF 檔案持久化範例組態
appendonly yes  # 開啟 AOF 持久化
appendfsync everysec  # 每秒將寫入操作同步到 AOF 檔案

內容解密:

  • save 組態用於控制 RDB 快照的頻率。
  • appendonly yes 開啟 AOF 持久化功能。
  • appendfsync everysec 設定每秒同步一次寫入操作到 AOF 檔案,以平衡效能與資料安全性。

Redis 資料分片與叢集架構

當單一 Redis 例項的記憶體無法容納所有資料時,可以使用 Redis 分片(Sharding)技術,將資料分散到多個 Redis 節點上,形成叢集架構。

  graph LR;
    A[Client] --> B[Redis Cluster];
    B --> C[Redis Node 1];
    B --> D[Redis Node 2];
    B --> E[Redis Node 3];
    B --> F[Redis Node 4];

圖表翻譯: 此圖示展示了 Redis 叢集架構,客戶端請求被分配到不同的 Redis 節點上,每個節點儲存部分資料。

Redis 基本資料結構

Redis 支援多種基本資料結構,包括字串(Strings)、雜湊(Hashes)、列表(Lists)、集合(Sets)和有序集合(Sorted Sets)。

字串(Strings)

字串是 Redis 中最基本的資料型別,可以儲存任何形式的資料,如 JSON 物件。

# 設定字串範例
import redis
r = redis.Redis(host='localhost', port=6379, db=0)
r.set('name', 'Hybrowlabs')

內容解密:

  • 使用 redis Python 客戶端連線到本地 Redis 伺服器。
  • r.set('name', 'Hybrowlabs') 將字串 'Hybrowlabs' 與鍵 'name' 相關聯。

位元圖(Bitmaps)

位元圖支援對字串進行位元操作,適用於需要進行位元級操作的場景。

# 位元圖操作範例
r.setbit('bitmap', 7, 1)  # 設定位元圖中第 7 位為 1

內容解密:

  • r.setbit('bitmap', 7, 1) 對鍵 'bitmap' 對應的字串的第 7 位進行設定。

雜湊(Hashes)

雜湊是一種鍵值對集合,適合用於儲存物件,如使用者資訊。

# 雜湊操作範例
r.hset('user', 'name', 'John')
r.hset('user', 'age', '30')

內容解密:

  • 使用 hset 方法將使用者資訊儲存到雜湊中。

列表(Lists)

列表是一種有序的字串集合,實作為連結串列,適合用於佇列或堆疊等場景。

# 列表操作範例
r.lpush('tasks', 'task1')
r.rpush('tasks', 'task2')

內容解密:

  • lpush 將元素新增到列表左端。
  • rpush 將元素新增到列表右端。

集合(Sets)

集合是一種無序且不重複的字串集合,支援集合運算,如並集、交集等。

# 集合操作範例
r.sadd('users', 'user1')
r.sadd('users', 'user2')

內容解密:

  • sadd 將元素新增到集合中。

有序集合(Sorted Sets)

有序集合是一種有序且不重複的字串集合,每個元素都有一個分數,用於排序。

# 有序集合操作範例
r.zadd('scores', {'user1': 100, 'user2': 90})

內容解密:

  • zadd 將元素及其分數新增到有序集合中。

Redis 資料結構與應用場景深度解析

在探討 Redis 的過程中,我們瞭解到 Redis 提供了多種資料結構以滿足不同的應用需求。除了常見的 String、Hashes、Bitmaps、List、Sets 等基本資料結構外,Redis 還提供了 Sorted Sets、HyperLogLog、Geospatial Indexes 和 Redis Streams 等進階資料結構。

Redis Sorted Sets:有序集合的應用

Redis Sorted Sets 是一種特殊的資料結構,它結合了 Set 的唯一性與 List 的有序性。在需要快速存取特定成員的情況下,Sorted Sets 是比 List 更合適的選擇。雖然在 Sorted Sets 中插入或刪除元素的時間複雜度為 O(N),但其提供了豐富的操作命令,使其在多種場景下具有極高的實用價值。

何時使用 Redis Sorted Sets?

  1. 排行榜(Leaderboards):Sorted Sets 非常適合用於實作排行榜功能,可以根據使用者的分數或其他指標進行排序。
  2. 問答列表(Q&A lists):許多問答平台,如 Stack Overflow,會使用 Sorted Sets 來儲存問題,並根據評分或投票數進行排序。

Sorted Sets 的優勢

  • 快速存取:能夠快速地根據成員的分數進行存取和排序。
  • 有序性:保持元素的有序性,方便進行範圍查詢。

Geospatial Index Support:地理空間索引支援

Redis 的 Geospatial Indexes 並不是一種獨立的資料結構,而是根據 Sorted Sets 實作的。透過使用 Geohash 演算法,將經緯度編碼為單一的分數,從而實作對地理位置資料的高效儲存和查詢。

實作邏輯

  1. Geohash 演算法:將經緯度轉換為一個單一的分數,使得地理位置資料能夠被高效地索引和查詢。
  2. Sorted Sets 操作:利用 Sorted Sets 的命令對地理位置資料進行操作,如範圍查詢、附近位置查詢等。

HyperLogLog:基數估計的利器

HyperLogLog 是一種機率性資料結構,用於估計資料集中的唯一元素數量。它在犧牲一定精確度的情況下,極大地節省了記憶體空間。

何時使用 HyperLogLog?

  1. 快速估計唯一值數量:當需要快速估計資料集中的唯一值數量時,HyperLogLog 是一個理想的選擇。
  2. 記憶體敏感場景:在記憶體資源有限的環境下,HyperLogLog 可以提供一個相對準確的估計,同時節省大量記憶體。

Redis Streams:日誌資料結構的革新

Redis Streams 是 Redis 5.0 版本引入的一種新的資料結構,它是一種 append-only 的表格,支援多個消費者同時消費資料。與 Redis Pub/Sub 相比,Redis Streams 提供了更強大的功能和靈活性。

Redis Streams 的優勢

  1. 多消費者支援:支援多個消費者同時消費不同的資料部分。
  2. 持久化儲存:可以將事件資料儲存在記憶體中,適合用於訊息佇列、日誌彙總等場景。

何時使用 Redis Streams?

  1. 訊息佇列(Messaging):可以用於實作訊息佇列,支援多個生產者和消費者。
  2. 網頁活動追蹤(Web activity tracking):可以用於追蹤網頁使用者的活動。
  3. 日誌彙總(Log aggregation):可以用於彙總分散的日誌資料。
  4. 串流處理(Stream processing):支援對串流資料進行實時處理。

設定與組態 Redis 環境

在前一章節中,我們對 Redis 的核心架構和多種資料結構有了初步的瞭解。現在,我們將著手建立 Redis 環境,並對其進行組態,以滿足實際應用的需求。

Redis 環境安裝

Redis 支援多種作業系統,包括 Linux、BSD 和 macOS。對於 Windows 使用者,可以透過 Windows Subsystem for Linux (WSL) 或在雲端環境中安裝 Redis。

在 Ubuntu/Debian 上安裝 Redis

$ sudo apt update
$ sudo apt install redis-server

上述命令將從官方的 Ubuntu 套件倉函式庫下載並安裝 Redis 伺服器。

組態 Redis

Redis 的組態是透過一個名為 redis.conf 的檔案來完成的。該檔案包含了多種組態指令,用於控制 Redis 的行為。

編輯 redis.conf 檔案

$ sudo nano /etc/redis/redis.conf

redis.conf 檔案中,可以設定密碼、調整記憶體限制、組態持久化選項等。

設定密碼

requirepass "your-redis-db-password"

設定密碼後,所有連線到 Redis 的客戶端都需要進行身份驗證。

使用 systemd 管理 Redis 服務

在現代 Linux 發行版中,systemd 是預設的服務管理器。我們可以組態 systemd 以確保 Redis 服務在背景執行並在系統啟動時自動啟動。

$ sudo systemctl restart redis.service
$ sudo systemctl status redis

上述命令用於重啟 Redis 服務並檢查其狀態。

圖表翻譯:

此圖示展示了使用 systemd 管理 Redis 服務的流程,包括重啟服務和檢查服務狀態。

  graph LR;
    D[D]
    A[開始] --> B[重啟Redis服務];
    B --> C[檢查Redis服務狀態];
    C --> D{服務是否執行?};
    D -- 是 --> E[確認成功];
    D -- 否 --> F[排查錯誤];

內容解密:

上述Mermaid圖表展示了管理Redis服務的基本流程。首先,重啟Redis服務以應用任何組態變更。接著,檢查Redis服務的狀態,以確保其正常執行。如果服務執行正常,則確認成功;否則,需要進一步排查錯誤原因。

隨著對 Redis 的深入瞭解,我們將能夠更好地利用其強大的功能來滿足各種應用需求。在下一章節中,我們將進一步探討 Redis 的進階功能和最佳實踐,以充分發揮其潛力。

詳細程式碼範例與解析

以下是一個簡單的 Python 範例,展示如何使用 redis 套件連線到 Redis 資料函式庫並進行基本操作:

import redis

# 連線到Redis
client = redis.Redis(host='localhost', port=6379, db=0, password='your-redis-db-password')

# 設定一個鍵值對
client.set('key', 'value')

# 取得鍵的值
value = client.get('key')
print(value.decode('utf-8'))  # 輸出: value

# 使用Sorted Set
client.zadd('sorted_set', {'member1': 1, 'member2': 2})
# 取得Sorted Set中的成員
members = client.zrange('sorted_set', 0, -1, withscores=True)
print(members)  # 輸出: [('member1', 1.0), ('member2', 2.0)]

# 使用HyperLogLog
client.pfadd('hyperloglog', 'element1', 'element2')
# 取得HyperLogLog中的基數估計值
cardinality = client.pfcount('hyperloglog')
print(cardinality)  # 輸出: 2

內容解密:

此Python程式碼範例展示瞭如何使用redis套件與Redis資料函式庫進行互動。首先,建立了一個Redis客戶端例項,並連線到本地的Redis伺服器。然後,示範瞭如何設定和取得鍵值對、使用Sorted Set儲存和檢索成員,以及使用HyperLogLog進行基數估計。

圖表翻譯:

此圖示描述了Redis客戶端與伺服器之間的互動流程,包括連線建立、命令傳送和結果傳回。

  sequenceDiagram;
    participant Client as "Redis Client";
    participant Server as "Redis Server";
    Client->>Server: 連線請求;
    Server->>Client: 連線建立;
    Client->>Server: SET key value;
    Server->>Client: OK;
    Client->>Server: GET key;
    Server->>Client: value;

內容解密:

上述Mermaid序列圖展示了Redis客戶端與伺服器之間的典型互動流程。首先,客戶端發起連線請求,伺服器回應並建立連線。接著,客戶端傳送SET命令以設定鍵值對,伺服器傳回OK表示成功。隨後,客戶端傳送GET命令以取得鍵的值,伺服器傳回對應的值。