Redis


1. 為啥在項目里要用緩存呢

用緩存,主要是倆用途,高性能和高並發

高性能

image.png
image.png

高並發
image.png
image.png

2.介紹

Redis 是一個開源的使用 ANSI C 語言編寫、遵守 BSD 協議、支持網絡、可基於內存亦可持久化的日志型、Key-Value 數據庫,並提供多種語言的 API的非關系型數據庫。

傳統數據庫(關系型數據庫)遵循 ACID 規則。而 Nosql(非關系型數據庫)(Not Only SQL 的縮寫,是對不同於傳統的關系型數據庫的數據庫管理系統的統稱) 一般為分布式,而分布式一般遵循 CAP 定理。

CAP理論

C:consistency(一致性)
A:avalibility(可用性)
P:Partition(分區)-tolerence to partition(分區容忍度)
分區:一個分布式系統,網絡不通訊,導致連接不通,系統被分割成幾個數據區域
原因:數據不連通了,產生數據分區

影響:
查還好一點
數據修改時,必須要求數據一致--加鎖,實現數據一致性【需求要求數據一致性】
數據修改時,可以數據不一致--不用加鎖【需求不要求數據一致性】

分區容忍度
數據的一致性要求高,容忍度高,加鎖
數據的一致性要求低,容忍度低,可以不加鎖
預期結果,保持數據的一致

可用性

請求在一定時間段內都應該有響應
為了解決鎖一直加着
CP理論:【一致性+分區】數據的一致性要求高-加鎖
AP理論:【可用性+分區】數據的一致性要求低-不加鎖

CAP總結
分區是常態,可不避免,三者不可共存
可用性和一致性是一對冤家
一致性高,可用性低
一致性低,可用性高

3. 為什么說redis能夠快速執行

  1. 絕大部分請求是純粹的內存操作(非常快速)
  2. 采用單線程,避免了不必要的上下文切換和競爭條件
  3. 非阻塞IO - IO多路復用

4. Redis支持的數據類型?

String字符串:
格式: set key value
string類型是二進制安全的。意思是redis的string可以包含任何數據。比如jpg圖片或者序列化的對象 。
string類型是Redis最基本的數據類型,一個鍵最大能存儲512MB。

Hash(哈希)
key=150
value={
“id”: 150,
“name”: “zhangsan”,
“age”: 20
}
hash類的數據結構,主要是用來存放一些對象,把一些簡單的對象給緩存起來,后續操作的時候,你可以直接僅僅修改這個對象中的某個字段的值
格式: hmset name key1 value1 key2 value2
Redis hash 是一個鍵值(key=>value)對集合。
Redis hash是一個string類型的field和value的映射表,hash特別適合用於存儲對象。

List(列表)
key=某大v
value=[zhangsan, lisi, wangwu]
比如可以通過list存儲一些列表型的數據結構,類似粉絲列表了、文章的評論列表了之類的東西
Redis 列表是簡單的字符串列表,按照插入順序排序。你可以添加一個元素到列表的頭部(左邊)或者尾部(右邊)
格式: lpush name value
在 key 對應 list 的頭部添加字符串元素
格式: rpush name value
在 key 對應 list 的尾部添加字符串元素
格式: lrem name index
key 對應 list 中刪除 count 個和 value 相同的元素
格式: llen name
返回 key 對應 list 的長度
Set(集合)
可以基於set玩兒交集、並集、差集的操作,比如交集吧,可以把兩個人的粉絲列表整一個交集,看看倆人的共同好友是誰
格式: sadd name value
Redis的Set是string類型的無序集合。
集合是通過哈希表實現的,所以添加,刪除,查找的復雜度都是O(1)。

zset(sorted set:有序集合)

格式: zadd name score value
Redis zset 和 set 一樣也是string類型元素的集合,且不允許重復的成員。
不同的是每個元素都會關聯一個double類型的分數。redis正是通過分數來為集合中的成員進行從小到大的排序。
zset的成員是唯一的,但分數(score)卻可以重復。
比如說你要是想根據時間對數據排序,那么可以寫入進去的時候用某個時間作為分數,人家自動給你按照時間排序了
排行榜:將每個用戶以及其對應的什么分數寫入進去,zadd board score username,接着zrevrange board 0 99,就可以獲取排名前100的用戶;zrank board username,可以看到用戶在排行榜里的排名

5.什么是Redis持久化?Redis有哪幾種持久化方式?優缺點是什么?

持久化就是把內存的數據寫到磁盤中去,防止服務宕機了內存數據丟失。
Redis 提供了兩種持久化方式:RDB(默認) 和AOF RDB內存快照和AOF日志文件
RDB(快照的方式):
生成一個文件,便於復制,移動,性能比較好
rdb是Redis DataBase縮寫
功能核心函數rdbSave(生成RDB文件)和rdbLoad(從文件加載內存)兩個函數
AOF:
Aof是Append-only file縮寫
每當執行服務器(定時)任務或者函數時flushAppendOnlyFile 函數都會被調用, 這個函數執行以下兩個工作

aof寫入保存:
WRITE:根據條件,將 aof_buf 中的緩存寫入到 AOF 文件
SAVE:根據條件,調用 fsync 或 fdatasync 函數,將 AOF 文件保存到磁盤中。
存儲結構:
內容是redis通訊協議(RESP )格式的命令文本存儲。
比較:
1、aof文件比rdb更新頻率高,優先使用aof還原數據。
2、aof比rdb更安全也更大
3、rdb性能比aof好
4、如果兩個都配了優先加載AOF

6. redis的底層數據結構

redis底層有6種數據結構,分別是簡單動態字符串(SDS),鏈表,字典,跳躍表,整數集合,壓縮列表。

跳躍表
Redis使用跳躍表作為有序集合鍵的底層實現之一,若一個有序集合包含的元素數量比較多,或者有序集合中的成員是比較長的字符串時,Redis就會使用跳躍表來作為有序集合鍵的底層實現。
有序集合使用兩種數據結構來實現,從而可以使插入和刪除操作達到O(log(N))的時間復雜度。這兩種數據結構是哈希表和跳躍表。向哈希表添加元素,用於將成員對象映射到分數;同時將該元素添加到跳躍表,以分數進行排序。
和鏈表、字典等數據結構被廣泛地應用在Redis內部不同,Redis只在兩個地方用到了跳躍表,一個是實現有序集合鍵,另一個是在集群結點中用作內部數據結構。除此之外,跳躍表在Redis里面沒有其他用途。
跳躍表(skiplist)是一種有序數據結構,它通過在每個節點中維持多個指向其他節點的指針,從而達到快速訪問節點的目的。跳躍表是一種隨機化的數據,跳躍表以有序的方式在層次化的鏈表中保存元素,效率和平衡樹媲美 ——查找、刪除、添加等操作都可以在對數期望時間下完成,並且比起平衡樹來說,跳躍表的實現要簡單直觀得多。
Redis 只在兩個地方用到了跳躍表,一個是實現有序集合鍵,另外一個是在集群節點中用作內部數據結構。

跳躍表的定義

image.png
image.png

我們先來看一下一整個跳躍表的完整結構:
     Redis 的跳躍表 主要由兩部分組成:zskiplist(鏈表)和zskiplistNode (節點)

7.使用redis有哪些好處?

(1) 速度快,因為數據存在內存中,類似於HashMap,HashMap的優勢就是查找和操作的時間復雜度都是O(1)
(2)支持豐富數據類型,支持string,list,set,sorted set,hash
(3) 支持事務,操作都是原子性,所謂的原子性就是對數據的更改要么全部執行,要么全部不執行
(4) 豐富的特性:可用於緩存,消息,按key設置過期時間,過期后將會自動刪除

8.redis的淘汰機制

Redis提供了下面幾種淘汰策略供用戶選擇,其中默認的策略為noeviction策略:
· noeviction:當內存使用達到閾值的時候,所有引起申請內存的命令會報錯。
· allkeys-lru:在主鍵空間中,優先移除最近未使用的key。
· volatile-lru:在設置了過期時間的鍵空間中,優先移除最近未使用的key。
· allkeys-random:在主鍵空間中,隨機移除某個key。
· volatile-random:在設置了過期時間的鍵空間中,隨機移除某個key。
· volatile-ttl:在設置了過期時間的鍵空間中,具有更早過期時間的key優先移除。

9.Master&Slave是什么?

也就是我們所說的主從復制,主機數據更新后根據配置和策略,自動同步到備機
的master/slaver機制,Master以寫為主,Slave以讀為主。

它能干嘛
1、讀寫分離;
2、容災恢復

哨兵監控
當master出現問題后,獎slaver切換為master

10. redis常見性能問題和解決方案

(1) Master最好不要做任何持久化工作,如RDB內存快照和AOF日志文件
(2) 如果數據比較重要,某個Slave開啟AOF備份數據,策略設置為每秒同步一次
(3) 為了主從復制的速度和連接的穩定性,Master和Slave最好在同一個局域網內
(4) 盡量避免在壓力很大的主庫上增加從庫
(5) 主從復制不要用圖狀結構,用單向鏈表結構更為穩定,即:Master <- Slave1 <- Slave2 <- Slave3…

這樣的結構方便解決單點故障問題,實現Slave對Master的替換。如果Master掛了,可以立刻啟用Slave1做Master,其他不變。

11.redis包含三種集群策略

1.主從復制: 在主從復制中,數據庫分為倆類,主數據庫(master)和從數據庫(slave)。
其中主從復制有如下特點:
1.1. 主數據庫可以進行讀寫操作,當讀寫操作導致數據變化時會自動將數據同步給從數據庫
1.2. 從數據庫一般都是只讀的,並且接收主數據庫同步過來的數據
1.3. 一個master可以擁有多個slave,但是一個slave只能對應一個master、

主從復制工作機制
當slave啟動后,主動向master發送SYNC命令。master接收到SYNC命令后在后台保存快照(RDB持久化)和緩存保存快照這 段時間的命令,然后將保存的快照文件和緩存的命令發送給slave。slave接收到快照文件和命令后加載快照文件和緩存的執行命令。

12. Redis 有哪些架構模式?講講各自的特點

單機版

image.png
image.png

|

特點:簡單
問題:
1、內存容量有限 2、處理能力有限 3、無法高可用。

主從復制

image.png
image.png

Redis 的復制(replication)功能允許用戶根據一個 Redis 服務器來創建任意多個該服務器的復制品,其中被復制的服務器為主服務器(master),而通過復制創建出來的服務器復制品則為從服務器(slave)。 只要主從服務器之間的網絡連接正常,主從服務器兩者會具有相同的數據,主服務器就會一直將發生在自己身上的數據更新同步 給從服務器,從而一直保證主從服務器的數據相同。

特點:
1、master/slave 角色
2、master/slave 數據相同
3、降低 master 讀壓力在轉交從庫
問題:
無法保證高可用
沒有解決 master 寫的壓力

哨兵

image.png
image.png

Redis sentinel 是一個分布式系統中監控 redis 主從服務器,並在主服務器下線時自動進行故障轉移。其中三個特性:

監控(Monitoring): Sentinel 會不斷地檢查你的主服務器和從服務器是否運作正常。
提醒(Notification): 當被監控的某個 Redis 服務器出現問題時, Sentinel 可以通過 API 向管理員或者其他應用程序發送通知。
自動故障遷移(Automatic failover): 當一個主服務器不能正常工作時, Sentinel 會開始一次自動故障遷移操作。

特點:
1、保證高可用
2、監控各個節點
3、自動故障遷移

缺點:主從模式,切換需要時間丟數據
沒有解決 master 寫的壓力

集群(proxy 型):

image.png
image.png

Twemproxy 是一個 Twitter 開源的一個 redis 和 memcache 快速/輕量級代理服務器; Twemproxy 是一個快速的單線程代理程序,支持 Memcached ASCII 協議和 redis 協議。

特點:
1、多種 hash 算法:MD5、CRC16、CRC32、CRC32a、hsieh、murmur、Jenkins
2、支持失敗節點自動刪除
3、后端 Sharding 分片邏輯對業務透明,業務方的讀寫方式和操作單個 Redis 一致

缺點:增加了新的 proxy,需要維護其高可用。
failover 邏輯需要自己實現,其本身不能支持故障的自動轉移可擴展性差,進行擴縮容都需要手動干預

集群(直連型):

image.png
image.png

從redis 3.0之后版本支持redis-cluster集群,Redis-Cluster采用無中心結構,每個節點保存數據和整個集群狀態,每個節點都和其他所有節點連接。

特點:
1、無中心架構(不存在哪個節點影響性能瓶頸),少了 proxy 層。
2、數據按照 slot 存儲分布在多個節點,節點間數據共享,可動態調整數據分布。
3、可擴展性,可線性擴展到 1000 個節點,節點可動態添加或刪除。
4、高可用性,部分節點不可用時,集群仍可用。通過增加 Slave 做備份數據副本
5、實現故障自動 failover,節點之間通過 gossip 協議交換狀態信息,用投票機制完成 Slave到 Master 的角色提升。

缺點:
1、資源隔離性較差,容易出現相互影響的情況。
2、數據通過異步復制,不保證數據的強一致性

13. 使用過Redis分布式鎖么,它是怎么實現的?

先拿setnx來爭搶鎖,搶到之后,再用expire給鎖加一個過期時間防止鎖忘記了釋放。
如果在setnx之后執行expire之前進程意外crash或者要重啟維護了,那會怎么樣?
set指令有非常復雜的參數,這個應該是可以同時把setnx和expire合成一條指令來用的!

緩存雪崩和緩存穿透問題解決方案

緩存雪崩
簡介:緩存同一時間大面積的失效,所以,后面的請求都會落到數據庫上,造成數據庫短時間內承受大量請求而崩掉。解決辦法(中華石杉老師在他的視頻中提到過,視頻地址在最后一個問題中有提到):
* 事前:盡量保證整個 redis 集群的高可用性,發現機器宕機盡快補上。選擇合適的內存淘汰策略。
* 事中:本地ehcache緩存 + hystrix限流&降級,避免MySQL崩掉
* 事后:利用 redis 持久化機制保存的數據盡快恢復緩存

Image.jpg
Image.jpg

緩存穿透
簡介:一般是黑客故意去請求緩存中不存在的數據,導致所有的請求都落到數據庫上,造成數據庫短時間內承受大量請求而崩掉。解決辦法: 有很多種方法可以有效地解決緩存穿透問題,最常見的則是采用布隆過濾器,將所有可能存在的數據哈希到一個足夠大的bitmap中,一個一定不存在的數據會被 這個bitmap攔截掉,從而避免了對底層存儲系統的查詢壓力。另外也有一個更為簡單粗暴的方法(我們采用的就是這種),如果一個查詢返回的數據為空(不管是數 據不存在,還是系統故障),我們仍然把這個空結果進行緩存,但它的過期時間會很短,最長不超過五分鍾。

如何解決 Redis 的並發競爭 Key 問題

所謂 Redis 的並發競爭 Key 的問題也就是多個系統同時對一個 key 進行操作,但是最后執行的順序和我們期望的順序不同,這樣也就導致了結果的不同!
推薦一種方案:分布式鎖(zookeeper 和 redis 都可以實現分布式鎖)。(如果不存在 Redis 的並發競爭 Key 問題,不要使用分布式鎖,這樣會影響性能)
基於zookeeper臨時有序節點可以實現的分布式鎖。大致思想為:每個客戶端對某個方法加鎖時,在zookeeper上的與該方法對應的指定節點的目錄下,生成一個唯一的瞬時有序節點。 判斷是否獲取鎖的方式很簡單,只需要判斷有序節點中序號最小的一個。 當釋放鎖的時候,只需將這個瞬時節點刪除即可。同時,其可以避免服務宕機導致的鎖無法釋放,而產生的死鎖問題。完成業務流程后,刪除對應的子節點釋放鎖。
在實踐中,當然是從以可靠性為主。所以首推Zookeeper。

如何保證緩存與數據庫雙寫時的數據一致性?

你只要用緩存,就可能會涉及到緩存與數據庫雙存儲雙寫,你只要是雙寫,就一定會有數據一致性的問題,那么你如何解決一致性問題?
一般來說,就是如果你的系統不是嚴格要求緩存+數據庫必須一致性的話,緩存可以稍微的跟數據庫偶爾有不一致的情況,最好不要做這個方案,讀請求和寫請求串行化,串到一個內存隊列里去,這樣就可以保證一定不會出現不一致的情況
串行化之后,就會導致系統的吞吐量會大幅度的降低,用比正常情況下多幾倍的機器去支撐線上的一個請求。

14. Springboot與redis的使用

1.

<!-- 引入redis依賴 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2.
然后,資源配置文件application.yml(或properties)中加入redis相關配置:

spring:
      redis:
        #redis數據庫地址
        host: localhost
       port: 6379
        password: root
        timeout: 1000
        #redis數據庫索引,默認0
       database: 1 


3.

這里我們引入了StringRedisTemplate類,這個類也是Java中整合Redis主要使用的操作類。這里首先使用MyBatis向數據庫添加一條user數據,如果添加成功,則使用StringRedisTemplate中的opsForValue.set()方法,將該user數據Json格式化后添加到Redis數據庫中,以"user : "+該user的id屬性值作為鍵

BoundHashOperations<StringObjectObject> hashOperations = this.stringRedisTemplate.boundHashOps(KEY_PREFIX);
//判斷是否存在此K值
if (hashOperations.hasKey(KEY_PREFIX)) {
hashOperations.delete(KEY_PREFIX);
}
seckillGoods.forEach(goods -> hashOperations.put(goods.getSkuId().toString(), goods.getStock().toString()));

}
redisTemplate.opsForValue().set("user : "+user.getUserId(), JsonUtils.objectToJson(user))

redisTemplate.opsForValue().get("user : "+userId)

15.Redis相比memcached有哪些優勢?

(1) memcached所有的值均是簡單的字符串,redis作為其替代者,支持更為豐富的數據類型
(2) redis的速度比memcached快很多
(3) redis可以持久化其數據
(4)Redis支持數據的備份,即master-slave模式的數據備份。


免責聲明!

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



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