Redis 研究筆記
Overview
open source
in-memory data store
cache
streaming engine
message broker
Clustering / High availability
TLS/SSL 連線
Use cases
Real-time data store 即時數據存儲
Caching & session storage 緩存和會話存儲
Streaming & messaging 串流媒體和訊息傳遞
小評: Redis 支援多種資料結構,不同功能述求用不同資料結構來實現。
以功能面談 Redis
Redis
vs Redis Stack
Redis
vs Redis Stack
(來自AI)
關於Redis和Redis Stack的主要區別,可以這樣對比:
開源程度
Redis是完全開源的資料庫軟件。
Redis Stack在Redis的基礎上開發,是部分開源的。
功能
Redis提供基礎的鍵值對資料庫功能。單一產品。
Redis Stack在Redis功能上擴充了模塊、管理工具等。包含 Redis、Kubernetes、Elasticsearch 和 Prometheus。
資料結構
Redis有字符串、哈希、列表、集合等資料結構。
Redis Stack添加了更多像數據流、搜索引擎等的資料結構。提供高可用性、安全性和可擴展性。可用於構建和管理複雜的應用程式。
商業支持
Redis主要由開源社區驅動開發。
Redis Stack提供商業支持和服務。
運行環境
Redis可在各種環境中運行。
Redis Stack主要面向企業級產品環境。
總結來說,Redis Stack在Redis的基礎上做了擴展和商業化,提供更豐富的資料結構、功能和支援,更適合企業級產品使用。但Redis本身仍是開源免費的核心資料庫軟件。
Redis 和 Redis Stack 的首次發布時間如下:
Redis:
最初版本:2009年
穩定版1.0:2010年1月
Redis Stack:
最初發布:2021年11月
可以看到,Redis已有10多年的開發歷史,是一個相當成熟和穩定的開源資料庫。
而Redis Stack則是在2021年底由Redis Labs公司基於Redis開發的新產品線和品牌。它在開源Redis的基礎上增加了更多的商業功能和服務。
所以Redis Stack可以看作是Redis的商業化版本或分支,目的是在企業級生產環境中提供更強大的Redis應用方案。它們都以開源Redis資料庫為基礎,但Redis Stack提供了更多高級功能。

前述提到的 Redis Use Case: Caching & session storage、 Streaming & messaging 用
Redis
版本就可實現。
About Redis Stack https://redis.io/docs/about/about-stack/
Redis license
官網說明: https://redis.io/docs/about/license/
Open Source 授權採 SSPL (Server Side Public License)。
只要用於商用就很模糊。
SSPL 授權並不被開源團體認可。
以產品面談 Redis
Redis 現在主要產品。
Redis
基本功能。前述提到的 Redis Use Case: Caching & session storage、 Streaming & messaging 用此版本就可實現。
可在 Docker Hub 找到官方版本並安裝。
單機非商用可免費使用。
不確定商用是否要付費?
Redis Stack
更多進階功能,GRAPH、JSON, Search and Query, Time Series, Probabilistic. 等等。
包含
RedisInsight
,Redis 的 GUI 管理工具。官方建議用於開發環境。
可在 Docker Hub 找到官方版本並安裝。
單機非商用可免費使用。
不確定商用是否要付費?
Redis Stack Server
功能與 Redis Stack 相同不過少了
RedisInsight
管理工具。官方建議用於正式環境。
可在 Docker Hub 找到官方版本並安裝。
單機非商用可免費使用。
不確定商用是否要付費?
是否支援 cluster 尚不確定?
Redis Enterprise Cloud / 企業版
AWS, Azure Cloud, Google Cloud
雲端、需付費
Redis 部署結構
(來自AI)
Redis 的典型部署結構主要有以下幾種:
單節點部署 最簡單的部署方式,將Redis單個實例運行在一台服務器上。適用於測試和小型項目。
主從複製(Replication) 使用一個主節點進行讀寫,多個從節點從主節點同步數據,形成主從結構。可以實現讀寫分離,提高讀取速度。
Sentinel (高可用) 使用Sentinel進行監控,當主節點故障時自動將從節點提升為主節點。實現高可用。
叢集(Cluster) 將數據分片到多個節點,每個節點負責部分數據。支援擴容。
多資料中心部署 跨多個資料中心部署Redis,同步數據。提高可用性和低延遲訪問。
雲服務 在公有雲上使用Redis雲服務,如AWS ElastiCache、阿里雲Redis等。
綜上所述,根據實際需求Redis可以部署為單節點或不同的分佈式結構,以實現擴展性、高可用性等目的。
Redis 資料結構
常用的 Redis
資料結構介紹
Redis
資料結構介紹(來自網路)
Redis提供了好幾種資料結構,比較常用到的是String、Hash、List、Set、SortedSet這5種,另外還有特殊用途的HyperLogLog及Geo。
String 是最簡單的Key/Value結構
Hash 是一種Map結構,以.Net來說就像是HashTable,一個Key底下可以存放N個Key/Value
List 跟.Net裡的List不一樣,是類似Queue或Stack的結構,以加入List的順序排序
Set 則是一種沒有排序的集合
SortedSet 是加上排序功能的Set,但跟List不一樣的是排序依給定的權重值來排
HyperLogLog 我個人覺得它有點不算是結構,應該算是一種演算法,用在個數估算用的
Geo 顧名思義,這是放經緯度的,可以拿來算2點之間的距離或是做跟地圖相關的應用
Bitmaps,Redis bitmap 实现了对二进制串的操作,可以对字符串的位进行操作。
推論
Redis Stack
提供的功能都是為特殊雲端應用進行存取加速的,暫時不研究Redis Stack
提供的資料結構。
安裝 / Docker
可單獨安裝在 Linux, MacOS 。
現在不支援在 Windows 單獨安裝,硬要裝的話也要基於 WSL 模擬 linux 執行環境再單獨安裝,這可以用在個人開發環境。
若要安裝在 Windows 建議還是安裝在 Docker 上。官方有在 Docker Hub
提供 Redis
, Redis Stack
, Redis Stack Server
三個版本。
參考文件
管理介面 redis-cli
Redis CLI
https://redis.io/docs/connect/cli/


管理介面 Redisinsight
Quick start using RedisInsight
https://redis.io/docs/interact/programmability/triggers-and-functions/quick_start_ri/
程式開發 C# / NRedisStack
NRedisStack
現在支援的程式語言:
C#/.NET、Go、Java、Node.js、Python
參考文件
程式開發 - 連線、基本指令與參數
using NRedisStack;
using NRedisStack.RedisStackCommands;
using StackExchange.Redis;
//## for Redis-Stack-Server,有支援帳密連線。
using var redis = ConnectionMultiplexer.Connect(new ConfigurationOptions
{
EndPoints = { { "localhost", 6379 } },
User = "default", // More info <https://redis.io/docs/management/security/acl/>
Password = "mypassword", // use your Redis password
Ssl = false,
SslProtocols = System.Security.Authentication.SslProtocols.Tls12,
AllowAdmin = true, // 啟動管理員模式。才可抓取 INFO 主機狀態值。
});
// 或
// for Redis,不需帳密就可連線
using var redis = ConnectionMultiplexer.Connect("localhost:6379", options => {
options.AllowAdmin = true; // 啟動管理員模式。才可抓取 INFO 主機狀態值。
});
IDatabase db = redis.GetDatabase();
// String 結構 ---------------------------------------
db.StringSet("foo", "我出運了", TimeSpan.FromSeconds(3));
//db.StringSet("baz", 9876543210.123456789m); // 不支援 deciaml
for (int i = 1; i <= 5; i++)
{
var value = db.StringGet("foo");
Console.WriteLine(value.HasValue ? value : "nil");
// 取值 也 取時效
var fooExpires = db.StringGetWithExpiry("foo");
Console.WriteLine($"{fooExpires.Value} | {fooExpires.Expiry}");
// 取值 並 重設時效
var fooExpires2 = db.StringGetSetExpiry("foo", TimeSpan.FromSeconds(3));
Console.WriteLine(fooExpires2.HasValue ? fooExpires2 : "nil");
// 移除
bool del_ret = db.KeyDelete("foo");
Console.WriteLine(del_ret);
System.Threading.SpinWait.SpinUntil(() => false, 1000);
}
// Hash 結構, 二層結構 ---------------------------------------
var hash = new HashEntry[] {
new HashEntry("name", "John"),
new HashEntry("surname", "Smith"),
new HashEntry("company", "Redis"),
new HashEntry("age", "29"),
new HashEntry("salary", "9876543210.123456789"),
};
db.HashSet("user-session:123", hash);
// 取 Hash 全部
var hashFields = db.HashGetAll("user-session:123");
Console.WriteLine(String.Join("; ", hashFields));
// 取 Hash 其中一個值
var hashValue = db.HashGet("user-session:123", "age");
Console.WriteLine(hashValue);
// Set 結構 ---------------------------------------
string mysetKey = "myset:123";
Console.WriteLine($"{db.KeyType(mysetKey)} | {db.KeyExists(mysetKey)}");
db.SetAdd(mysetKey, "我是字串", CommandFlags.FireAndForget);
db.SetAdd(mysetKey, 166888, CommandFlags.FireAndForget);
db.SetAdd(mysetKey, 889, CommandFlags.FireAndForget);
Console.WriteLine(db.SetPop(mysetKey)); // pop 一筆
Console.WriteLine(String.Join(", ", db.SetMembers(mysetKey))); // 列出全部
Console.WriteLine("§§ List (Queue/Stack) 結構 ---------------------------------------");
string mylistKey = "mylist:456";
db.ListLeftPush(mylistKey, "abc");
db.ListLeftPush(mylistKey, "走過路過別錯過。");
Console.WriteLine("§§ SortedSet 結構 ---------------------------------------");
string mysetKey2 = "myset:789";
db.SortedSetAdd(mysetKey2, "我是字串", 4);
db.SortedSetAdd(mysetKey2, 166888, 8);
db.SortedSetAdd(mysetKey2, 889, 6);
Console.WriteLine(db.SortedSetPop(mysetKey2)); // pop 一筆
Console.WriteLine(db.SortedSetPop(mysetKey2)); // pop 一筆
Console.WriteLine(db.SortedSetPop(mysetKey2)); // pop 一筆
Console.WriteLine("§§ Hyper Log Log 結構 ---------------------------------------");
// 估算大型數據集基數的場景,如:廣告點擊計數、唯一訪問者統計、按讚數等估算。
db.HyperLogLogAdd("likeCnt", "4");
db.HyperLogLogAdd("likeCnt", "5");
db.HyperLogLogAdd("likeCnt", "3");
Console.WriteLine($"likeCnt: {db.HyperLogLogLength("likeCnt")}"); // 按讚數
Console.WriteLine("§§ Geo 結構 -------------------------------------------");
db.GeoAdd("mygeokey", 111.11, 22.22, "某甲");
db.GeoAdd("mygeokey", 131.11, 52.22, "某乙");
var distance = db.GeoDistance("mygeokey", "某甲", "某乙");
Console.WriteLine($"{"某甲"}與{"某乙"}的距離有{distance}。");
計算 hit rate
// to connect
using var redis = ConnectionMultiplexer.Connect("localhost:6379", options => {
options.AllowAdmin = true; // 啟動管理員模式。才可抓取 INFO 主機狀態值。
});
var statsInfo = redis.GetServer("localhost:6379").Info("Stats")
.SelectMany(m => m.Select(c => c))
.ToDictionary(c => c.Key, c => c.Value);
long hits = long.Parse(statsInfo["keyspace_hits"]);
long misses = long.Parse(statsInfo["keyspace_misses"]);
long total = hits + misses;
double hitRate = (double)hits * 100.0d / (double)(total);
Console.WriteLine($"Hit Rate → {hits} / {total} = {hitRate:#.00}%");
Dump reids server all INFO
// to connect
using var redis = ConnectionMultiplexer.Connect("localhost:6379", options => {
options.AllowAdmin = true; // 啟動管理員模式。才可抓取 INFO 主機狀態值。
});
// get all INFO
var allInfos = redis.GetServer("localhost:6379").Info();
// dump
foreach (var info in allInfos)
foreach (var prop in info)
Console.WriteLine($"Dump redis info: {info.Key}: {prop.Key} => {prop.Value}");
完整程式碼
(EOF)
Last updated