前言
Redis作為一種優(yōu)秀的基于key/value的緩存,有非常不錯的性能和穩(wěn)定性,無論是在工作中,還是面試中,都經常會出現。
今天這篇文章就跟大家一起聊聊,我在實際工作中使用Redis的10種場景,希望對你會有所幫助。
1. 統(tǒng)計訪問次數
對于很多官方網站的首頁,經常會有一些統(tǒng)計首頁訪問次數的需求。
訪問次數只有一個字段,如果保存到數據庫中,再最后做匯總顯然有些麻煩。
該業(yè)務場景可以使用Redis,定義一個key,比如:OFFICIAL_INDEX_VISIT_COUNT。
在Redis中有incr命令,可以實現給value值加1操作:
incr?OFFICIAL_INDEX_VISIT_COUNT
當然如果你想一次加的值大于1,可以用incrby命令,例如:
incrby?OFFICIAL_INDEX_VISIT_COUNT?5
這樣可以一次性加5。
2. 獲取分類樹
在很多網站都有分類樹的功能,如果沒有生成靜態(tài)的html頁面,想通過調用接口的方式獲取分類樹的數據。
我們一般為了性能考慮,會將分類樹的json數據緩存到Redis當中,為了后面在網站當中能夠快速獲取數據。
不然在接口中需要使用遞歸查詢數據庫,然后拼接成分類樹的數據結構。
這個過程非常麻煩,而且需要多次查詢數據庫,性能很差。
因此,可以考慮用一個定時任務,異步將分類樹的數據,直接緩存到Redis當中,定義一個key,比如:MALL_CATEGORY_TREE。
然后接口中直接使用MALL_CATEGORY_TREE這個key從緩存中獲取數據即可。
可以直接用key/value字符串保存數據。
不過需要注意的是,如果分類樹的數據非常多可能會出現大key的問題。
3. 做分布式鎖
分布式鎖可能是使用Redis最常見的場景之一,相對于其他的分布式鎖,比如:數據庫分布式鎖或者Zookeeper分布式鎖,基于Redis的分布式鎖,有更好的性能,被廣泛使用于實際工作中。
我們使用下面這段代碼可以加鎖:
try{
??String?result?=?jedis.set(lockKey,?requestId,?"NX",?"PX",?expireTime);
??if?("OK".equals(result))?{
??????return?true;
??}
??return?false;
}?finally?{
????unlock(lockKey);
}??
但上面這段代碼在有些場景下,會有一些問題,釋放鎖可能會釋放了別人的鎖。
說實話Redis分布式鎖雖說很常用,但坑也挺多的,如果用不好的話,很容易踩坑。
4. 做排行榜
很多網站有排行榜的功能,比如:商城中有商品銷量的排行榜,游戲網站有玩家獲得積分的排行榜。
通常情況下,我們可以使用Sorted Set
保存排行榜的數據。
使用ZADD
可以添加排行榜的數據,使用ZRANGE
可以獲取排行榜的數據。
例如:
ZADD?rank:score?100?"周星馳"
ZADD?rank:score?90?"周杰倫"
ZADD?rank:score?80?"周潤發(fā)"
ZRANGE?rank:score?0?-1?WITHSCORES
返回數據:
1)?"周星馳"
2)?"100"
3)?"周杰倫"
4)?"90"
5)?"周潤發(fā)"
6)?"80"
5. 記錄用戶登錄狀態(tài)
通常下,用戶登錄成功之后,用戶登錄之后的狀態(tài)信息,會保存到Redis中。
這樣后面該用戶訪問其他接口的時候,會直接從Redis中查詢用戶登錄狀態(tài),如果可以查到數據,說明用戶已登錄,則允許做后續(xù)的操作。
如果從Redis中沒有查到用戶登錄狀態(tài),說明該用戶沒有登錄,或者登錄狀態(tài)失效了,則直接跳轉到用戶登錄頁面。
使用Redis保存用戶登錄狀態(tài),有個好處是它可以設置一個過期時間,比如:該時間可以設置成30分鐘。
jedis.set(userId,?userInfo,?1800);
在Redis內部有專門的job,會將過期的數據刪除,也有獲取數據時實時刪除的邏輯。
6. 限流
使用Redis還有一個非常常用的的業(yè)務場景是做限流
。
當然還有其他的限流方式,比如:使用nginx,但使用Redis控制可以更精細。
比如:限制同一個ip,1分鐘之內只能訪問10次接口,10分鐘之內只能訪問50次接口,1天之內只能訪問100次接口。
如果超過次數,則接口直接返回:請求太頻繁了,請稍后重試。
跟上面保存用戶登錄狀態(tài)類似,需要在Redis中保存用戶的請求記錄。
比如:key是用戶ip,value是訪問的次數從1開始,后面每訪問一次則加1。
如果value超過一定的次數,則直接攔截這種異常的ip。
當然也需要設置一個過期時間,異常ip如果超過這個過期時間,比如:1天,則恢復正常了,該ip可以再發(fā)起請求了。
或者限制同一個用戶id。
7. 位統(tǒng)計
比如現在有個需求:有個網站需要統(tǒng)計一周內連續(xù)登陸的用戶,以及一個月內登陸過的用戶。
這個需求使用傳統(tǒng)的數據庫,實現起來比較麻煩,但使用Redis的bitmap
讓我們可以實時的進行類似的統(tǒng)計。
bitmap 是二進制的byte數組,也可以簡單理解成是一個普通字符串。它將二進制數據存儲在byte數組中以達到存儲數據的目的。
保存數據命令使用setbit,語法:
setbit?key?offset?value
具體示例:
setbit?user:view:2024-01-17?123456?1
往bitmap數組中設置了用戶id=123456的登錄狀態(tài)為1,標記2024-01-17已登錄。
然后通過命令getbit獲取數據,語法:
getbit?key?offset
具體示例:
getbit?user:view:2024-01-17?123456
如果獲取的值是1,說明這一天登錄了。
如果我們想統(tǒng)計一周內連續(xù)登錄的用戶,只需要遍歷用戶id,根據日期中數組中去查詢狀態(tài)即可。
8. 緩存加速
我們在工作中使用Redis作為緩存加速,這種用法也是非常常見的。
如果查詢訂單數據,先從Redis緩存中查詢,如果緩存中存在,則直接將數據返回給用戶。
如果緩存中不存在,則再從數據庫中查詢數據,如果數據存在,則將數據保存到緩存中,然后再返回給用戶。
如果緩存和數據庫都不存在,則直接給用戶返回數據不存在。
流程圖如下:
但使用緩存加速的業(yè)務場景,需要注意一下,可能會出現:緩存擊穿、穿透和雪崩等問題。
9. 做消息隊列
我們說起隊列經常想到是:kafka、rabbitMQ、RocketMQ等這些分布式消息隊列。
其實Redis也有消息隊列的功能,我們之前有個支付系統(tǒng),就是用的Redis隊列功能。
PubSub(發(fā)布訂閱)是Redis2.0版本引入的消息傳遞模型。
顧名思義,消費者可以訂閱一個或多個channel,生產者向對應channel發(fā)送消息后,所有訂閱者都能收到相關消息。對應channel發(fā)送消息后,所有訂閱者都能收到相關消息。
在java代碼中可以實現MessageListener接口,來消費隊列中的消息。
@Slf4j
@Component
public?class?RedisMessageListenerListener?implements?MessageListener?{
????@Autowired
????private?RedisTemplate<String,?Object>?redisTemplate;
????@Override
????public?void?onMessage(Message?message,?byte[]?pattern)?{
????????String?channel?=?new?String(pattern);
????????RedisSerializer<?>?valueSerializer?=?redisTemplate.getValueSerializer();
????????Object?deserialize?=?valueSerializer.deserialize(message.getBody());
????????if?(deserialize?==?null)?return;
????????String?md5DigestAsHex?=?DigestUtils.md5DigestAsHex(deserialize.toString().getBytes(StandardCharsets.UTF_8));
????????Boolean?result?=?redisTemplate.opsForValue().setIfAbsent(md5DigestAsHex,?"1",?20,?TimeUnit.SECONDS);
????????if?(Boolean.TRUE.equals(result))?{
????????????log.info("接收的結果:{}",?deserialize.toString());
????????}?else?{
????????????log.info("其他服務處理中");
????????}
????}
}
10. 生成全局ID
在有些需要生成全局ID的業(yè)務場景,其實也可以使用Redis。
可以使用incrby命令,利用原子性操作,可以執(zhí)行下面這個命令:
incrby?userid?10000
在分庫分表的場景,對于有些批量操作,我們可以從Redis中,一次性拿一批id出來,然后給業(yè)務系統(tǒng)使用。
作者:蘇三說技術