【Redis的那些事 · 上篇】Redis的介紹、五種數據結構演示和分佈式鎖
Redis是什麼
Redis,全稱是Remote Dictionary Service,翻譯過來就是,遠程字典服務。
redis屬於nosql非關係型數據庫。Nosql常見的數據關係,基本上是以key-value鍵值對形式存在的。
Key-value: 就像翻閱中文字典或者單詞字典,通過指定的需要查詢的字或者單詞(key),可以查找到字典裏面對應的詳細內容和介紹(value)
Redis的一些特點:支持數據持久化、支持多種數據結構、支持數據備份、原子性操作等。
原子性:操作不能被中途打斷。
Redis的由來
Redis的作者:意大利人 —— Salvatore Sanfilippo,現在至少四十幾歲了,還在寫代碼。
Redis靈感來源:Alessia Merz,意大利一個舞者女郎。Merz在意大利有愚蠢的含義(俚語)。於是,Redis的默認服務端口號6379的來源靈感,來自於Mers這個詞,詳情可看九宮格輸入法:
Redis的安裝
Mac系統:brew install redis
Linux系列系統:apt-get install redis 或 yum install redis 或apt-get install redis-server 或 yum install redis-server
Windows系統:下載地址://github.com/tporadowski/redis/releases
Redis啟動方式
Mac/Linux: 啟動服務端redis-server 啟動客戶端:redis-cli
如果需要後台啟動,需要修改 redis.conf 文件,設置daemonize 為 yes
然後使用 redis-server /xxx/redis.conf 指定配置文件進行啟動。xxx是指定的路徑。
以下下載的姿勢可能不對,版本有點低,所以後面暫且用windows環境下的進行測試。
Windows啟動方式:雙擊redis-server.exe文件即可運行
可以點擊cli.exe文件,啟動客戶端。
輸入ping,返回pong,代表服務是通的。
通過使用:set key value
可以用來設置一個鍵值對。
通過:get key
可以獲取到key對應的value值。
通過命令創建redis密碼: config set requirepass 密碼
通過使用 命令:auth 密碼
進行redis權限驗證。
使用:keys * 可以顯示所有當前存在的key
使用命令: select index
可以選擇指定的Redis的Index(數據庫)。Redis默認有最多16個數據庫(或者叫Index),默認從0開始。例如上面設置的默認是0庫,選擇1庫進行查詢,就會沒有東西。
Redis的數據結構
Redis的數據結構,體現在key-value的value上。Key默認都是字符串,value的基本數據結構包括字符串(string)、列表(list)、哈希(hash)、集合(set)、有序集合(zset)
字符串數據結構
字符串在redis裏面是可變的。用一個圖來簡單說明一下。
字符串存儲規則:Redis存儲字符串期間,額外的空間分配規則是,當數據小於1MB的時候,每次擴容的空間是成倍增長的。大於1MB的時候,每次擴容的空間是1MB。
上面這段話如果不太理解,可以看Redis源碼,源碼內容如下。
並且String單個數據最大的長度為 2^32-1=512M
關於字符串的其他操作:
使用命令: exists key
可以查看是否存在該key;
使用命令:del key
可以直接刪除指定的key以及對應的value。
如果已有key,使用:set key xxx
會直接把key原有的值設置為xxx
使用命令: expire key second
可以給指定的key設置過期時間。例如我設置了10s過期,十秒以後,就會被自動銷毀了。
使用命令: setex key second value
可以設置key-value鍵值對,並且可以同時設置過期時間的秒數。
使用命令: ttl key
可以查看指定的key的剩餘的過期時間。
對於數值型的字符串,可以使用命令:incr key 和 decr key 進行自增1和自減1
使用命令:incrby key number 和 decrby key number 進行自增或自減指定的數值。
可以通過批量設置命令:mset key value key value……
進行批量設置。
通過:mget key key key……
進行批量讀取。不過mget批量讀取的結果集是個列表(因為帶有序號)
列表數據結構
Redis的列表,最大可以存儲40億+個元素(2^32-1)。
列表的插入速度很快,時間複雜度是O,但是當數據量特別龐大的時候,使用索引進行查詢操作會變得很慢,因為通過索引定位查詢的時間複雜度為O(n)。
設置列表的key和value命令:lpush key value value value ……
可以設置一個key,帶有多個元素的列表。l:left,代表的是左邊,相當於每個元素是從左邊被寫入的(倒序插入)。
使用命令: lpop key
可以取出最左邊的元素的值,同時會把該值捨棄掉。
rpush是依次從右邊插入(正序插入),rpop是取出最右邊的元素的值,然後捨棄掉。r: right,代表右邊
可以使用命令:linsert key before|after 指定的value 要插入的value
進行插入元素。before 會把要插入的元素插入到指定的value的前面;after會把要插入的元素插入到指定的value的後面。
通過使用命令:lset key index 新的value
可以把列表指定的索引對應的值給替換掉。
可以通過命令:lindex key index
獲取指定的索引的值,並且不會被捨棄。操作索引期間,需要注意時間複雜度,元素多的情況下慎用。
可以使用命令:lrange key 起始索引 結束索引
獲取在索引區間的所有元素。元素包含起始索引和結束索引的值。
列表還可以用來當作消息隊列使用,因為列表存取的一些方式,可以用來先進先出、先進後出等堆棧操作,先進先出與消息隊列機制雷同。
哈希數據結構
哈希數據結構,可以當作是字典(key-value)裏面嵌套了個字典(value數據類型又是一個 key-value的結構)。類似Json,或者類似俄羅斯套娃,例如:
person:{
「Name」:」wesky」,
「age」:18
}
使用命令: hset key field value
可以設置哈希數據結構的key,以及一個屬性和屬性對應的值。
使用命令:hget key field
可以獲取指定哈希數據的key對應的屬性的值。
使用命令:hmset key field value field value ……
可以批量設置哈希數據指定key的多個屬性和值。
使用命令:hmget key field1 field2 ……
可以批量獲取指定的key下指定的多個屬性的值。
使用命令:hgetall key
可以獲取指定的哈希數據的key下的所有屬性和值的列表。如下圖所示。
使用命令:hkeys key
可以獲取哈希數據指定key的所有屬性名稱的列表;
使用命令:hvals key
可以獲取哈希數據指定key的所有屬性的值的列表;
使用命令: hlen key
可以獲取到哈希數據裏面指定key的屬性個數。
集合數據結構
集合結構也可以看成是一個沒有屬性值的哈希數據結構,並且屬性不能重複且無序的。
類似於:
Person{
「name」,
「age」
}
使用命令: sadd key field1 field2……
可以設置集合的key和元素集。由於集合是不可重複的,所以重複新增的元素會被自動剔除。
使用命令:smembers key
可以返回指定集合的所有元素;
使用命令:scard key
可以查詢集合元素的個數;
使用命令:srandmember key (number:可選)
可以隨機返回指定集合的一個或多個元素。不指定個數,即返回一個。
集合數據,可以進行一些集合運算操作。
命令:sdiff key1 key2
可以比較集合key1和集合key2的差集,差集結果為寫在前面的集合元素減去後面集合的元素;
命令:sinter key1 key2
可以獲取到集合key1和集合key2的交集。
命令:sunion key1 key2
可以獲取集合key1和集合key2的並集。
有序集合
有序集合比較常見的一個場景,是用來做排行榜。
命令:zadd key score1(分數,用於排行的值) member1(集合的元素) score2(分數,用於排行的值) member2(集合的元素) ……
可以用來新增有序集合。其中,分數代表權重,值越低,排越前。
命令:zrange key 起始索引 結束索引
可以查詢指定集合索引區間的所有元素的屬性。
命令: zincrby key 增加權重值 menber
可以對有序集合指定的元素進行增加權重(對分數進行增加指定的值)
命令:zcard key
可以獲取有序集合的個數;
命令: zcount key 最小分數 最大分數
可以獲取到有序集合在指定的分數區間的所有元素;
命令:zcount key member
可以獲取有序集合裏面指定的元素當前的分數;
命令:zrange key 起始索引 結束索引 withscores
可以獲取到有序索引裏面指定的索引區間內所有的元素以及元素對應的分數。
備註:以上五種數據結構,都屬於容器型,它們的特點是,當沒有元素的時候,會被自動釋放掉。
Redis分佈式鎖
Redis的操作是原子性的,如果存在多客戶端同時操作的情況下,會發生一些干擾問題。原子性指的是,redis在進行讀寫期間是不會被打斷的,會一直進行到底。下面用一個圖片進行說明。
如上圖所示,A和B同時都要操作Redis數據庫裏面的Key1。假設此刻Key1存儲的是銀行的存款,然後在A的地方消費掉了,此刻A觸發了扣減餘額的操作。這個時候,修改redis的值是通過先讀取值出來到內存裏面,然後進行扣減的;讀取出來的時候,還沒扣減完成,這個時候B(比如說是信用卡自動還款扣錢)也要扣減Key1的餘額,也要進行先讀取出來,然後才進行扣減。由於Redis是原子性操作,所以A的步驟不會被打斷,B也不會被打斷。這個時候,A扣減完成了,例如原本餘額是100元,扣減了10元,A更改完畢以後,值變成了90元。此刻,B也要扣減,例如扣減20元,但是讀取的是A改完之前的值,所以改完以後是80元。以上就產生了衝突,於是就有了Redis的分佈式鎖用來避免這個問題。
通過命令: set key value ex second nx
可以設置一個鎖,key代表鎖的名稱,value是值;second是鎖的超時時間。
如下圖所示,我開了兩個客戶端,並且標註了我的操作順序號。
鎖如果沒有過期或刪除,其他客戶端創建鎖會失敗;但是其他客戶端也可以刪除鎖,所以具有一定風險。建議可以對鎖設置不同客戶端所需要的不同的值用來區分。然後把需要操作的地方,放到鎖裏面操作,來避免產生的同時操作產生的問題。
例如偽代碼:
If(exists(lock)) { return false; // 存在鎖,修改失敗 } Else
{ Set lock true ex 5 nx; Set key1 100; del lock; Return true; // 修改成功 }
今天暫且寫到這兒了,後續還有redis的位圖、布隆過濾器、限流、線程模型、通訊協議、訂閱模式、管道、內存回收、源碼解讀等等內容,敬請期待~~
今天2021-12-18剛好也是自己生日(農曆11月15),祝自己生日快樂。同時也祝大家學習愉快~~
歡迎各位大佬留下寶貴意見,歡迎點贊、推薦、或者留言~~ 感謝觀看!