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系統:下載地址:https://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是鎖的超時時間。
如下圖所示,我開了兩個客戶端,并且標注了我的操作順序號。
鎖如果沒有過期或刪除,其他客戶端創建鎖會失敗;但是其他客戶端也可以刪除鎖,所以具有一定風險。建議可以對鎖設置不同客戶端所需要的不同的值用來區分。然后把需要操作的地方,放到鎖里面操作,來避免產生的同時操作產生的問題。
例如偽代碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | If(exists(lock)) { ??return?false;?// 存在鎖,修改失敗 } Else<br>{ ??Set?lock?true?ex 5 nx; ??Set key1 100; ??del?lock; ??Return?true;?// 修改成功 } |
Redis位圖
????位圖的最小單位是bit,每個bit的值只能是0和1,位圖的應用場景一般用于一些簽到記錄,例如打卡等。
場景舉例:?例如某APP要存儲用戶的打卡記錄,如果按照正常的思路來做,可能是用戶每天是否打卡的記錄都單獨設置一個key-value鍵值對來存儲,這樣的話,每個用戶每天都需要耗費一個鍵值對空間。而如果是位圖,就可以很方便地通過位圖來進行記錄,例如如下圖:
?
位圖不算基礎數據結構或者特殊數據結構,其本質上還是字符串。由于每個bit代表一個數據,所以還可以當作是bit數組來看待。
可以通過命令:
setbit?key?偏移量(索引位)??value(0/1,默認是0)
進行設置對應位置的位圖數據。
通過命令:
?getbit?key?偏移量
可以獲取到對應的位圖索引數據。
也可以通過:?
get?key?
來獲取位圖對應的字符串信息。
?
例如hello字符串的ascii碼對應的二進制,分別是:
h:?01101000
e:?01100101
l:?01101100
l:?01101100
o:?01101111
以下設置字符串hello的位圖操作,如圖所示,字符串對應二進制數拼接起來的二進制,值為1所在的bit索引位(offset),使用:
setbit?key?offset?1?
進行設置1即可。
?
setbit/gitbit 和 set/get 實際上是可以互相轉換的,只是一種是操作bit位,一種是操作直接的值。同時可以互相交叉操作使用,例如setbit存儲,get讀取;set 存儲,getbit讀取等等。
可以通過命令:?bitcount?key?起始字符索引?結束字符索引
對指定key里面的數據,指定的字符索引區間內,獲取到對應的位圖數據是1的個數。如果不指定,則會獲取到全部字符串對應位圖的1的個數。如下圖所示,結合以上二進制數據可知,h字符有3個1,o字符有6個1。
?
以上指令操作可以適用于在類似打卡天數統計上使用,可以快速統計出區間內為1的數據個數。
通過命令:bitops ?key ?bit值(0/1)??起始字符索引?結束字符索引
可以獲取到指定的區間內,第一次出現指定的bit值(0或1)所在的位圖索引。如果不指定區間,默認代表字符串全部區間。如下圖所示,hello里面,第一次出現1是在位圖的第一個索引位置;第一次出現0是在第0個位圖索引位;字符索引位為1代表第二個字符,第一次出現的值為1的位圖索引位置為9。
注意:?字符串的索引,0到N,0代表第一個字符,例如’h’。位圖的索引,也是0到N,0代表位圖上面第一個bit位,值為0或者1,例如h的位圖索引位置是0的值是0??(01101000)
?
可以通過命令:
bitfield??key?get?類型?位圖索引
來獲取指定類型數據的ascii碼。
例如,以下截圖中,命令:
bitfield?hello?get?u8?0?
其中,u8代表類型,u開頭代表無符號數據,8代表獲取8個bit位。如果是有符號的數據,是以i開頭的。最后面的0,代表要獲取的起始位圖下標索引,此處是第0個索引。
hello五個字符,對應的ascii碼分別為:104,101,108,108,111
如果以上命令的類型 u8 換成 u4 ,則獲取到的值是0110,對應的值是6;以此類推。
也可以并列get獲取,例如:
bitfield??key??get??type1?offset1??type2?offset2?……
其他玩法,大佬們可以自己嘗試。我這邊有關操作可以參考如下截圖所示內容。
?
通過命令:
bitfield?key?set?type?位圖索引?ascii碼
可以把對應的ascii碼根據類型寫入到指定的索引中,并且會返回原來索引被替換的ascii碼值。
例如下圖所示操作,位圖索引從0開始,代表第一個字符h所在位置。97代表a的ascii碼,執行以后,返回104(h的ascii碼),并且通過get命令可以查看到字符串已經被替換了。
?
可以使用命令:
bitfield??key??incrby??type??索引??自增值
對指定類型和索引區間的值進行累加?,如下圖所示。h通過 u8 類型自增1,即h+1=i
注意:對于累加的數據不能超出指定類型的最大值,例如 u4 最大值是15,累加到15以后會自動折返為0。
?
?針對以上會出現折返的情況,可以使用溢出報錯或者保持最大或最小值的方式來避免折返的情況。
使用命令:
Bitfield??key??overflow??fail??incrby??type??offset??value
可以實現溢出的時候,會返回nil;
使用命令:
Bitfield??key??overflow??sat??incrby??type??offset??value
可以實現當要溢出的時候,還是會返回當前的最大值或最小值。如下圖所示。
?
HyperLogLog
HyperLogLog是一種可以快速去重的數據結構。但是有一定的誤差率,大概在0.81%左右。應用場景一般是在需要針對一些大數據量的情況下進行去重計算大概的統計值使用,例如網站的PV量等等。
使用命令:
pfadd???key??value1??value2?……
可以添加對應的多個數據集到指定的key里面去。
如果添加已經存在的數據,會被自動去重。
使用命令:pfcount key
可以統計數據集的個數。
使用命令:pfmerge?目標key??源key1???源key2??……
可以對多個不同的key進行數據合并,并且數據集重復的會自動排重。
使用HyperLogLog的用途,是在針對大數據量的情況下,在允許一定的容錯率的情況下,用它可以節約資源并且快速地進行排重。例如使用set來設置數據,資源損耗肯定是巨大的;但是使用hyperloglog來處理,資源損耗是固定的12kb,可以處理的數據量大約是2^64個數據。
?
冷門科普:命令是pf開頭,是為了紀念HyperLogLog的作者——Philippe Flajolet?
布隆過濾器
布隆過濾器,最常見的場景是商品推薦業務。例如購物時候瀏覽的信息被記錄以后,可以進行推薦其他同類型的其他商品。推薦的其他商品不會和瀏覽過的商品重復(去重),但是也存在一定的誤差。
布隆過濾器源碼地址鏈接:
https://github.com/RedisBloom/RedisBloom
先進行下載,下載方式可以按照自己喜歡的方式下載。例如此處我下載到d目錄下的wesky/bloom文件夾下。
?
然后進入到文件夾內,使用make命令進行編譯。編譯成功的話,會產生一個 redisbloom.so的文件。如下,我也很尷尬,沒成功,就暫且到這里吧。
?
假如上面配置成功的話,啟動redis服務的時候,可以把.so文件配置到redis.conf配置文件下,例如我上面所在的位置,新增的樣式如下:
loadmodule?D:/Wesky/Bloom/RedisBloom/redisbloom.so
或者使用命令啟動的時候,使用命令進行指定:
redis-server?--loadmodule?D:/Wesky/Bloom/RedisBloom/redisbloom.so
由于當前我本機無法編譯布隆過濾器源碼,所以就暫且到這吧,請見諒。
布隆過濾器下,會有一些命令,供參考,大家可以根據自己情況,進行自己嘗試,當作是留個懸念了。
命令:
bf.add??key??xxx
bf.madd??key??數據1???數據2?……
bf.exists?key?數據
bf.mexists?key?數據1?數據2?……
……