日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

初识Redis,看这一篇就够了

發布時間:2023/11/27 生活经验 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 初识Redis,看这一篇就够了 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Redis (全稱: Remote Dictionary Server 遠程字典服務)是一個開源的使用 ANSI C語言 編寫、支持網絡、可基于內存亦可持久化的日志型、 Key-Value數據庫 。
環境的搭建和安裝網上有很多教程,在這里就不再重復了。

  1. Redis 是什么?

Redis (全稱: Remote Dictionary Server 遠程字典服務)是一個開源的使用 ANSI C語言 編寫、支持網絡、可基于內存亦可持久化的日志型、 Key-Value數據庫 。

大家可能知道 Redis 是做緩存用的,它實際上也是一種數據庫,可以對經常使用到的數據進行存儲,也就是大家所說的緩存。

官方給出的數據是, Redis 能達到 10w+ 的 QPS( 每秒查詢速度 ) 。

為什么 Redis 的速度比 Mysql 等這種數據快呢?

因為 Redis 存儲的是 key-values 格式的數據,時間復雜度是 O(1) ,即直接通過 key 查詢對應的 value 。 而如 Mysql 數據庫,底層的實現是 B+ 樹,時間復雜度是 O(logn) 。

最重要的一點是,數據庫的數據是存儲在磁盤中的,而 Redis 是存儲在內存當中的,它們的速度差距不言而喻。但 Redis 也支持持久化存儲,這個后面的常見問題里會提到。

  1. Redis 數據類型

Redis 支持 5 種數據類型: string (字符串)、 hash (哈希)、 list (列表,有序可重復)、 set (集合,無序不可重復)、 zset (有序集合,有序不可重復)。

Redis 中所有數據都是字符串, key 是區分大小寫的。

(1)string 是最基本的類型,可以包含任何數據,但是 string 類型的值最大能存儲 512MB 。

(2)hash 的 value 相當于一個 map , value 里面也有對應的 key-value ,特別適合存儲對象。一個 hash 可以存儲 2^32-1 個鍵值對,基本用不完。并且可以修改某一個屬性值,所以一般用于存儲用戶或其他實體類的值。

(3)list 中的 value 按照插入順序排序,可以在列表的頭部和尾部添加新元素。一般用于最新消息的排行或消息隊列。

(4)set 存放的是不重復值的集合,是無序的。并提供了求交集、并集、差集等操作,所以一般用于統計等功能。

(5)與 set 不同的是, zset 是通過分數( score )從小到大進行排序的,我們可以指定每個值的分數,分數可以重復。一般用于排行等功能。

3.Redis常用命令

基于對上面 5 種數據類型的了解,接著學習一下 Redis 常用命令。更多了命令學習,推薦大家看一看官方文檔 http://www.redis.cn/commands.html

(1)對stirng的操作

redis命令不區分大小寫。

下面命令中,str就是key,hello就是value,append為追加命令,如果原來沒有str,就新建一個。

append str hello //對key為str的鍵追加hello字符串append str
redis//str的value變為helloredisset str1 1  //set命令設置一個key的value值
str1是key,1是valueget str1 //get命令,獲取一個key的值 incr str1 
//incr命令,執行加1操作,比如str1的值會變成2,如果指定的key的value不能表示一個整數,就會返回一個錯誤decr str1 
//減一操作

(2)對hash的操作

上面說到過,hash的value相當于一個map,所以只設置值的時候myhash是key,h1是value里面的key,hello是h1的value

hset myhash h1 hello//設置一個key的value值hget myhash
h1//返回hello,myhash為key,h1是value里面的key,兩個都需要指定hlen
myhash//獲取myhash的字段數量,這里返回1hkeys myhash//獲取myhash所以字段,這里返回h1

(3)對list的操作

mylst是key,a,b,c,d都是value,并且有順序,所以實際存進去后是d,c,b,a

lpush mylist a b c d//lpush,從隊列左邊入隊一個或多個元素lrange mylist 0
-1//獲取指定范圍的值,從0開始,-1代表全部,注意這里返回d,c,b,a。rpush mylist 1 2 3//從右邊入隊,再次lrange的話就是d,c,b,a,1,2,3lpop
mylist//從左邊彈出一個元素,這里彈出d,此時的mylist就沒有d了

(4)對set的操作

如果我們添加了重復的元素,不會報錯,但只會存一個。如a b b,只會存a b

兩個集合之間不受影響,即key為myset和myset2兩個集合里面都可以有a b

sadd myset a b c d//添加一個或多個元素到集合里面smembers
myset//獲取集合里所有元素,輸出是無序的,隨機的。這里可能是b,d,c,asrem myset a
c//移除myset中的a和c元素,由于不可能重復也沒順序,所以可以直接指定元素值來移除

(5)對zset的操作

myzset為key,a b c前面的數字就是score

zadd myzset 2 b 1 a 3 c//添加一個或多個元素zrange myzset 0
-1//獲取指定范圍的值,0開始,-1代表全部。這里返回a,b,c

更多的命令可以看上面網站中的文檔,寫的非常詳細,下面的常見問題中也會提及一些。

4.Redis常見問題

(1)在大量的key中查詢某一固定前綴的key

在實際的業務當中,key的命名是有規范的,比如緩存用戶信息,key的前綴可能會是user。

現在有幾千萬條數據,查詢user為前綴的key的話,第一下想到的可能會是keys命令

keys user*//user*為正則表達式

其時間復雜度為O(n),雖然性能也算可以,但是在查詢幾千萬條數據時明顯太慢了,花上幾分鐘都不稀奇,而且在查詢出來之前,可能會造成服務卡頓,占用大量內存,顯然是不可取的。

那么這種情況就可以使用scan命令

下面的命令中,math count為可選項,可用可不用,所以需要顯示的寫出來。math意味后面會匹配一個正則表達式。count代表一次查詢10條。

這個10條不是強制的,可能會比10條少。

scan 0 math user* count 10//從0開始,查詢user為前綴的key,一次查詢10條并返回

執行上面一句話后,會返回兩個東西,一個游標,代表執行到哪了,比如執行到了14325。返回的另一個就是user為前綴的key了。

下次再執行這條語句時,把0換成14325,接著上次的位置繼續查詢。但是游標不一定是遞增的,也許下次的游標比這次還小,所以存在重復的隱患。

我們可以在業務代碼處循環查詢,記錄每次返回的游標,并把查詢的key存入到set當中,起到去重的效果。

scan,實際上就是分批查詢,速度顯然沒有keys快,在查詢大量數據時,不會對服務器造成壓力。數據量不大時依舊推薦keys。

(2)利用Redis實現分布式鎖

首先了解什么是分布式鎖。即控制分布式系統訪問共享資源的一種方式。

比如系統(或主機)A和B都需要訪問資源DataA時,當A先訪問到了DataA,這時候就需要分布式鎖來把B擋住,防止A和B彼此干擾,保證數據的一致性。

額外提一點就是,Redis命令的操作是原子性的,原子性在數據庫的事務中有體現,Redis的命令也是原子性的,要么執行要么不執行,不會出現一個命令執行到一半失敗了,但還是改變了數據的問題。

實現分布式鎖,需要解決一下幾個問題:

1.互斥性,即任意時刻只能有一個客戶端獲取鎖。

2.安全性,鎖只能有持有它的客戶端刪除,不能由其他客戶端刪除。

3.死鎖,即由于某些原因,一些客戶端出現問題不能及時釋放鎖,導致其他客戶端也不能獲取鎖。

4.容錯,當某些Redis節點出現問題時,客戶端也要能獲取到鎖。

我們可以用setnx實現鎖的功能。語法:setnx key value

僅當key不存在時,才會設置成功。成功返回1,否則返回0。

1.在對應的訪問資源的業務代碼處,對指定的key設值,如果成功了,則代表沒有其他線程執行過這段代碼,也就是沒有其他線程訪問這個資源。

如果設值失敗,就代表有其他線程占用該資源,就一直等待,直到setnx成功。

2.還有個問題就是,這個key是長期有效的,所以還需要用到expire命令,語法:expire key seconds,seconds單位為秒,用以設置對應key的過期時間。

上面兩步似乎好像是實現了鎖的功能,但是缺陷也非常明顯,如果成功設值后,在我設置時間之前客戶端就出現問題了怎么辦? 用兩個命令實現一個功能有悖于Redis的原子性 。

在Redis2.6.12版本開始,set有兩個參數,就是實現了以上兩個功能。雖然上面兩步分開的做法是錯的,但是思路是一樣的。

具體語法: set key value ex 10 nx 。ex代表過期時間,這里設置10秒過期,nx代表key是要唯一的,即一個命令實現了以上兩個步驟。

最后還有一個小問題,如果不同資源同時設置了鎖key,過期時間也是一樣的,到期后Redis同時刪除大量key時,難免會出現卡頓。

解決方法就是在設置過期值時加上隨機值。

3.利用Redis實現消息隊列

消息隊列,簡稱MQ,即消息和隊列兩個單詞的首字母縮寫。常見的消息隊列有RabbitMQ和RocketMQ等,利用Redis實現消息隊列只是熟悉下其特點,實際當中一般會使用專門的消息隊列中間件。

如果之前沒了解過消息隊列,建議搜索一下消息隊列相關知識進行一下簡單的學習。

簡單地說,消息隊列的作用就是接受客戶端的請求,然后對這些請求依次處理,一般應用請求量特別大時,比如秒殺搶購等。上面介紹數據類型時就說到了list一般用于消息隊列。

看一下list的常見操作,雖然叫做列表,但其特點和數據結構的隊列基本一模一樣。所以在用Redis實現消息隊列時,首先肯定會想到list。

1.利用list的話,仿佛 使用rpush生產消息,lpop消費消息 就行了。但是有一個小問題,lpop不會等待rpush的,當rpush還沒來得及生成數據時,這時lpop會直接返回null的。

2.既然要等待rpush生成數據,難免又會想到一個命令blpop,其語法為:blpop key seconds。 和lpop功能一樣,但是會等待指定的時間,這段時間內rpush如果生成數據的話,blpop會及時返回。

  1. 但是blpop的缺點也很明顯,當然這個缺點也存在于lpop當中,就是blpop執行完后,代表出隊,rpush生成的這條消息就沒了,而消息隊列中有的需求是需要多個消費者去接收的。

這時候就可以用上 Redis的訂閱者模式 ,Redis客戶端可以訂閱任意數量的頻道(Topic)
在Redis當中用subscribe命令訂閱一個頻道,語法subscribe topic,topic就是自定義的頻道名稱,注意是topic不是key, 不需要事先定義,直接訂閱就行了。

然后用publish生產消息,語法publish topic value,topic就是你想發布到哪個頻道,value就是數據內容,而訂閱了這個頻道的所有消費者都會接收到消息。 注意是及時收到,不需要你再去手動用命令獲取。

訂閱者模式,的確解決了以上兩種方法的缺點,但是其缺陷也很明顯,就是只有處于訂閱者模式,也就是監聽狀態下,消費者才會接受到生產者的消息,也就是及時發送及時接收的,一旦Redis客戶端下線,就永遠不會接收到這個消息了。

這就回到了前面說到的一句話,實際當中會使用專門的消息隊列中間件來說實現這些功能,以上三種方法或多或少可以實現消息隊列的功能,但是缺陷也非常明顯。

4.Redis如何做持久化

Redis是基于內存當中的,那么肯定就會有疑問了,當我關閉主機或者關閉了Redis,那Redis的數據是不是就全沒了。

持久化的作用就是,把Redis的數據存儲到磁盤當中,以免Redis的數據丟失。

Redis有兩種持久化機制,默認的一種是RDB,另一種是AOF。

1.RDB(快照)持久化會在某個時間點保存全量的數據,快照即針對內存進行的快速讀取技術。而這個時間點可以由我們的實際業務進行時間策略配置。

RDB會按照時間周期策略對數據以快照的方式保存到磁盤里,并產生一個 dump.rdb的二進制文件 。我們可以在redis.conf配置文件中save參數查看和配置時間策略。

dump.rdb文件是如何創建的呢? rdb文件可以通過兩個命令創建 ,一個是save,一個是bgsave。 要注意這里的save是redis命令,上面提到的save是配置文件里面的參數。

save命令會阻塞Redis服務器進程,直到rdb文件創建完成,一般很少使用。

bgsave命令會fork出一個子進程來創建rdb文件,不會阻塞服務器進程。fork即創建一個與父進程幾乎一樣的子進程。

bgsave的基本原理:當我們使用bgsave命令時,首先會檢查是否存在RDB/AOF子進程正在進行,有的話就返回錯誤,即當我們第一次執行了bgsave,在執行完之前其他的bgsave會被拒絕執行。

如果沒有正在進行的子進程,就會調用redis源碼里面的rdbSaveBackground這個方法,然后利用fork創建一個子進程。

RDB的缺點:

1.1.前面提到,在某個時間點會進行全量數據保存,數據量大的話由于I/O而嚴重影響到性能。

1.2.由于RDB是根據配置文件里面的時間策略進行保存的,如果發生意外情況,那么上次保存到當前時間段內的數據會發生丟失。

2.AOF(Append-Only-File)持久化 會以追加的方式(append)保存除了查詢指令以外所有變更的數據,其默認的文件名稱為 appendonly.aof 。

AOF持久化默認是關閉的,我們可以 在配置文件當中找到appendonly參數,把它的參數內容改為yes。

前面說到AOF文件會記錄所有非查詢的所有指令,最后肯定難以避免文件不斷增大的問題,最主要的問題是記錄的很多數據是不必要的。

比如循環更新一個數100次,AOF會記錄這100個過程,而我們只需要最終結果就行了。

所以, Redis提供了一個日志重寫的功能解決文件不斷增大的問題 ,可以用BGREWRITEAOF命令手動執行。日志重寫在服務不中斷的情況下也能執行, 其基本原理如下 :

1.使用fork創建一個子進程。2.子進程把新的AOF寫道一個臨時文件里,并不會依賴現有的AOF文件,只需要讀取內存中的數據。這里就優化了很多不必要的數據。

2.主進程這時候會依舊將新的變動寫到內存里,也會寫到現有的AOF文件里,即使子進程重寫失敗,數據也不會丟失。4.主進程獲取到子進程AOF重寫完成的信號后,會把新的變動追加到新的AOF文件里。

3.最后使用新的AOF文件替換掉原來的AOF文件。

如果啟用了AOF持久化,Redis啟動時會先檢查AOF文件是否存在,如果存在就直接加載AOF文件,如果不存在就檢查RDB文件是否存在,如果存在就加載,不存在就直接啟動Redis。

在Redis4.0之后,推出了RDB-AOF混合持久化方式并作為默認方式,RDB全量保存,AOF增量保存,集成了它們各自的優點。

5.SpringBoot整合Redis

首先在依賴項里面添加redis啟動器

spring-boot-starter-data-redis

然后在配置文件里面進行相關的配置,更多的配置可以看RedisProperties.java源碼查看。

spring.redis.host=127.0.0.1 #redis地址spring.redis.port=6379
#redis服務端口號

最后注入相關的類

//操作的是復雜類型,比如各種實體類@AutowiredRedisTemplate
redisTemplate//操作的是字符串@AutowiredStringRedisTemplate
stringRedisTemplate

SpringBoot框架下對Redis的操作不像Jedis那樣可以直接使用原生的Redis命令,具體的API大家可以自行搜索相關的文檔。

不過推薦使用一些SpringBoot的Redis工具類,工具類會對 RedisTemplate和StringRedisTemplate的方法進行封裝,而封裝后的方法名和Redis原生命令是一樣的。

最后,希望閱讀此文后能讓你軟件開發的過程中 ,能更好的學習Redis。另外小編分類整理了許多java進階學習材料和BAT面試題,需要資料的請轉發此文章后再私聊小編回復【java】就能領取2019年java進階學習資料和BAT面試題以及《Effective Java》(第3版)電子版書籍。也可以加群:712263501領取海量學習資料進行學習。

總結

以上是生活随笔為你收集整理的初识Redis,看这一篇就够了的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。