Redis相關複習 知識點 相關知識點簡介 1 為什麼要使用redis(說redis優點)? 2 使用redis有什麼缺點? 3 單線程的redis為什麼這麼快? 4 redis的數據類型,以及每種數據類型的使用場景 5 redis的過期策略以及記憶體淘汰機制 6 redis和資料庫雙寫一致性問題 7 ...
相關知識點簡介
1 為什麼要使用redis(說redis優點)?
2 使用redis有什麼缺點?
3 單線程的redis為什麼這麼快?
4 redis的數據類型,以及每種數據類型的使用場景
5 redis的過期策略以及記憶體淘汰機制
6 redis和資料庫雙寫一致性問題
7 如何應對緩存穿透和緩存雪崩問題
8 如何解決redis的併發競爭問題
1 為什麼要使用redis?
在項目中使用redis,主要是從兩個角度去考慮:性能和併發,redis還具備可以做分散式鎖等其他的功能,但是如果只是為了使用分散式鎖這些功能,還可以使用其它中間件來代替(如zookpeer等),並不是非要去使用redis。
-
一. 性能:當我們碰到執行耗時很長時間,而且結果不頻繁變動的SQL語句,就特別適合將運行結果放入緩存資料庫裡面,這樣一來,後面的請求就全部去緩存裡面讀取,使得請求可以快速響應 (Tips:sql運行時間越短越好,用緩存是最快的方式)
-
二. 併發:在數據量很大的時候,所有的請求直接訪問資料庫,mysql資料庫的壓力會特別大(mysql資料庫併發很小) 然後就會崩潰。
-
這個時候,就需要使用redis資料庫進行一個中間緩存的操作,讓請求先去訪問reids,而不是去直接訪問mysql (請求過來之後首先先去redis資料庫裡面查數據,redis裡面沒有再去mysql裡面查,查到之後放到redis裡面一份),這樣以來,redis解決了大部分的訪問問題,mysql資料庫的壓力就會小很多
Redis的特點:
-
記憶體資料庫,速度快,也支持數據的持久化,可以將記憶體中的數據保存在磁碟中,重啟的時候可以再次載入進行使用。
-
Redis不僅僅支持簡單的key-value類型的數據,同時還提供list,set,zset,hash等數據結構的存儲。
-
Redis支持數據的備份,即master-slave模式的數據備份。
-
支持事務
命令行啟動redis的方法首先windows +r 輸入cmd 打開黑視窗輸入 redis-server //第一步啟動客戶端
然後另起一個黑視窗輸入redis-cli -h 資料庫ip //第二步啟動服務端
然後輸入密碼
2 . 使用redis有什麼缺點
一共是四個問題
-
緩存和資料庫雙寫一致性問題
-
緩存雪崩問題
-
緩存擊穿問題
-
緩存的併發競爭問題
3 . 單線程的redis為什麼這麼快
這個問題是對redis內部機制的一個考察,主要是三個點
-
redis純記憶體操作
-
單線程操作,避免了頻繁的上下文和線程切換,只去處理簡單的sql語句,不處理io操作
-
採用了非阻塞I/O多路復用機制
題外話:我們現在要仔細的說一說I/O多路復用機制,因為這個說法實在是太通俗了,通俗到一般人都不懂是什麼意思。舉一個例子:張三在家開了一家快遞店,負責同城快送服務。張三因為資金限制,雇佣了一批快遞員(線程),然後張三發現資金不夠了,只夠買一輛車送快遞(只能每次執行一個操作,車代表CPU核數)。
經營方式一 客戶每送來一份快遞,張三就讓一個快遞員盯著,然後快遞員開車去送快遞。慢慢的張三就發現了這種經營方式存在下述問題
-
幾十個快遞員基本上時間都花在了搶車上了,大部分快遞員都處在閑置狀態,誰搶到了車,誰就能去送快遞(多個線程搶占線程鎖,很多線程都是空閑)
-
隨著快遞的增多,快遞員也越來越多,張三發現快遞店裡越來越擠,沒辦法雇佣新的快遞員了
-
快遞員之間的協調很花時間(多個線程每次執行之前都搶這一個鎖,浪費時間)
經營方式二 改善之後,小曲只雇佣一個快遞員(單線程)。然後呢,客戶送來的快遞,小曲按送達地點標註好,然後依次放在一個地方。最後,那個快遞員依次的去取快遞,一次拿一個,然後開著車去送快遞,送好了就回來拿下一個快遞(一次執行一個操作,執行完成之後執行其他的)。
總結:經營方式一就是傳統的併發模型,每個I/O流(快遞)都有一個新的線程(快遞員)管理。 經營方式二就是I/O多路復用。只有單個線程(一個快遞員),通過跟蹤每個I/O流的狀態(每個快遞的送達地點),來管理多個I/O流。
Redis的優勢:
-
性能極高 – Redis能讀的速度是110000次/s,寫的速度是81000次/s 。
-
豐富的數據類型 – Redis支持二進位案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 數據類型操作。
-
原子性 – Redis的所有操作都是原子性的,同時Redis還支持對幾個操作合併後的原子性執行。(事務)
-
豐富的特性 – Redis還支持 publish/subscribe, 通知, key 過期等等特性。
redis所有的操作都是原子性的,採用單線程處理所有業務,命令是一個一個執行的,因此無需考慮併發帶來的數據影響
五種類型與類比java的模型
-
string --> String
-
hash --> Hashmap
-
list --> LinkList
-
set --> HashSet
-
sorted_set --> TreeSet
二 .五大基本數據類型
1 .String類型語句
(典型應用場景: • 通用緩存、計數器(下載量、點擊量、線上人數等)等)
IO優化:合理使用mget、mset、pipeline等多值命令,提高批量操作的效率
• 命令處理時間通常小於網路傳輸時間,減少網路開銷的次數將會極大提高操作效率
• 批量操作的命令/KEY數量一次不易過多,否則會出現Redis處理阻塞或者網路延遲
• 不要將所有數據都放到Redis記憶體中,只放熱數據和有用的數據**
• 長字元串儘量壓縮存儲,控制在512位元組以內**
String作為數值操作時的註意事項
string在redis內部存儲預設就是一個字元串,當遇到增減類操作incr,decr時會轉成數值型進行計算
redis所有的操作都是原子性的,採用單線程處理所有業務,命令是一個一個執行的,因此無需考慮併發帶來的數據影響。
按數值進行操作的數據,如果原始數據不能轉成數值,或超過了redis數值上線範圍,將會報錯。9223372036854775807 (java中long型數據最大值,Long.MAX_VALUE)
//spring語法格式
//添加/修改數據
set key value
//獲取數據
get key
//刪除數據
del key
//設置一個有過期時間的鍵
set key value [ex 過期時間單位:秒] [px 過期時間單位:毫秒] //ex跟px之間設置一個就可以了
//設置一個string類型的name,它的過期時間是20秒
set name zhangsan ex 20
//查看key的過期時間
ttl key
//刪除過期時間的設置
persist key
//也可以通過重新設置值 但是不加過期時間的方式來取消過期時間
//添加/修改多個數據語法格式
mset key1 value key2 value2 …
//獲取多個數據
mget key1 key2 …
//追加數據到值的尾部
append key value
//獲取數據字元個數(字元串長度)
strlen key
--------------------------
//設置數值數據增加指定範圍的值
//key的值自增+1
incr key
//key增加指定的數值 incrby age 10
incrby key increment
//增加一個浮點數(小數)
incrbyfloat key increment
//設置數值數據減少指定範圍的值
decr key //自減1
decrby key increment //減少指定數值
//清屏
clear
2. Hash(哈希)
相當於比string類型多了個對象,可以多個鍵值對存放在一個對象裡面,這就叫做hash
Ø 類型說明:
哈希類型所存儲的鍵值本身又是一個鍵值對結構!
Ø 典型應用場景:
對象信息,比如用戶基礎信息、商品信息等
對象類數據的存儲如果具有較為頻繁的更新需求,操作會顯得笨重,存容易,改麻煩。 為了區別與Redis中的鍵值對的稱呼,hash中的鍵成為field,而key特征Redis的鍵。
hash類型數據操作的註意事項
單個hash類型成員個數不要過多
hgetAll獲取所有成員謹慎使用,容易帶來性能問題(hscan)
hash類型下的value只能存儲字元串,不允許存儲其他類型數據,不存在嵌套現象。如果數據未獲取到,對應的值為(nil) 每個hash可以存儲2的32次方-1個鍵值對
hash類型十分貼近對象的數據存儲形式,並且可以靈活添加刪除對象屬性。但hash設計不是為了存儲大量對象的,切記不可濫用,更不可以將hash作為對象列表使用 hgetAll操作可以獲取全部屬性,如果內部fiekd過多,遍歷整體數據效率就會很低,有可能成為數據訪問瓶頸。
//Hash基本操作
//添加/修改數據 對象 屬性 值
hset key field value // hset user name zhangsan
//獲取數據
hget key field // hget user name
//根據key刪除數據
hdel key field1 [field2]
// hdel user name
//根據對象名獲取所有鍵值對
hgetall key
//添加/修改多個數據
hmset key field1 value1 field2 calue2
// hmset user name zhangsan age 15 //user 裡面設置了兩個鍵值對 name和age
//獲取多個數據
hmget key field1 field2 …
// hmget user name age //獲取user中的name和age的值
//獲取哈希表中欄位的數量
hlen key
//獲取哈希表中是否存在指定的欄位
hexists key field
//hexists user name 看user中有沒有name欄位
//獲取哈希表中所有的欄位名和欄位值
hkeys key //欄位名 獲取所有鍵
hvals key //欄位值 獲取所有值
3 . list 類型
數據存儲需求:存儲多個數據,並對數據進入存儲空間的順序進行區分 需要的存儲數據:一個存儲空間保存多個數據,且通過數據可以體現進入順序 list類型:保存多個數據,底層使用雙向鏈表存儲結構實現
lpush rpop 隊列先進先出(隊列像排隊一樣誰在前面誰先出去)
棧是先進後出(棧像一個水瓶一樣,先進來的最後才能出去)
//-----------添加/修改/查詢數據----------------
//從list的左邊添加進來
lpush key value1 [value2] …
//lpush student zhangsan lisi
//從list的右邊添加進來
rpush key value1 [value2] …
//將值 value 插入到列表 key 當中,位於值 pivot 之前或之後。 如果命令執行成功,返回插入操作完成之後,列表的長度。 如果沒有找到指定元素 ,返回 -1 。 如果 key 不存在或為空列表,返回 0
linsert key BEFORE|AFTER pivot value
// linsert student before xiaoli zhangsan 在xiaoli前面添加一個值zhangsan
//獲取從lilst左數第start到stop個元素,從0開始
lrange key start stop
//lrange student 0 3 獲取student中0到3的值
//查詢第i個元素
lindex key index
//獲取指定list的長度
llen key
//規定時間內獲取並移除數據 blpop是從左邊移除數據 brpop是從右邊移除數據
blpop key1 [key2] timeout
brpop key1 [key2] timeout
//阻塞式獲取,在規定時間內獲取這個值,規定時間內如果還沒有的時候可以等,直到有值就可以獲取到獲取超時獲取為空. 比如說現在設置了獲取超時時間是30秒,30秒內只要其他客戶端通過 lpush 添加進來數據就可以獲取到並刪除
//開兩個客戶端,一個設置15s內獲取list1中的值,此時list1位空一直等待(阻塞),在15秒內另一個客戶端存入到list1中數據,此時就被獲取到。
//-----------獲取並移除數據-----------------
//獲取並刪除list左邊第一個元素
lpop key
//獲取並刪除list右邊第一個元素
rpop key
//移除指定數據 count為移除的數量,value為移除哪個值
lrem key count value
4 . Set類型
新的存儲需求:存儲大量的數據,在查詢方面提供更高的效率 需要的存儲結構:能夠保存大量的數據,高校的內部存儲機制,便於查詢 set類型:與hash存儲結構完全相同,僅存儲鍵,不存儲值(nil),並且值是不允許重覆的。也就是只有鍵沒有值的hash Set的基本操作
set類型不允許數據重覆,如果添加的數據在set中已經存在,將只保留一份 set雖然與hash的存儲結構相同,但是無法啟用hash中存儲值的空間
//-----------添加數據-----------(可以同時添加多個值,用空格分開)
sadd key menber1 [member2]
//sadd 集合名 數據1...
//獲取全部數據
smembers key
//smembers 集合名
//刪除指定的數據
srem key member1 [member2]
//srem 集合名 數據
//獲取集合數據總量
scard key
//判斷集合中是否包含指定數據
sismember key member
----------------------------------------------------------------------------------
//業務場景-隨機操作數據
//每位用戶首次使用進入頭條時候會設置3項愛好的內容,但是後期為了增加用戶的活躍度,興趣點,必須讓用戶對其他信息類別逐漸產生興趣,增加客戶留存度,如何實現? 使用set的集合隨機獲取就可以
//業務分析
//系統分析出各個分類的最新或最熱點信息條目並組織成set集合,隨機挑選其中部分信息
//配合用戶關註的信息分類中的熱點信息放一塊的全部信息集合
//隨機獲取集合中指定數量的數據
srandmember key [count]
//srandmember 集合名 數量
//隨機獲取集合中指定數量的數據(如果不指定數量的話就可以像隨機數一樣)
srandmember key [count]
//隨機獲取集合中的某個數據並將該數據移出集合
spop key
//---------求兩個集合的交、並、差集-----------
//求兩個集合的交集 (比如找兩個人共同的好友)
sinter key1 [key2] //sinter 集合一 集合二
//求兩個集合的並集 (兩個人全部的好友)
sunion key1 [key2]
//求兩個集合的差集(key1有但是key2沒有的)
sdiff key1 [key2]
//將指定數據從原始集合移動到目標集合中
smove source destination member
//smove 集合1 集合2 從集合1到集合2移動的數據
SpringBoot整合Redis
1 .首先導入redis對應的starter
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2 接下來配置,在application.yml配置文件裡面加redis的數據源相關配置 url username password等
3 最後提供 註入redis介面對象RedisTemplate,通過Redisemplate操作redis資料庫