---
# System prepended metadata

title: Redis

---

# Redis

## NoSQL (NOT only SQL)
NoSQL 的意思是它不僅僅是SQL，所以他可以做到類似SQL的關聯式結構，而redis的效能好的原因是他不需要依賴業務邏輯去儲存資料，而是以key and value方式，因為大大增加料的擴展能力，例如主從式架構，db資料的拷貝，相對SQL來說非常容易，但redis或是NOSQL還是有一些使用上的限制如下

* 不遵循SQL標準
* 不支持ACID
* 遠超過SQL的性能

這裡補充一下不支持ACID準則，不代表他無法做事務機制，redis之類的nosql還是有自己對應的事物操作。

[redis cheat sheet](https://quickref.me/redis.html)

## Server 演進

在 web 1.0時期屬於單體示架構，一台server對應一台db

![](https://i.imgur.com/HjrlA2q.png)

但隨著ap架構增長，單體是架構就會出現內存壓力與db io 壓力等問題

![](https://i.imgur.com/2lhEyfO.png)

而NoSQL目的就是要解決以上的壓力問題，以session為例子，以往我的的session需要拷貝到不同server上，這樣會造成，數據的冗余節點越多浪費更大，甚至多個節點你需要多個IO去拉取db來達到同步

![](https://i.imgur.com/l8dGfQT.png)

下圖就是透過NOSQL去同步多台server的session資料，減少資料拷貝次數，同時減少IO壓力，這也是NoSQl很常拿來做db cache的原因，無需透過IO操作就可以同步資料

![](https://i.imgur.com/9b6JjzN.png)

NoSQL也可以透過破壞一定程度的業務邏輯來達到性能的提升，目的其實就是減少IO

![](https://i.imgur.com/GfopLHM.png)



Redis 是一個開源的內存資料庫系統，支援多種資料結構（如字串、列表、哈希、集合、有序集合等）並提供高效的查詢和快速的讀寫性能。Redis 支援兩種不同的持久化方式，即 RDB（Redis Database）和 AOF（Append-Only File），它們各自有優點和缺點。

###  RDB 的優點：

效能較好：RDB 是一種快速且高效的持久化方式，它會將 Redis 的資料集快照存儲到磁碟上，並在需要的時候可以快速地恢復資料。這使得 RDB 在恢復大型資料集時非常快速，並且對於備份和複製資料庫也非常有效。

資料壓縮：RDB 支援資料壓縮，可以將資料集壓縮後存儲在磁碟上，節省了磁碟空間。

簡單：RDB 的配置和使用相對簡單，適合於快速設置和使用。

###  RDB 的缺點：

適合大型資料集的定期快照：RDB 使用的是定期快照的方式來保存資料，因此在發生故障時可能會損失最近的資料更新。

資料恢復時可能較慢：當資料集很大時，RDB 的資料恢復速度可能會比較慢，因為需要讀取整個快照並將其還原到內存中。

不適合高頻率的資料更新：如果資料集需要經常更新，那麼 RDB 的快照會比較頻繁，這可能會對系統的性能產生一些影響。

### AOF 的優點：

高可靠性：AOF 是一種寫日誌（Write-Ahead Log）的方式，它記錄了每一次對資料庫的寫操作，因此可以提供更高的資料可靠性，即使發生故障也可以輕鬆地從日誌中恢復資料。

恢復精確度高：由於 AOF 記錄了每一次寫操作，因此資料恢復時可以更加精確地還原資料的
狀態，避免了資料丟失的風險。

適合高頻率的資料更新：AOF 可以選擇不同的同步策略，包括每次寫操作都同步到磁碟，或者定期同步到磁碟，這使得 AOF 在高頻率的資料更新場景中更加適用，可以提供更好的資料一致性和持久性。

### AOF 的缺點：

效能較低：AOF 的寫入操作需要追加到日誌文件中，這會導致寫入操作的速度相對較慢，因此相較於 RDB，AOF 的效能可能會稍低。

文件大小較大：由於 AOF 需要記錄每一次寫操作，因此 AOF 文件的大小通常會比 RDB 文件的大小大，這會占用更多的磁碟空間。

恢復速度相對較慢：AOF 的資料恢復速度相對於 RDB 來說可能會比較慢，因為需要逐行解析並還原資料，尤其在資料集較大的情況下，恢復時間可能會較長。

綜合而言，RDB 適合對資料一致性要求不高、資料集較大且資料讀取比較頻繁的場景，而 AOF 適合對資料一致性要求較高、資料更新較為頻繁的場景。選擇哪種持久化方式應根據實際應用場景的需求來進行選擇。在某些情況下，也可以同時使用 RDB 和 AOF 來實現資料的雙重持久化，提供更高的資料保證和可靠性。
### zset

zset在redis是一個有序的集合，裡面的值不會重複，但對應到的score是可以的，適合用在做排行榜的資料。

```javascript
// zadd 新增key topn
redis > zadd topn 200 java 300 c++ 400 mysql 500 php

//列出所有內容
redis >  zrange topn 0 -1
1) "java"
2) "c++"
3) "mysql"
4) "php"

//列出前兩筆資料，排序是由小到大
redis > zrange topn 0 1
1) "java"
2) "c++"

//透過withscores 可以清楚看到值得大小
redis > zrange topn 0 2 withscores
1) "java"
2) "200"
3) "c++"
4) "300"
5) "mysql"
6) "400"

//可以看到在該範圍內的value
redis > zrangebyscore topn 100 200
1) "java"

//為key內部的value加值
redis > zincrby topn 50 java
"250"

//這時候value就改變了
redis > zrangebyscore topn 250 250
1) "java"

//刪除key成員
redis > zrem topn php 

//列出成員中value的範圍個數
redis > zcount topn 100 250
(integer) 1

//查看排名
redis > zrank topn php
(integer) 3


```

SortedSet (zset)底層結構類似為java Map<String,Double>，內部的元素value賦予一個權重score進行排序，透過map的hash關聯找到對應的值，達到快速查詢的效果


### redis many to many sample
hset 類似於 js object
sadd 類似於 js array
```javascript
# Here are my categories
> hset category:1 name cinema  ... more fields ...
> hset category:2 name music   ... more fields ...
> hset category:3 name sports  ... more fields ...
> hset category:4 name nature  ... more fields ...

# Here are my users
> hset user:1 name Jack   ... more fields ...
> hset user:2 name John   ... more fields ...
> hset user:3 name Julia  ... more fields ...

# Let's establish the many-to-many relationship
# Jack likes cinema and sports
# John likes music and nature
# Julia likes cinema, music and nature

# For each category, we keep a set of reference on the users
> sadd category:1:users 1 3
> sadd category:2:users 2 3
> sadd category:3:users 1
> sadd category:4:users 2 3

# For each user, we keep a set of reference on the categories
> sadd user:1:categories 1 3
> sadd user:2:categories 2 4
> sadd user:3:categories 1 2 4
```

```javascript
# Categories of Julia
> smembers user:3:categories
1) "1"
2) "2"
3) "4"

# Users interested by music
> smembers category:2:users
1) "2"
2) "3"

# Users interested by both music and cinema
> sinter category:1:users category:2:users
1) "3"
```

### redis 分布式存儲

#### 億萬級數據的數據存儲


當數據更多單一server勢必無法承受大規模的吞吐量，解決方式有二：

**垂直整合：** 

加大單一機台硬體設備效能，但肯定會有附載上限，例如 google 、 amazon 等這些大廠肯定背後不止一台 server 運行。

為了解決垂直整合的上限，這時就有分部式存儲觀念，分布式存儲就是實作 db 的 load balancer ，方法有以下三點：

**水平擴充：**
#### hash 取餘數

  用戶透過固定 hash 算法，% N台機器節點數量，計算hash 值將讀寫操作映射到相對的 redis server 身上，由於 redis key 是獨立的，這也確保每次的讀寫都是到特定的 server 中。
  
**優點：** 簡單快速達到負載均衡效果，只需劃分好機台數量。

**缺點：** 當單一機台掛掉或是增加機台，分母數量變化，原本選好的 server 位置將重新計算，資料可能會有缺失，甚至 db migrate 、集群擴縮容會因為server 掛掉導致數據不一致與資料遺失而產生實作問題。

#### 一致性 hash
    目的是當服務器數量發生變化，勁量減少影響客戶端到服務器的映射關係，解決hash 取餘 server 節點掛掉資料遺失問題，以及節點數量變化的數據遷移。
    
一致性 hash 算法不同於 hash 取餘根據 server 節點數量外，是透過將 hash算法擴大至 0 ~2^32 首尾相連的原型數據，並根據 hash 結果找到最接近的節點。為什麼是 2^32是因為 redis 理論上可以容納的最大節點數就是  2^32 。

![](https://hackmd.io/_uploads/ryUCoBmPh.png)

一致性 hash 可以夠過 ip 地址換算找到對應的節點位置，找到 key hash 位置，key 落點的位置順時針走遇到的第一個 server 位置就是要存儲的地方

**優點：**
    server 掛掉並不會導致所有節點位置都需要重算，增加server容錯率跟擴展性，例如服務器２掛掉，那剩下的請求將會順時針改存儲到服務器3，影響的數據只會是服務器２跟服務器３的資料，其餘都是正常。
    
**缺點：**
    數據傾斜問題，你會發現 c-b 之間位置較大，這時 c server可以要處理更多請求，導致 c server需要應付更多的吞吐量。
    
![](https://hackmd.io/_uploads/HyYJpBXDh.png)

    
![](https://hackmd.io/_uploads/rkixiHmw2.png)


### hash slot 分配
在數據跟節點之間多了一個中介層，用於數據分配，一個集群最多有 16384個 slot 默認，redis 集群式透過 hash slot 去分配數據而不是用一致性 hash，解決數據傾斜問題，原本在一致性 hash 算法中的落點在hash slot 中的slot。

![](https://hackmd.io/_uploads/Syumx8mwn.png)
