1. 為啥在項目里要用緩存呢
用緩存,主要是倆用途,高性能和高并發(fā)
高性能
高并發(fā)
2.介紹
Redis 是一個開源的使用 ANSI C 語言編寫、遵守 BSD 協(xié)議吆豹、支持網(wǎng)絡、可基于內存亦可持久化的日志型理盆、Key-Value 數(shù)據(jù)庫痘煤,并提供多種語言的 API的非關系型數(shù)據(jù)庫。
傳統(tǒng)數(shù)據(jù)庫(關系型數(shù)據(jù)庫)遵循 ACID 規(guī)則猿规。而 Nosql(非關系型數(shù)據(jù)庫)(Not Only SQL 的縮寫衷快,是對不同于傳統(tǒng)的關系型數(shù)據(jù)庫的數(shù)據(jù)庫管理系統(tǒng)的統(tǒng)稱) 一般為分布式,而分布式一般遵循 CAP 定理姨俩。
CAP理論
C:consistency(一致性)
A:avalibility(可用性)
P:Partition(分區(qū))-tolerence to partition(分區(qū)容忍度)
分區(qū):一個分布式系統(tǒng)蘸拔,網(wǎng)絡不通訊,導致連接不通环葵,系統(tǒng)被分割成幾個數(shù)據(jù)區(qū)域
原因:數(shù)據(jù)不連通了调窍,產(chǎn)生數(shù)據(jù)分區(qū)
影響:
查還好一點
數(shù)據(jù)修改時,必須要求數(shù)據(jù)一致--加鎖张遭,實現(xiàn)數(shù)據(jù)一致性【需求要求數(shù)據(jù)一致性】
數(shù)據(jù)修改時邓萨,可以數(shù)據(jù)不一致--不用加鎖【需求不要求數(shù)據(jù)一致性】
分區(qū)容忍度
數(shù)據(jù)的一致性要求高,容忍度高,加鎖
數(shù)據(jù)的一致性要求低缔恳,容忍度低宝剖,可以不加鎖
預期結果,保持數(shù)據(jù)的一致
可用性
請求在一定時間段內都應該有響應
為了解決鎖一直加著
CP理論:【一致性+分區(qū)】數(shù)據(jù)的一致性要求高-加鎖
AP理論:【可用性+分區(qū)】數(shù)據(jù)的一致性要求低-不加鎖
CAP總結
分區(qū)是常態(tài)歉甚,可不避免万细,三者不可共存
可用性和一致性是一對冤家
一致性高,可用性低
一致性低纸泄,可用性高
3. 為什么說redis能夠快速執(zhí)行
- 絕大部分請求是純粹的內存操作(非忱党快速)
- 采用單線程,避免了不必要的上下文切換和競爭條件
- 非阻塞IO - IO多路復用
4. Redis支持的數(shù)據(jù)類型?
String字符串:
格式: set key value
string類型是二進制安全的刃滓。意思是redis的string可以包含任何數(shù)據(jù)仁烹。比如jpg圖片或者序列化的對象 耸弄。
string類型是Redis最基本的數(shù)據(jù)類型咧虎,一個鍵最大能存儲512MB。
Hash(哈希)
key=150
value={
“id”: 150,
“name”: “zhangsan”,
“age”: 20
}
hash類的數(shù)據(jù)結構计呈,主要是用來存放一些對象砰诵,把一些簡單的對象給緩存起來,后續(xù)操作的時候捌显,你可以直接僅僅修改這個對象中的某個字段的值
格式: hmset name key1 value1 key2 value2
Redis hash 是一個鍵值(key=>value)對集合茁彭。
Redis hash是一個string類型的field和value的映射表,hash特別適合用于存儲對象扶歪。
List(列表)
key=某大v
value=[zhangsan, lisi, wangwu]
比如可以通過list存儲一些列表型的數(shù)據(jù)結構理肺,類似粉絲列表了、文章的評論列表了之類的東西
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類型的無序集合树姨。
集合是通過哈希表實現(xiàn)的,所以添加桥状,刪除帽揪,查找的復雜度都是O(1)。
zset(sorted set:有序集合)
格式: zadd name score value
Redis zset 和 set 一樣也是string類型元素的集合,且不允許重復的成員辅斟。
不同的是每個元素都會關聯(lián)一個double類型的分數(shù)转晰。redis正是通過分數(shù)來為集合中的成員進行從小到大的排序。
zset的成員是唯一的,但分數(shù)(score)卻可以重復。
比如說你要是想根據(jù)時間對數(shù)據(jù)排序挽霉,那么可以寫入進去的時候用某個時間作為分數(shù)防嗡,人家自動給你按照時間排序了
排行榜:將每個用戶以及其對應的什么分數(shù)寫入進去,zadd board score username侠坎,接著zrevrange board 0 99蚁趁,就可以獲取排名前100的用戶;zrank board username实胸,可以看到用戶在排行榜里的排名
5.什么是Redis持久化他嫡?Redis有哪幾種持久化方式?優(yōu)缺點是什么庐完?
持久化就是把內存的數(shù)據(jù)寫到磁盤中去钢属,防止服務宕機了內存數(shù)據(jù)丟失。
Redis 提供了兩種持久化方式:RDB(默認) 和AOF RDB內存快照和AOF日志文件
RDB(快照的方式):
生成一個文件门躯,便于復制淆党,移動,性能比較好
rdb是Redis DataBase縮寫
功能核心函數(shù)rdbSave(生成RDB文件)和rdbLoad(從文件加載內存)兩個函數(shù)
AOF:
Aof是Append-only file縮寫
每當執(zhí)行服務器(定時)任務或者函數(shù)時flushAppendOnlyFile 函數(shù)都會被調用讶凉, 這個函數(shù)執(zhí)行以下兩個工作
aof寫入保存:
WRITE:根據(jù)條件染乌,將 aof_buf 中的緩存寫入到 AOF 文件
SAVE:根據(jù)條件,調用 fsync 或 fdatasync 函數(shù)懂讯,將 AOF 文件保存到磁盤中荷憋。
存儲結構:
內容是redis通訊協(xié)議(RESP )格式的命令文本存儲。
比較:
1褐望、aof文件比rdb更新頻率高勒庄,優(yōu)先使用aof還原數(shù)據(jù)。
2瘫里、aof比rdb更安全也更大
3实蔽、rdb性能比aof好
4、如果兩個都配了優(yōu)先加載AOF
6. redis的底層數(shù)據(jù)結構
redis底層有6種數(shù)據(jù)結構减宣,分別是簡單動態(tài)字符串(SDS),鏈表盐须,字典,跳躍表漆腌,整數(shù)集合贼邓,壓縮列表。
跳躍表
Redis使用跳躍表作為有序集合鍵的底層實現(xiàn)之一闷尿,若一個有序集合包含的元素數(shù)量比較多塑径,或者有序集合中的成員是比較長的字符串時,Redis就會使用跳躍表來作為有序集合鍵的底層實現(xiàn)填具。
有序集合使用兩種數(shù)據(jù)結構來實現(xiàn)统舀,從而可以使插入和刪除操作達到O(log(N))的時間復雜度匆骗。這兩種數(shù)據(jù)結構是哈希表和跳躍表。向哈希表添加元素誉简,用于將成員對象映射到分數(shù)碉就;同時將該元素添加到跳躍表,以分數(shù)進行排序闷串。
和鏈表瓮钥、字典等數(shù)據(jù)結構被廣泛地應用在Redis內部不同,Redis只在兩個地方用到了跳躍表烹吵,一個是實現(xiàn)有序集合鍵碉熄,另一個是在集群結點中用作內部數(shù)據(jù)結構。除此之外肋拔,跳躍表在Redis里面沒有其他用途锈津。
跳躍表(skiplist)是一種有序數(shù)據(jù)結構,它通過在每個節(jié)點中維持多個指向其他節(jié)點的指針凉蜂,從而達到快速訪問節(jié)點的目的琼梆。跳躍表是一種隨機化的數(shù)據(jù),跳躍表以有序的方式在層次化的鏈表中保存元素,效率和平衡樹媲美 ——查找跃惫、刪除叮叹、添加等操作都可以在對數(shù)期望時間下完成,并且比起平衡樹來說爆存,跳躍表的實現(xiàn)要簡單直觀得多。
Redis 只在兩個地方用到了跳躍表蝗砾,一個是實現(xiàn)有序集合鍵先较,另外一個是在集群節(jié)點中用作內部數(shù)據(jù)結構。
跳躍表的定義
我們先來看一下一整個跳躍表的完整結構:
Redis 的跳躍表 主要由兩部分組成:zskiplist(鏈表)和zskiplistNode (節(jié)點)
7.使用redis有哪些好處悼粮?
(1) 速度快闲勺,因為數(shù)據(jù)存在內存中,類似于HashMap扣猫,HashMap的優(yōu)勢就是查找和操作的時間復雜度都是O(1)
(2)支持豐富數(shù)據(jù)類型菜循,支持string,list申尤,set癌幕,sorted set,hash
(3) 支持事務昧穿,操作都是原子性勺远,所謂的原子性就是對數(shù)據(jù)的更改要么全部執(zhí)行,要么全部不執(zhí)行
(4) 豐富的特性:可用于緩存时鸵,消息胶逢,按key設置過期時間,過期后將會自動刪除
8.redis的淘汰機制
Redis提供了下面幾種淘汰策略供用戶選擇,其中默認的策略為noeviction策略:
· noeviction:當內存使用達到閾值的時候初坠,所有引起申請內存的命令會報錯和簸。
· allkeys-lru:在主鍵空間中,優(yōu)先移除最近未使用的key碟刺。
· volatile-lru:在設置了過期時間的鍵空間中比搭,優(yōu)先移除最近未使用的key。
· allkeys-random:在主鍵空間中南誊,隨機移除某個key身诺。
· volatile-random:在設置了過期時間的鍵空間中,隨機移除某個key抄囚。
· volatile-ttl:在設置了過期時間的鍵空間中霉赡,具有更早過期時間的key優(yōu)先移除。
9.Master&Slave是什么幔托?
也就是我們所說的主從復制穴亏,主機數(shù)據(jù)更新后根據(jù)配置和策略,自動同步到備機
的master/slaver機制重挑,Master以寫為主嗓化,Slave以讀為主。
它能干嘛
1谬哀、讀寫分離刺覆;
2、容災恢復
哨兵監(jiān)控
當master出現(xiàn)問題后史煎,獎slaver切換為master
10. redis常見性能問題和解決方案
(1) Master最好不要做任何持久化工作谦屑,如RDB內存快照和AOF日志文件
(2) 如果數(shù)據(jù)比較重要,某個Slave開啟AOF備份數(shù)據(jù)篇梭,策略設置為每秒同步一次
(3) 為了主從復制的速度和連接的穩(wěn)定性氢橙,Master和Slave最好在同一個局域網(wǎng)內
(4) 盡量避免在壓力很大的主庫上增加從庫
(5) 主從復制不要用圖狀結構,用單向鏈表結構更為穩(wěn)定恬偷,即:Master <- Slave1 <- Slave2 <- Slave3…
這樣的結構方便解決單點故障問題悍手,實現(xiàn)Slave對Master的替換。如果Master掛了袍患,可以立刻啟用Slave1做Master坦康,其他不變。
11.redis包含三種集群策略
1.主從復制: 在主從復制中协怒,數(shù)據(jù)庫分為倆類涝焙,主數(shù)據(jù)庫(master)和從數(shù)據(jù)庫(slave)。
其中主從復制有如下特點:
1.1. 主數(shù)據(jù)庫可以進行讀寫操作孕暇,當讀寫操作導致數(shù)據(jù)變化時會自動將數(shù)據(jù)同步給從數(shù)據(jù)庫
1.2. 從數(shù)據(jù)庫一般都是只讀的仑撞,并且接收主數(shù)據(jù)庫同步過來的數(shù)據(jù)
1.3. 一個master可以擁有多個slave赤兴,但是一個slave只能對應一個master、
主從復制工作機制
當slave啟動后隧哮,主動向master發(fā)送SYNC命令桶良。master接收到SYNC命令后在后臺保存快照(RDB持久化)和緩存保存快照這 段時間的命令,然后將保存的快照文件和緩存的命令發(fā)送給slave沮翔。slave接收到快照文件和命令后加載快照文件和緩存的執(zhí)行命令陨帆。
12. Redis 有哪些架構模式?講講各自的特點
單機版
|
特點:簡單
問題:
1采蚀、內存容量有限 2疲牵、處理能力有限 3、無法高可用榆鼠。
主從復制
Redis 的復制(replication)功能允許用戶根據(jù)一個 Redis 服務器來創(chuàng)建任意多個該服務器的復制品纲爸,其中被復制的服務器為主服務器(master),而通過復制創(chuàng)建出來的服務器復制品則為從服務器(slave)妆够。 只要主從服務器之間的網(wǎng)絡連接正常识啦,主從服務器兩者會具有相同的數(shù)據(jù),主服務器就會一直將發(fā)生在自己身上的數(shù)據(jù)更新同步 給從服務器神妹,從而一直保證主從服務器的數(shù)據(jù)相同颓哮。
特點:
1、master/slave 角色
2鸵荠、master/slave 數(shù)據(jù)相同
3冕茅、降低 master 讀壓力在轉交從庫
問題:
無法保證高可用
沒有解決 master 寫的壓力
哨兵
Redis sentinel 是一個分布式系統(tǒng)中監(jiān)控 redis 主從服務器,并在主服務器下線時自動進行故障轉移腰鬼。其中三個特性:
監(jiān)控(Monitoring): Sentinel 會不斷地檢查你的主服務器和從服務器是否運作正常嵌赠。
提醒(Notification): 當被監(jiān)控的某個 Redis 服務器出現(xiàn)問題時, Sentinel 可以通過 API 向管理員或者其他應用程序發(fā)送通知熄赡。
自動故障遷移(Automatic failover): 當一個主服務器不能正常工作時, Sentinel 會開始一次自動故障遷移操作齿税。
特點:
1彼硫、保證高可用
2、監(jiān)控各個節(jié)點
3凌箕、自動故障遷移
缺點:主從模式拧篮,切換需要時間丟數(shù)據(jù)
沒有解決 master 寫的壓力
集群(proxy 型):
Twemproxy 是一個 Twitter 開源的一個 redis 和 memcache 快速/輕量級代理服務器; Twemproxy 是一個快速的單線程代理程序牵舱,支持 Memcached ASCII 協(xié)議和 redis 協(xié)議串绩。
特點:
1、多種 hash 算法:MD5芜壁、CRC16礁凡、CRC32高氮、CRC32a、hsieh顷牌、murmur剪芍、Jenkins
2、支持失敗節(jié)點自動刪除
3窟蓝、后端 Sharding 分片邏輯對業(yè)務透明罪裹,業(yè)務方的讀寫方式和操作單個 Redis 一致
缺點:增加了新的 proxy,需要維護其高可用运挫。
failover 邏輯需要自己實現(xiàn)状共,其本身不能支持故障的自動轉移可擴展性差,進行擴縮容都需要手動干預
集群(直連型):
從redis 3.0之后版本支持redis-cluster集群谁帕,Redis-Cluster采用無中心結構峡继,每個節(jié)點保存數(shù)據(jù)和整個集群狀態(tài),每個節(jié)點都和其他所有節(jié)點連接。
特點:
1雇卷、無中心架構(不存在哪個節(jié)點影響性能瓶頸)鬓椭,少了 proxy 層。
2关划、數(shù)據(jù)按照 slot 存儲分布在多個節(jié)點小染,節(jié)點間數(shù)據(jù)共享,可動態(tài)調整數(shù)據(jù)分布贮折。
3裤翩、可擴展性,可線性擴展到 1000 個節(jié)點调榄,節(jié)點可動態(tài)添加或刪除踊赠。
4、高可用性每庆,部分節(jié)點不可用時筐带,集群仍可用。通過增加 Slave 做備份數(shù)據(jù)副本
5缤灵、實現(xiàn)故障自動 failover伦籍,節(jié)點之間通過 gossip 協(xié)議交換狀態(tài)信息,用投票機制完成 Slave到 Master 的角色提升腮出。
缺點:
1帖鸦、資源隔離性較差,容易出現(xiàn)相互影響的情況胚嘲。
2作儿、數(shù)據(jù)通過異步復制,不保證數(shù)據(jù)的強一致性
13. 使用過Redis分布式鎖么,它是怎么實現(xiàn)的馋劈?
先拿setnx來爭搶鎖攻锰,搶到之后晾嘶,再用expire給鎖加一個過期時間防止鎖忘記了釋放。
如果在setnx之后執(zhí)行expire之前進程意外crash或者要重啟維護了口注,那會怎么樣变擒?
set指令有非常復雜的參數(shù),這個應該是可以同時把setnx和expire合成一條指令來用的寝志!
緩存雪崩和緩存穿透問題解決方案
緩存雪崩
簡介:緩存同一時間大面積的失效娇斑,所以,后面的請求都會落到數(shù)據(jù)庫上材部,造成數(shù)據(jù)庫短時間內承受大量請求而崩掉毫缆。解決辦法(中華石杉老師在他的視頻中提到過,視頻地址在最后一個問題中有提到):
* 事前:盡量保證整個 redis 集群的高可用性乐导,發(fā)現(xiàn)機器宕機盡快補上苦丁。選擇合適的內存淘汰策略。
* 事中:本地ehcache緩存 + hystrix限流&降級物臂,避免MySQL崩掉
* 事后:利用 redis 持久化機制保存的數(shù)據(jù)盡快恢復緩存
緩存穿透
簡介:一般是黑客故意去請求緩存中不存在的數(shù)據(jù)旺拉,導致所有的請求都落到數(shù)據(jù)庫上,造成數(shù)據(jù)庫短時間內承受大量請求而崩掉棵磷。解決辦法: 有很多種方法可以有效地解決緩存穿透問題蛾狗,最常見的則是采用布隆過濾器,將所有可能存在的數(shù)據(jù)哈希到一個足夠大的bitmap中仪媒,一個一定不存在的數(shù)據(jù)會被 這個bitmap攔截掉沉桌,從而避免了對底層存儲系統(tǒng)的查詢壓力。另外也有一個更為簡單粗暴的方法(我們采用的就是這種)算吩,如果一個查詢返回的數(shù)據(jù)為空(不管是數(shù) 據(jù)不存在留凭,還是系統(tǒng)故障),我們仍然把這個空結果進行緩存偎巢,但它的過期時間會很短蔼夜,最長不超過五分鐘。
如何解決 Redis 的并發(fā)競爭 Key 問題
所謂 Redis 的并發(fā)競爭 Key 的問題也就是多個系統(tǒng)同時對一個 key 進行操作压昼,但是最后執(zhí)行的順序和我們期望的順序不同挎扰,這樣也就導致了結果的不同!
推薦一種方案:分布式鎖(zookeeper 和 redis 都可以實現(xiàn)分布式鎖)巢音。(如果不存在 Redis 的并發(fā)競爭 Key 問題,不要使用分布式鎖尽超,這樣會影響性能)
基于zookeeper臨時有序節(jié)點可以實現(xiàn)的分布式鎖官撼。大致思想為:每個客戶端對某個方法加鎖時,在zookeeper上的與該方法對應的指定節(jié)點的目錄下似谁,生成一個唯一的瞬時有序節(jié)點傲绣。 判斷是否獲取鎖的方式很簡單掠哥,只需要判斷有序節(jié)點中序號最小的一個。 當釋放鎖的時候秃诵,只需將這個瞬時節(jié)點刪除即可续搀。同時,其可以避免服務宕機導致的鎖無法釋放菠净,而產(chǎn)生的死鎖問題禁舷。完成業(yè)務流程后,刪除對應的子節(jié)點釋放鎖毅往。
在實踐中牵咙,當然是從以可靠性為主。所以首推Zookeeper攀唯。
如何保證緩存與數(shù)據(jù)庫雙寫時的數(shù)據(jù)一致性?
你只要用緩存洁桌,就可能會涉及到緩存與數(shù)據(jù)庫雙存儲雙寫,你只要是雙寫侯嘀,就一定會有數(shù)據(jù)一致性的問題另凌,那么你如何解決一致性問題?
一般來說戒幔,就是如果你的系統(tǒng)不是嚴格要求緩存+數(shù)據(jù)庫必須一致性的話吠谢,緩存可以稍微的跟數(shù)據(jù)庫偶爾有不一致的情況,最好不要做這個方案溪食,讀請求和寫請求串行化囊卜,串到一個內存隊列里去,這樣就可以保證一定不會出現(xiàn)不一致的情況
串行化之后错沃,就會導致系統(tǒng)的吞吐量會大幅度的降低栅组,用比正常情況下多幾倍的機器去支撐線上的一個請求。
14. Springboot與redis的使用
<!-- 引入redis依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
然后枢析,資源配置文件application.yml(或properties)中加入redis相關配置:
spring:
redis:
#redis數(shù)據(jù)庫地址
host: localhost
port: 6379
password: root
timeout: 1000
#redis數(shù)據(jù)庫索引玉掸,默認0
database: 1
這里我們引入了StringRedisTemplate類,這個類也是Java中整合Redis主要使用的操作類醒叁。這里首先使用MyBatis向數(shù)據(jù)庫添加一條user數(shù)據(jù)司浪,如果添加成功,則使用StringRedisTemplate中的opsForValue.set()方法把沼,將該user數(shù)據(jù)Json格式化后添加到Redis數(shù)據(jù)庫中啊易,以"user : "+該user的id屬性值作為鍵
BoundHashOperations<String, Object, Object> 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有哪些優(yōu)勢?
(1) memcached所有的值均是簡單的字符串饮睬,redis作為其替代者租谈,支持更為豐富的數(shù)據(jù)類型
(2) redis的速度比memcached快很多
(3) redis可以持久化其數(shù)據(jù)
(4)Redis支持數(shù)據(jù)的備份躯枢,即master-slave模式的數(shù)據(jù)備份适掰。