作為一名 JAVA后端人員,對 redis肯定并不陌生,Redis作為一種內(nèi)存數(shù)據(jù)庫,以其速度之快在編程的舞臺上縱橫多年,那么,Redis到底適合哪些業(yè)務(wù)場景?今天就來聊一聊。
1. 緩存/數(shù)據(jù)庫
緩存(Cache)是 Redis使用最廣泛的場景之一,也是很多小伙伴結(jié)識 Redis的重要原因,在 8種10倍提升API性能的方式 文章中我們也強(qiáng)調(diào)了Redis可以作為緩存的來加速 API性能。如下圖,在 WebServer和數(shù)據(jù)庫之間會增加一層 Redis緩存,這樣 WebServer可以直接從Redis中快速拿到數(shù)據(jù)返回,加快了 WebServer的響應(yīng)速度。
舉例:
- 電商領(lǐng)域,可以緩存一些熱門商品的靜態(tài)信息或用戶數(shù)據(jù),這樣,在大流量訪問時,不用查詢數(shù)據(jù)庫,加速訪問速度。
- 配置中心,業(yè)務(wù)開發(fā)中,經(jīng)常會使用一些全局配置,而且配置更改的頻率很低,因此,可以把配置都加載到 Redis內(nèi)存中,加快查詢數(shù)據(jù)。
需要說明的是:很多時候,我們都會把 Redis的持久化功能打開,因此,在把 Redis當(dāng)作緩存的同時,同樣把 Redis當(dāng)作數(shù)據(jù)庫在使用。
2. 分布式鎖
分布式鎖(Distributed Lock)也是 Redis使用最廣泛的場景之一,分布式系統(tǒng)中,當(dāng)我們在處理有并發(fā)的業(yè)務(wù)場景時,為了保證線程安全,通常通常會使用分布式鎖,單機(jī)下,Redis通常使用 SET NX(if Not Exist)和 PX(過期時間)來創(chuàng)建鎖,指令如下:
# 如果key不存,set key=value,
# 失效時間是 expiration毫秒
SET key value NX PX expiration
在 Java中,Redission是一個基于 Redis的分布式Java對象映射(Java Redis Client),它提供了豐富的特性和工具,示例代碼展示了如何在 Redission框架中使用 Redis分布式鎖:
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
public class RedissonExample {
public static void mAIn(String[] args) {
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
RedissonClient redisson = Redisson.create(config);
// 使用分布式鎖
String lockKey = "lockKey";
boolean isLocked = redisson.getLock(lockKey).tryLock();
if (isLocked) {
// 獲得鎖,執(zhí)行相關(guān)操作
System.out.println("Lock acquired successfully");
redisson.getLock(lockKey).unlock(); // 釋放鎖
} else {
System.out.println("Failed to acquire lock");
}
redisson.shutdown(); // 關(guān)閉連接
}
}
需要說明的是:除了Redis,Zookeeper也是實現(xiàn)分布式鎖比較常用的一種技術(shù)方案。
3. 限流
限流(Rate Limiter)也是 Redis使用比較多的一個場景,限流是保護(hù)系統(tǒng)免受過載的一種方法,它可以確保在指定時間內(nèi)對系統(tǒng)的請求進(jìn)行限制。在 Redis 中,可以使用 SET、EXPIRE 和 Lua 腳本來實現(xiàn)簡單的限流功能。
示例代碼展示了Java Jedis 庫實現(xiàn)基于令牌桶算法的 Redis 限流:
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Response;
import redis.clients.jedis.Transaction;
public class RateLimiter {
private final Jedis jedis;
private final String key;
private final int capacity;
private final int tokensPerSecond;
public RateLimiter(Jedis jedis, String key, int capacity, int tokensPerSecond) {
this.jedis = jedis;
this.key = key;
this.capacity = capacity;
this.tokensPerSecond = tokensPerSecond;
}
/**
* 用于檢查是否允許請求,根據(jù)當(dāng)前令牌數(shù)量和容量進(jìn)行判斷
*/
public boolean allowRequest() {
long now = System.currentTimeMillis();
Transaction transaction = jedis.multi();
// Add current time with score
transaction.zadd(key, now, String.valueOf(now));
// Remove tokens that are older than 1 second
transaction.zremrangeByScore(key, 0, now - 1000);
// Get current number of tokens
Response<Long> sizeResponse = transaction.zcard(key);
transaction.exec();
long size = sizeResponse.get();
// Check if number of tokens is within capacity
return size <= capacity;
}
public static void main(String[] args) {
Jedis jedis = new Jedis("localhost"); // Connect to Redis
// Create rate limiter
RateLimiter rateLimiter = new RateLimiter(jedis, "RateLimiterKey", 10, 5);
for (int i = 0; i < 15; i++) {
boolean allowed = rateLimiter.allowRequest();
if (allowed) {
System.out.println("Request allowed");
} else {
System.out.println("Request denied");
}
}
// Close Redis connection
jedis.close();
}
}
4. 會話存儲
會話(Session)也是 Redis常見的一種功能,熟悉 Spring的小伙伴肯定知道它也有一個 Session功能,那么它和 Redis的 Session有什么區(qū)別呢?
Spring Session是一個抽象層,提供與存儲后端銜接能力,至于后端采用內(nèi)存、數(shù)據(jù)庫還是Redis存儲Spring Session不關(guān)注。而 Redis Session是 Spring Session的一種具體實現(xiàn),將會話數(shù)據(jù)存儲在Redis中。
舉例:存儲用戶登錄信息:
#將用戶的登錄信息存儲在 Redis中,key:userId, value:user登錄信息
SET user:userId {"username": "xxx", "password": "xxx",...}
5. 發(fā)布/訂閱
發(fā)布/訂閱(Sub/Pub)是 Redis中一個類似于消息中間件(MQ)的功能,當(dāng)我們的業(yè)務(wù)中有需要通過事件觸發(fā)的場景時可以使用該功能,不過 Redis的 Sub/Pub功能還是比較簡陋,有復(fù)雜的業(yè)務(wù)場景時還是推薦MQ。
舉例:
群聊,在實時聊天應(yīng)用中,利用 Redis的發(fā)布/訂閱功能實現(xiàn)消息廣播。
實現(xiàn)事件通知系統(tǒng),如新訂單通知、新郵件提醒等。
#訂閱頻道
SUBSCRIBE channel_xxx
# 向頻道中發(fā)送消息
PUBLISH channel_xxx "Message content"
6. 排名/排行榜
排名/排行榜(Rank/LeaderBoard)是 Redis中一個比較實用的功能,在文章熱榜、游戲競技或社區(qū)平臺中,排行榜(Leaderboard)和排名(Ranking)系統(tǒng)是常見的功能,用于展示用戶在特定活動、比賽或指標(biāo)上的排名情況,而 Redis的有序集合(Sorted Set)是實現(xiàn)排行榜功能的理想數(shù)據(jù)結(jié)構(gòu),因為它可以存儲每個成員的分?jǐn)?shù),并根據(jù)分?jǐn)?shù)進(jìn)行排序。
舉例:
(1) 記錄網(wǎng)站訪問次數(shù)或文章閱讀次數(shù)。
# 添加文章的點擊量
#將 Article1 的值增加1。如果Article1 不存在于有序集合中,
# 該命令會將 Article1 添加到集合,并設(shè)置值為1
ZINCRBY leaderboard 1 "Article1"
ZINCRBY leaderboard 1 "Article2"
ZINCRBY leaderboard 1 "Article3"
# 獲取 Article2的排名(從高到低排名)
ZREVRANK leaderboard "Article2"
# 獲點擊量 Top10 的文章和點擊量
ZREVRANGE leaderboard 0 9 WITHSCORES
(2) 實現(xiàn)用戶積分排行榜。
7. 計數(shù)
在 Redis中,可以使用 INCR、DECR 等命令來進(jìn)行簡單的計數(shù)操作。這些命令用于對鍵的值進(jìn)行遞增或遞減操作,常用于實現(xiàn)計數(shù)器等功能。
常用計數(shù)命令:
# 對 key進(jìn)行 +1 操作
INCR key
# 對key 進(jìn)行 -1 操作
DECR key
# 對 key進(jìn)行 +n 操作
INCRBY key n
# 對 key進(jìn)行 -n 操作
DECRBY key n
另外,在排名/排行榜中,ZINCRBY 是對 Sort set的一種計數(shù)方式。
舉例:
- 網(wǎng)站訪問量計數(shù)器,可以實時統(tǒng)計網(wǎng)站的訪問次數(shù);
- 點贊/喜歡計數(shù)器,對文章或內(nèi)容的點贊或喜歡次數(shù)進(jìn)行計數(shù);
- 用戶在線狀態(tài)統(tǒng)計,統(tǒng)計在線用戶數(shù)量;
8. 地理位置應(yīng)用
Redis的地理位置應(yīng)用功能使用的場景比較有針對性,如果你不是在特定的領(lǐng)域,可能并不會使用該功能,它是 通過 Geo數(shù)據(jù)類型支持地理位置存儲和檢索,可以用于構(gòu)建位置服務(wù)和地理位置相關(guān)的應(yīng)用。
舉例:
(1) 點過外賣的小伙伴肯定不陌生,外賣平臺上,附近商家搜索功能。
# 查找經(jīng)度12.087269,緯度39.412669 附近5 km的距離范圍
GEORADIUS locations 12.087269 39.412669 5 km
(2) 打車平臺,比如一些網(wǎng)約車平臺,就可以把司機(jī),乘客的位置信息(經(jīng)緯度)通過Redis的Geo來實現(xiàn)距離計算等功能。
# 添加經(jīng)緯度信息,經(jīng)緯度是編造的,不一定真實
GEOADD locations 12.322389 39.125356 "Driver"
GEOADD locations 12.087269 39.412669 "Passenger"
# 計算司機(jī)和乘客兩地點間的距離
GEODIST locations Driver Passenger
總結(jié)
本文介紹了Redis常見的 8種實用場景:
- 緩存/數(shù)據(jù)庫
- 分布式鎖
- 限流
- 會話存儲
- 發(fā)布/訂閱
- 排名/排行榜
- 計數(shù)
- 地理位置應(yīng)用
如果你在業(yè)務(wù)中不確定是否需要引入 Redis時,可以參考本文,如果場景剛好命中其中一種,那么可以選擇使用 Redis。如果你的業(yè)務(wù)場景不在這 8種常見場景中,不代表不能使用 Redis,可能需要你更多的技術(shù)調(diào)研來確認(rèn)合適的技術(shù)方案。
最后,把猿哥的座右銘送給你:投資自己才是最大的財富。