參考地址
- https://juejin.cn/post/7079756129433370638
- https://blog.csdn.net/gaogaoshan/article/details/41039581
- https://redis.io/docs/clients/go/
redis的使用場景的解釋
下面一一來分析下Redis的應(yīng)用場景都有哪些。
1、緩存
緩存現(xiàn)在幾乎是所有中大型網(wǎng)站都在用的必殺技,合理的利用緩存不僅能夠提升網(wǎng)站訪問速度,還能大大降低數(shù)據(jù)庫的壓力。Redis提供了鍵過期功能,也提供了靈活的鍵淘汰策略,所以,現(xiàn)在Redis用在緩存的場合非常多。
2、排行榜
很多網(wǎng)站都有排行榜應(yīng)用的,如京東的月度銷量榜單、商品按時(shí)間的上新排行榜等。Redis提供的有序集合數(shù)據(jù)類構(gòu)能實(shí)現(xiàn)各種復(fù)雜的排行榜應(yīng)用。
3、計(jì)數(shù)器
什么是計(jì)數(shù)器,如電商網(wǎng)站商品的瀏覽量、視頻網(wǎng)站視頻的播放數(shù)等。為了保證數(shù)據(jù)實(shí)時(shí)效,每次瀏覽都得給+1,
并發(fā)量高時(shí)如果每次都請(qǐng)求數(shù)據(jù)庫操作無疑是種挑戰(zhàn)和壓力。Redis提供的incr命令來實(shí)現(xiàn)計(jì)數(shù)器功能,內(nèi)存操作,性能非常好,非常適用于這些計(jì)數(shù)場景。
4、分布式會(huì)話
集群模式下,在應(yīng)用不多的情況下一般使用容器自帶的session復(fù)制功能就能滿足,當(dāng)應(yīng)用增多相對(duì)復(fù)雜的系統(tǒng)中,一般都會(huì)搭建以Redis等內(nèi)存數(shù)據(jù)庫為中心
的session服務(wù),session不再由容器管理,而是由session服務(wù)及內(nèi)存數(shù)據(jù)庫管理。
5、分布式鎖
在很多互聯(lián)網(wǎng)公司中都使用了分布式技術(shù),分布式技術(shù)帶來的技術(shù)挑戰(zhàn)是對(duì)同一個(gè)資源的并發(fā)訪問,如全局ID、減庫存、秒殺等場景,
并發(fā)量不大的場景可以使用數(shù)據(jù)庫的悲觀鎖、樂觀鎖來實(shí)現(xiàn),但在并發(fā)量高的場合中,利用數(shù)據(jù)庫鎖來控制資源的并發(fā)訪問是不太理想的,
大大影響了數(shù)據(jù)庫的性能。可以利用Redis的setnx功能來編寫分布式的鎖,如果設(shè)置返回1說明獲取鎖成功,否則獲取鎖失敗,實(shí)際應(yīng)用中要考慮的細(xì)節(jié)要更多。
6、社交網(wǎng)絡(luò)
點(diǎn)贊、踩、關(guān)注/被關(guān)注、共同好友等是社交網(wǎng)站的基本功能,社交網(wǎng)站的訪問量通常來說比較大,而且傳統(tǒng)的關(guān)系數(shù)據(jù)庫類型不適合存儲(chǔ)這種類型的數(shù)據(jù),
Redis提供的哈希、集合等數(shù)據(jù)結(jié)構(gòu)能很方便的的實(shí)現(xiàn)這些功能。
7、最新列表
Redis列表結(jié)構(gòu),LPUSH可以在列表頭部插入一個(gè)內(nèi)容ID作為關(guān)鍵字,LTRIM可用來限制列表的數(shù)量,這樣列表永遠(yuǎn)為N個(gè)ID,無需查詢最新的列表,
直接根據(jù)ID去到對(duì)應(yīng)的內(nèi)容頁即可。
8、消息系統(tǒng)
消息隊(duì)列是大型網(wǎng)站必用中間件,如ActiveMQ、RabbitMQ、Kafka等流行的消息隊(duì)列中間件,主要用于業(yè)務(wù)解耦、流量削峰及異步處理實(shí)時(shí)性低的業(yè)務(wù)。
Redis提供了發(fā)布/訂閱及阻塞隊(duì)列功能,能實(shí)現(xiàn)一個(gè)簡單的消息隊(duì)列系統(tǒng)。另外,這個(gè)不能和專業(yè)的消息中間件相比。
9、地理位置
使用Redis的Geo數(shù)據(jù)類型可以存儲(chǔ)地理位置信息,實(shí)現(xiàn)地理位置相關(guān)的查詢和分析。
10、搜索引擎
Redis的Sorted Set可以用來存儲(chǔ)有序數(shù)據(jù),例如排行榜、搜索結(jié)果等。
在Go語言中,可以使用ZADD、ZRANGE等命令來實(shí)現(xiàn)對(duì)Sorted Set的操作,實(shí)現(xiàn)搜索引擎的功能。
常用命令
- SET 和 GET:用于設(shè)置和獲取字符串類型的值;
- HSET、HGET、HMSET、HMGET:用于設(shè)置和獲取哈希類型的值;
- LPUSH、RPUSH、LPOP、RPOP:用于操作列表類型的值;
- SADD、SREM、SMEMBERS:用于操作集合類型的值;
- ZADD、ZREM、ZRANGE:用于操作有序集合類型的值;
- INCR、INCRBY、DECR、DECRBY:用于對(duì)整數(shù)類型的值進(jìn)行原子性的加減操作;
- EXPIRE、TTL:用于設(shè)置和查詢鍵的過期時(shí)間;
- PUBLISH、SUBSCRIBE:用于實(shí)現(xiàn) Redis 的發(fā)布訂閱功能;
- MULTI、EXEC、WATCH、UNWATCH:用于實(shí)現(xiàn) Redis 的事務(wù)功能;
- SCAN:用于迭代大量的鍵,避免阻塞 Redis 服務(wù)器。
實(shí)際場景
- 緩存
- 數(shù)據(jù)共享分布式
- 分布式鎖
- 全局ID
- 計(jì)數(shù)器
- 限流
- 位統(tǒng)計(jì)
- 購物車
- 用戶消息時(shí)間線timeline
- 消息隊(duì)列
- 抽獎(jiǎng)
- 點(diǎn)贊、簽到、打卡
- 商品標(biāo)簽
- 商品篩選
- 用戶關(guān)注、推薦模型
- 排行榜
1、緩存
String類型
例如:熱點(diǎn)數(shù)據(jù)緩存(例如報(bào)表、明星出軌),對(duì)象緩存、全頁緩存、可以提升熱點(diǎn)數(shù)據(jù)的訪問數(shù)據(jù)。
2、數(shù)據(jù)共享分布式
String 類型,因?yàn)?Redis 是分布式的獨(dú)立服務(wù),可以在多個(gè)應(yīng)用之間共享
例如:分布式Session
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
3、分布式鎖
String 類型setnx方法,只有不存在時(shí)才能添加成功,返回true
public static boolean getLock(String key) {
Long flag = jedis.setnx(key, "1");
if (flag == 1) {
jedis.expire(key, 10);
}
return flag == 1;
}
public static void releaseLock(String key) {
jedis.del(key);
}
4、全局ID
int類型,incrby,利用原子性
incrby userid 1000
分庫分表的場景,一次性拿一段
5、計(jì)數(shù)器
int類型,incr方法
例如:文章的閱讀量、微博點(diǎn)贊數(shù)、允許一定的延遲,先寫入Redis再定時(shí)同步到數(shù)據(jù)庫
6、限流
int類型,incr方法
以訪問者的ip和其他信息作為key,訪問一次增加一次計(jì)數(shù),超過次數(shù)則返回false
7、位統(tǒng)計(jì)
String類型的bitcount(1.6.6的bitmap數(shù)據(jù)結(jié)構(gòu)介紹)
字符是以8位二進(jìn)制存儲(chǔ)的
set k1 a
setbit k1 6 1
setbit k1 7 0
get k1
/* 6 7 代表的a的二進(jìn)制位的修改
a 對(duì)應(yīng)的ASCII碼是97,轉(zhuǎn)換為二進(jìn)制數(shù)據(jù)是01100001
b 對(duì)應(yīng)的ASCII碼是98,轉(zhuǎn)換為二進(jìn)制數(shù)據(jù)是01100010
因?yàn)閎it非常節(jié)省空間(1 MB=8388608 bit),可以用來做大數(shù)據(jù)量的統(tǒng)計(jì)。
*/
例如:在線用戶統(tǒng)計(jì),留存用戶統(tǒng)計(jì)
setbit onlineusers 01
setbit onlineusers 11
setbit onlineusers 20
支持按位與、按位或等等操作
BITOPANDdestkeykey[key...] ,對(duì)一個(gè)或多個(gè) key 求邏輯并,并將結(jié)果保存到 destkey 。
BITOPORdestkeykey[key...] ,對(duì)一個(gè)或多個(gè) key 求邏輯或,并將結(jié)果保存到 destkey 。
BITOPXORdestkeykey[key...] ,對(duì)一個(gè)或多個(gè) key 求邏輯異或,并將結(jié)果保存到 destkey 。
BITOPNOTdestkeykey ,對(duì)給定 key 求邏輯非,并將結(jié)果保存到 destkey 。
計(jì)算出7天都在線的用戶
BITOP "AND" "7_days_both_online_users" "day_1_online_users" "day_2_online_users" ... "day_7_online_users"
8、購物車
String 或hash。所有String可以做的hash都可以做
key:用戶id;field:商品id;value:商品數(shù)量。
+1:hincr。-1:hdecr。刪除:hdel。全選:hgetall。商品數(shù):hlen。
9、用戶消息時(shí)間線timeline
list,雙向鏈表,直接作為timeline就好了。插入有序
10、消息隊(duì)列
List提供了兩個(gè)阻塞的彈出操作:blpop/brpop,可以設(shè)置超時(shí)時(shí)間
blpop:blpop key1 timeout 移除并獲取列表的第一個(gè)元素,如果列表沒有元素會(huì)阻塞列表直到等待超時(shí)或發(fā)現(xiàn)可彈出元素為止。
brpop:brpop key1 timeout 移除并獲取列表的最后一個(gè)元素,如果列表沒有元素會(huì)阻塞列表直到等待超時(shí)或發(fā)現(xiàn)可彈出元素為止。
上面的操作。其實(shí)就是java的阻塞隊(duì)列。學(xué)習(xí)的東西越多。學(xué)習(xí)成本越低
- 隊(duì)列:先進(jìn)先除:rpush blpop,左頭右尾,右邊進(jìn)入隊(duì)列,左邊出隊(duì)列
- 棧:先進(jìn)后出:rpush brpop
11、抽獎(jiǎng)
自帶一個(gè)隨機(jī)獲得值
spop myset
12、點(diǎn)贊、簽到、打卡
假如上面的微博ID是t1001,用戶ID是u3001
用 like:t1001 來維護(hù) t1001 這條微博的所有點(diǎn)贊用戶
- 點(diǎn)贊了這條微博:sadd like:t1001 u3001
- 取消點(diǎn)贊:srem like:t1001 u3001
- 是否點(diǎn)贊:sismember like:t1001 u3001
- 點(diǎn)贊的所有用戶:smembers like:t1001
- 點(diǎn)贊數(shù):scard like:t1001
13、商品標(biāo)簽
老規(guī)矩,用 tags:i5001 來維護(hù)商品所有的標(biāo)簽。
sadd tags:i5001 畫面清晰細(xì)膩
sadd tags:i5001 真彩清晰顯示屏
sadd tags:i5001 流程至極
14、商品篩選
// 獲取差集
sdiff set1 set2
// 獲取交集(intersection)
sinter set1 set2
// 獲取并集
sunion set1 set2
假如:iPhone15 上市了
sadd brand:apple iPhone11
sadd brand:ios iPhone11
sad screensize:6.0-6.24 iPhone11
sad screentype:lcd iPhone 11
篩選商品,蘋果的、ios的、屏幕在6.0-6.24之間的,屏幕材質(zhì)是LCD屏幕
sinter brand:apple brand:ios screensize:6.0-6.24 screentype:lcd
15、用戶關(guān)注、推薦模型
follow 關(guān)注 fans 粉絲
相互關(guān)注:
sadd 1:follow 2
sadd 2:fans 1
sadd 1:fans 2
sadd 2:follow 1
我關(guān)注的人也關(guān)注了他(取交集):
sinter 1:follow 2:fans
可能認(rèn)識(shí)的人:
用戶1可能認(rèn)識(shí)的人(差集):sdiff 2:follow 1:follow
用戶2可能認(rèn)識(shí)的人:sdiff 1:follow 2:follow
16、排行榜
id 為6001 的新聞點(diǎn)擊數(shù)加1:文章來源:http://www.zghlxwxcb.cn/news/detail-801116.html
zincrby hotNews:20190926 1 n6001
獲取今天點(diǎn)擊最多的15條:文章來源地址http://www.zghlxwxcb.cn/news/detail-801116.html
zrevrange hotNews:20190926 0 15 withscores
go的incr+expire原子性操作之調(diào)用lua腳本
- 它實(shí)現(xiàn)了 incr 和 expire 的原子化操作,并且在 key 不存在和 key 已經(jīng)過期的情況下也能正常工作。
package main
import (
"context"
"fmt"
"github.com/go-redis/redis/v8"
"time"
)
// Lua腳本
// 通過執(zhí)行一個(gè) Lua 腳本來實(shí)現(xiàn)原子化的 incr 和 expire 操作。如果該 key 的過期時(shí)間已經(jīng)設(shè)置為 -1,
// 則表示該 key 沒有過期時(shí)間,此時(shí)通過 expire 命令為該 key 設(shè)置過期時(shí)間。
func main(){
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "123456",
DB: 10,
})
defer client.Close()
result1, err1 := IncrWithTTL(client, "counter", 3600)
if err1 != nil {
fmt.Println(err1)
} else {
fmt.Println(result1)
}
}
func IncrWithTTL(client *redis.Client, key string, ttl time.Duration) (int64, error) {
script := redis.NewScript(`
local value = redis.call("incr", KEYS[1])
if redis.call("ttl", KEYS[1]) == -1 then
redis.call("expire", KEYS[1], ARGV[1])
end
return value
`)
result, err := script.Run(context.Background(), client, []string{key}, ttl.String()).Result()
if err != nil {
return 0, err
}
return result.(int64), nil
}
到了這里,關(guān)于Go新項(xiàng)目-調(diào)研關(guān)于go項(xiàng)目中redis的使用場景,lua實(shí)戰(zhàn)(7)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!