Redis詳解


Redis詳解

什么是Redis

Redis是一個開源的,內存數據庫,它可以作為數據庫、緩存和消息中間件。它支持多種類型的數據結構。如字符串string、散列hash、列表list、集合set、有序集合zset。Redsi還支持事務和不同級別的持久化操作。

各種數據類型 應用場景

# 五種數據類型
這里的數據類型我們統一認為是值得value,因為key都是string
## string
這個類型是最常用的一個類型,Redis的String類型每個key可以存儲512MB的數據。不要看type為String,其實它還可以存儲數字等各種java類型,甚至是序列化的對象、圖片、json字符串等。

通過string類型,我們可以設計出計數器、點贊、分布式鎖、對象存儲(序列化或者json)等。
## hash
存儲一個一個map,可以存在多個key-value。可以通過這個存儲一些沒有序列化的對象。可以實現保存用戶狀態,設置一個過期時間即可。
## list
List是一個基本類型,根據它的lpush、rpush,等命令可以實現出隊列、棧等數據結構。利用這些數據結構的特點幫我我們解決很多問題。
## set
這就類似於我們java中的set,它的內容不會重復,可以關注列表等。
## zset
比set多了一個排序規則,可以使用它做排行榜,它有一個top命令,可以取出前N個。

# 三大特殊類型

## 坐標geospatial
記錄一組經緯度,可以方便的計算兩個經緯度之間的位置,附近的人等等。
## 並集Hyperloglog
可以存儲2^64個元素的集合,可以很方便的計算並集
## 位圖bitmaps
存儲二進制位0和1 可以存儲多個0 1 ,結合數據字典可以實現很多業務。例如統計每周打卡天數,每月簽到次數等

Redis為什么是單線程 單線程還這么快?

# 為啥是單線程的?
因為Redsi官方說,Redis的性能瓶頸不在CPU,它對CPU的需求比較低。另外使用多線程還會涉及到很多的問題。Redis的瓶頸在網絡帶寬和內存大小上。

# 單線程還這么快?
1、純內存操作
2、非阻塞IO+多路復用機制
3、單線程避免頻繁切換上下文

Redis中的事務

# redis中的事務
Redis事務的本質:一組命令的集合,一個事務中的所有命令都會被序列化,在事務執行過程中,會按照順序執行。

**redis中的單條事務是有原子性的,但是redis中的事務是不保證原子性的。**
**redis中的事務沒有隔離級別的概念,所有的命令在事務中,並沒有被執行,只有發起命令時,才會被執行**

## redis的事務:
----- 隊列 set set set 執行 -----
- 開啟事務(multi)
- 命令入隊(set key val... set key2 val2...)
- 執行事務(exec) OR - 取消事務(discard)
當執行exec后,事務中的操作將有序的進行。取消事務后隊列中的代碼都不會被執行。當事務exec或者discard后就代表此次事務執行完畢了。

## 事務何時會失敗?
當隊列中存在編譯時異常, 事務中所有的命令都不會執行(例如:使用了錯誤的命令導致redis報錯)。如果出現運行時異常,除了出錯部分,其他的仍然會被執行(例如:給字符串incr)。

## 樂觀鎖和悲觀鎖
所謂悲觀鎖,就是認為無論什么時候都會出問題,任何操作都會加鎖。所謂樂觀鎖就是認為任何情況都不會出問題。所有操作都不會加鎖。
但是樂觀鎖會在更新之前查詢一下version字段的值,修改的時候判斷一下在此期間是否有人修改過數據。  

## watch監控版本
redis可以實現樂觀鎖,通過watch來監控。
在redis中實現樂觀鎖的方法非常的簡單,在事務之前加上watch key即可
例如:
version : 10
watch version
multi
set version 11
set key val...
exec
此時可以正常執行成功,

但是如果在此期間,有其他線程修改了version就無法執行事務。

RDB AOF

# Redis持久化
redis是一個內存數據庫,意味着斷電丟失。所以它的持久化是非常有必要的。Redis中提供了兩種持久化方式,RDB和AOF。默認的配置會保存在redis的data目錄中,rdb保存在dump.rdb中,aof存在appendonly.aof中

## RDB快照
所謂RDB就是在一段時間內將內存中的數據快照寫入磁盤,也就是所謂的snapshot(快照)。恢復時,從快照中將數據恢復至內存中。
在redis的配置文件中存在如下配置
save 900 1
save 300 10
save 60 100000
也就是說,在900S內只要有一次修改操作,300秒內發生10次修改操作,60秒內發生10000此修改該做就會觸發RDB操作。

RDB的優勢:文件保存的完整、恢復快。

## AOF日志
每次操作都會被立即記錄到磁盤中,性能差但是數據保存的十分完整。它有三種觸發機制,主要是兩種吧,一個是每秒保存,另一種是每次保存。優點:AOP比RDB更加可靠,一般AOF每隔一秒通過一個后台線程執行一次fsync操作,最多丟失1秒的數據。而且AOP還可以進行災難恢復,如果不小寫使用了flushall清空了所有數據,也可以通過AOF來恢復。缺點就是AOF的文件會很大。

穿透 雪崩

# 為什么要用緩存?
當一個數據的訪問量非常高頻的時候,會對數據庫造成巨大的壓力。所以我們引入了緩存的概念,當用戶需要操作DB之前,先判斷緩存中是否存在,如果存在就直接從緩存拿,沒有的話再查數據庫,再放入緩存一份。
那么此時如果緩存掛掉了,用戶的請求都直接訪問DB這將是災難性的。

# 什么是雪崩?
內存的價格是比較昂貴的,所以緩存中的數據會根據某些策略來設置過期時間,主要是惰性刪除和定期刪除兩種。如果緩存設置的過期時間是相同的,這段時間內會有大量的key過期,所有的請求都會跳過redis直接訪問DB,對DB造成大量的訪問。甚至會導致整個服務的癱瘓。這種現象就是Redis的雪崩。

## 如何防止雪崩?
上面我們說到,雪崩產生的原因和過期時間有關,那么我們解決了過期時間集中就可以了.
1、給緩存的過期時間加上一個隨機值,這樣就會大幅度的減少緩存在同一時間過期。
2、對於Redis癱瘓可以利用集群+哨兵

# 什么是穿透?
再來聊一種場景,例如現在緩存了100個用戶的信息,他們的id是1~100,那么當黑客請求id為-1的接口,就會導致直接去請求數據庫,並且再訪問數據庫之后不會將數據緩存到redis中。如果穿透發生了同樣會使得整個服務癱瘓。

## 如何防止穿透?
解決緩存穿透也有兩種方案
1、對於不合法的請求,可以使用過濾器提前攔截。不合法就不讓這個請求到達DAO層。
2、當數據不存在時,在緩存中緩存一個空對象。下次請求時,就可以從緩存中獲取啦,不過使用這種方法,一般都會設置一個比較短的過期時間。

如何保證Redis中數據和MySQL(OtherDB)的一致性

# 更新操作
一般來說,對於更新操作,我們會有兩種選擇:
1、先操作數據庫,再操作緩存
2、先操作緩存,在操作數據庫

首先我們要明確的時,無論我們先選擇哪個,我們都希望這兩個要么同時成功, 要么同時失敗,所以這就演變為了一個分布式事務的問題。

如果原子性被破壞了,可能會有以下的情況:
數據庫成功了,緩存操作失敗了
緩存操作成功了,數據庫操作失敗了

## 操作緩存
更新時,更新緩存也有兩種方案
1、更新緩存
2、刪除緩存
我們一般都是采用刪除緩存的策略,原因是更新更容易導致緩存與數據庫不一致的問題。

先刪除緩存,咋更新數據庫在高並發的情況下表現不是很好,先更新數據庫,再刪除緩存在高並發情況下表現更好,但是原子性容易被破壞。


集群 哨兵

所謂集群,就是通過增加服務器的數量,使得服務器達到一個穩定的、高可用的狀態。

單機的redis雖然提供了RDB+AOF的策略。但是如果Redis宕機,也是災難性的。為了提高redis的可用性,我們必須對他進行集群。

# 集群
部署多台Redis,有三種方案。twemproxy、codis、redis cluster3.0。這里不進行深入研究了。

## 主從復制
redis的集群中,每一個redis都稱之為節點
節點有兩種類型,主節點master和從節點slave
redis集群是基於redis主從復制實現的
只要網絡連接正常,master都會將自己的數據同步到slaves中,保持主從同步

## 節點特點
主節點可讀、可寫從節點只讀


## 哨兵
主從有一個弊端,就是當主節點掛了以后,整個集群就沒有主節點了。所以在這種設計模式下,又出現了哨兵的機制,哨兵的作用就是對一個或者多個Redis集群進行監控和提醒,當哨兵監控到主節點出現故障之后,就會通知其他節點開會,由這些節點投票選取票數最高者作為主節點。當選的從節點自動成為主節點。原master修復重新上線后會自動轉換為從節點。

分布式鎖

Redis為單進程單線程模式,采用隊列模式將並發訪問變成串行訪問,且多客戶端對Redis的連接並不存在競爭關系Redis中可以使用SETNX命令實現分布式鎖。
將 key 的值設為 value ,當且僅當 key 不存在。 若給定的 key 已經存在,則 SETNX 不做任何動作

解鎖:使用 del key 命令就能釋放鎖
解決死鎖:
1)通過Redis中expire()給鎖設定最大持有時間,如果超過,則Redis來幫我們釋放鎖。
2) 使用 setnx key “當前系統時間+鎖持有的時間”和getset key “當前系統時間+鎖持有的時間”組合的命令就可以實現。

SpringBoot中使用Redis

1、引入啟動器
2、配置類中初始化redisTemplate屬性
3、創建Redis工具類,封裝常用操作。由於工具類還是需要使用2,所以其也需要被Spring掃描。
4、注入工具類,使用~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM