redis
redis是目前最流行的非關系型資料庫,很多場景都可以使用到redis,是以有了這篇文章的誕生
為什麼使用redis?
在項目中,很多場景的并發量很大,如秒殺之類,若不使用redis緩存直接讓其通路資料庫,那麼會對資料庫造成很大的壓力進而導緻資料庫崩了,是以引入redis做分布式緩存
redis的五種資料結構:
- 一:String類型 keyValue都是String (可以用作緩存)
- 二:List類型 Value可存放多個值,有序且重複(可以通過lpush,rpop實作隊列 也可以通過range範圍查詢來實作分頁功能,使用者最近視訊觀看記錄)
- 三:Set類型 無序但不可重複(因為可以自動去重是以可以實作并集交集差集,可以實作好友去重,可以實作抽獎活動,去重保證每個人參加一次,可以實作朋友圈點贊)
- 四:Zset類型 對應的每個set元素可添加一個分數(可以實作排行榜)zset的底層是用跳表(一個多層的有序連結清單,一種基于機率統計的插入算法)實作
- 五:Hash類型 value就是一個map類型(購物車),redis的Hash其實可以了解成JAVA中的MAP<String,Map<KEY,VALUE>>
redis的持久化技術:
因為redis是在記憶體中工作,一旦關閉所有資料就消失了,是以需要使用一種持久化的技術,将redis的資料儲存起來
RDB和AOF
RDB:持久化時會fork一個一模一樣的子程序進行持久化,因為redis是單線程如果用目前的工作線程進行持久化,那麼就會阻塞使用者的操作直到持久化完成。在調用save指令時會阻塞目前的redis(RDB主要負責全量持久化),Redis适用于容災恢複支援大資料量恢複,但其可能會造成資料的丢失(Redis意外down掉的話,會丢失最後一次快照的修改)
AOF:可以支援實時的持久化,AOF檔案通常比RDB大恢複起來慢(AOF主要負責增量持久化),但其可以保證資料的完整性
RDB和AOF的選擇問題:
當對資料很敏感且不允許分鐘内的資料丢失則使用AOF,若資料量較大且追求恢複速度使用RDB,RDB非常适合災難恢複,不過還是建議兩個持久化政策一起使用。開機啟動時,先檢視是否開啟了AOF,如果開啟則加載AOF的Appendonly.aof,沒開啟則加載RDB的dump.rdb對于主從同步來說,從庫啟動後先執行RDB實作全量同步,再執行AOF進行實時持久化
redis的事務:
redis也支援事務,隻不過他的事務和mysql的不同,他的是誰成功就是成功,失敗就是失敗,即使失敗了也不會讓其他成功的復原
redis常見的問題:
redis的雪崩問題:
當redis當中很多字段都同時失效時,大量的請求直接打進了mysql當中,造成了redis的雪崩。
解決方法:
- ①可以設定他們的失效期均勻分布
- ②在程式中設定限流降級操作
- ③如果是因為redis當機問題,則可以設定redis叢集保證高可用④資料預熱,在活動開始前提前将資料存入redis當中。
redis的緩存穿透:
使用者惡意通路mysql中不存在的資料,故redis也沒有是以會造成大量的請求打到mysql中。
解決方式:
一:redis添加空資料:在資料庫中查不到資料時,自定義一個類存到redis中,每次查詢redis後,instanceof 自定義的class,如果為True則說明是空資料,直接傳回查不到,不再去查詢mysql
二:通路mysql前添加布隆過濾器,現将mysql中的資料id存儲到布隆過濾器,布隆過濾器中以0,1的方式存放mysql中的資料,當判斷資料是否存在布隆過濾器時,它會對給定的元素進行Hash計算如果結果都為1則資料在布隆過濾器中,如果有一個為0則資料不存在布隆過濾器中,直接傳回不再讓它執行後面的代碼(布隆過濾器也是有誤差的,布隆過濾器中存在的資料mysql不一定存在,布隆過濾器中不存在的資料mysql一定不存在)架構的布隆過濾器隻适合于單機版,我們可以使用redis的bitmap實作分布式布隆過濾器
redis的緩存擊穿:
當多個使用者通路某一個熱點資料,該資料在redis中突然失效,此時大量的請求又會打到mysql當中。
解決方法:
一:添加鎖,隻允許一個線程去通路mysql,通路完mysql将資料重新添加到緩存後,再讓其他線程通路緩存
二:設定熱點資料永不過期
redis的主從複制:
複制一份一模一樣的redis,實作讀寫分離高可用,主庫負責寫,從庫負責讀
原理:
從庫(slave)監聽主庫(master):Slaveof (主庫的)ip 端口從庫啟動後連接配接到master後會發送一個psync指令,如果該從庫是第一次連接配接主庫,則master接到指令後會觸發一個全量複制,啟動背景的存盤程序,收集所有的修改指令,生成RDB快照,然後将RDB傳送給從庫,從庫完成全量同步。之後新增到master的資料可以使用AOF增量同步到從庫
redis的哨兵模式:
當主庫挂了之後,從庫通過投票的方式選出一個從庫來轉為主庫(最少要有3個哨兵執行個體)
配置方式:主庫建立一個sentinel.conf檔案,編寫 sentinel monitor 自定義名 本機io 端口 x:x表示主機挂掉之後,從機的投票數的滿足條件
哨兵的作用:
- ①:叢集監控:負責監控Redis master和slave是否正常工作
- ②:消息通知:當某個Redis執行個體發生故障時,發送消息作為報警通知給管理者
- ③:故障轉移:如果master節點挂了,那麼在slave節點中自動選取一個作為新的master
- ④:配置中心:如果故障轉移發生了,則會通知其他slave新的master位址
如何在redis中找出key是以某個固定字首開頭的資料?
可以采用keys指令來掃描指定字首的key。
若目前redis正線上上使用,調用keys指令時,由于redis是單線程的故會阻塞一段時間直到keys指令執行完畢,這時可以使用scan指令,可無阻塞的進行掃描指定字首的key,但scan執行時間比keys長。
redis為什麼快?
因為他的操作是基于記憶體的
且采用了io多路複用技術
它是單線程避免了多線程環境下不必要的上下文切換(多線程下Cpu為每個線程配置設定一個時間片,時間片結束重新進入就緒狀态,會讓其他線程執行)也不必擔心鎖的問題,也不會出現死鎖情況
io多路複用:
redis當中利用了select poll epoll可以同時監聽多個流的IO事件能力,在空閑時,他會把線程阻塞掉,當一個或多個流有IO事件發生時,就會從阻塞狀态中喚醒,程式會輪詢一次所有的流,按順序處理就緒的流,此時就可以避免大量的無用操作。
多路:多個網絡連接配接 複用:複用同一線程 采用io多路複用可以讓單個線程高效的處理多個連接配接請求
redis的過期政策:(存放的資料設定過期時間後如何在到達時間後移除資料)當資料達到過期時間後,不會第一時間删除,它的過期政策是惰性删除(取資料時,判斷一下是否過期,過了就删除),定時删除(每隔一段時間,随機取一些資料判斷是否過期,過期就删除)
redis的淘汰政策:(當記憶體滿了,需要淘汰一些資料)
FIFO:淘汰最早添加進來的資料 LRU:淘汰最近最少使用的資料 random:随機淘汰
為什麼使用redis不使用Memcache
- 一:因為MC的Key不能超過250位元組Value不能超過1M位元組
- 二:key的最大失效時間為30天
- 三:MC不支援持久化和主從同步
- 四:redis支援更多的資料結構(MC隻支援String類型),redis采用單線程模式處理請求(MC是多線程),是以可以采用非阻塞的異步處理機制,單線程還可以避免線程上下文切換浪費的時間
redis的線程模型:
redis所采用的線程模型是檔案事件處理器,檔案事件處理器是單線程的,是以redis也是單線程的,它采用io多路複用來同時監聽多個Socket
如何保證資料庫和redis的資料一緻性:
(如果先删緩存,再更新資料庫,則有可能出現,更新資料庫前又讀取資料,緩存中又存放的是更新前的資料)
(如果先更新資料庫,再删緩存,有可能出現更新資料庫成功,删除緩存失敗,資料不一緻)
①:采用延遲雙删:
- 一:删除緩存中的資料
- 二:更新資料庫中的資料
- 三:根據業務情況,睡眠一定時間(害怕出現:讀取操作在更新資料庫前,當執行完第四步,才将讀取的資料存入到redis,這時就造成了資料不一緻,是以需要等待讀取所需時間後再删除)
- 四:再删除緩存中的資料(若在更新前,又進行讀取,讀取到的是更新前的髒資料,確定緩存中存放的不是之前的資料)
②:采用消息隊列:
先更新資料庫再删除redis
如果redis删除失敗:
- 一:在catch中将删除失敗的key發送到消息隊列
- 二:自己接受消息
- 三:擷取要删除的key後,進行重試删除操作直至删除成功
③:設定緩存的過期時間:這樣無論如何最終過期後都會去mysql中讀取最新的資料
如何保證Redis的并發競争key問題:
所謂Redis的并發競争key問題,就是多個服務同時對一個key進行操作,但最終執行的順序和我們預期的順序不同,這就導緻了不同的結果
解決方法:通過分布式鎖可以解決這個問題
使用Hash存儲商品資料,當資料量很大時,如何進行優化?
Hash的結構是:key filed value,當存儲商品時,一般key設定為product,由于資料量很大,對同一key進行操作會有阻塞的情況。
分段存儲:我們可以存儲資料時,通過商品Id%10000擷取值0-9999之間,然後存儲時就可以:key:(product:10),filed:id,value:商品資訊,這樣就可以保證每個key下的商品資料量都不大
redis是單線程的,那我們現在的伺服器都是多核的,是不是會有性能的浪費?
雖然他是單線程的,但我們可以在單機開多個Redis執行個體
如果單機還有瓶頸,那麼也可以在多機下開啟redis叢集(cluster)
資料同步的時候斷網了或者伺服器挂了怎麼辦?
在網絡恢複或者伺服器恢複後,會自動把缺少的資料補上。
部落格:http://mylike.ltd
作者:Eason丶Guo
連結:https://juejin.im/post/6881628117137948680
來源:掘金