Redis(七)新數據類型、新功能

第一章 Redis新數據類型

1.1 Bitmaps

簡介

現代計算機用二進制(位) 作爲信息的基礎單位, 1個字節等於8位, 例如“abc”字符串是由3個字節組成, 但實際在計算機存儲時將其用二進制表示, “abc”分別對應的ASCII碼分別是97、 98、 99, 對應的二進制分別是01100001、 01100010和01100011,如下圖

img

合理地使用操作位能夠有效地提高內存使用率和開發效率。

​ Redis提供了Bitmaps這個“數據類型”可以實現對位的操作:

(1) Bitmaps本身不是一種數據類型, 實際上它就是字符串(key-value) , 但是它可以對字符串的位進行操作。

(2) Bitmaps單獨提供了一套命令, 所以在Redis中使用Bitmaps和使用字符串的方法不太相同。 可以把Bitmaps想象成一個以位爲單位的數組, 數組的每個單元只能存儲0和1, 數組的下標在Bitmaps中叫做偏移量。

img

命令

1、setbit

(1)格式

setbit<key><offset><value>

設置Bitmaps中某個偏移量的值(0或1)

img

*offset:偏移量從0開始

(2)實例

每個獨立用戶是否訪問過網站存放在Bitmaps中, 將訪問的用戶記做1, 沒有訪問的用戶記做0, 用偏移量作爲用戶的id。

設置鍵的第offset個位的值(從0算起) , 假設現在有20個用戶,userid=1, 6, 11, 15, 19的用戶對網站進行了訪問, 那麼當前Bitmaps初始化結果如圖

img

unique:users:20201106

代表2020-11-06這天的獨立訪問用戶的Bitmaps

img

注:

很多應用的用戶id以一個指定數字(例如10000) 開頭, 直接將用戶id和Bitmaps的偏移量對應勢必會造成一定的浪費, 通常的做法是每次做setbit操作時將用戶id減去這個指定數字。

在第一次初始化Bitmaps時, 假如偏移量非常大, 那麼整個初始化過程執行會比較慢, 可能會造成Redis的阻塞。

2、getbit

(1)格式

getbit<key><offset>

獲取Bitmaps中某個偏移量的值

img

獲取鍵的第offset位的值(從0開始算)

(2)實例

獲取id=8的用戶是否在2020-11-06這天訪問過, 返回0說明沒有訪問過:

img

注:因爲100根本不存在,所以也是返回0

3、bitcount

統計字符串被設置爲1的bit數。一般情況下,給定的整個字符串都會被進行計數,通過指定額外的 start 或 end 參數,可以讓計數只在特定的位上進行。start 和 end 參數的設置,都可以使用負數值:比如 -1 表示最後一個位,而 -2 表示倒數第二個位,start、end 是指bit組的字節的下標數,二者皆包含。

(1)格式

bitcount<key>[start end] 

統計字符串從start字節到end字節比特值爲1的數量

img

(2)實例

計算2022-11-06這天的獨立訪問用戶數量

img

start和end代表起始和結束字節數, 下面操作計算用戶id在第1個字節到第3個字節之間的獨立訪問用戶數, 對應的用戶id是11, 15, 19。

img

舉例: K1 【01000001 01000000 00000000 00100001】,對應【0,1,2,3】

bitcount K1 1 2 : 統計下標1、2字節組中bit=1的個數,即01000000 00000000

--》bitcount K1 1 2   --》1

bitcount K1 1 3 : 統計下標1、2字節組中bit=1的個數,即01000000 00000000 00100001

--》bitcount K1 1 3  --》3

bitcount K1 0 -2 : 統計下標0到下標倒數第2,字節組中bit=1的個數,即01000001 01000000 00000000

--》bitcount K1 0 -2  --》3

注意:redis的setbit設置或清除的是bit位置,而bitcount計算的是byte位置。

4、bitop

(1)格式

bitop and(or/not/xor) <destkey> [key…]

img

bitop是一個複合操作, 它可以做多個Bitmaps的and(交集) 、 or(並集) 、 not(非) 、 xor(異或) 操作並將結果保存在destkey中。

(2)實例

2020-11-04 日訪問網站的userid=1,2,5,9。

setbit unique:users:20201104 1 1
setbit unique:users:20201104 2 1
setbit unique:users:20201104 5 1
setbit unique:users:20201104 9 1

2020-11-03 日訪問網站的userid=0,1,4,9。

setbit unique:users:20201103 0 1
setbit unique:users:20201103 1 1
setbit unique:users:20201103 4 1
setbit unique:users:20201103 9 1

計算出兩天都訪問過網站的用戶數量

bitop and unique:users:and:20201104_03 unique:users:20201103unique:users:20201104

img

img

計算出任意一天都訪問過網站的用戶數量(例如月活躍就是類似這種) , 可以使用or求並集

img

Bitmaps與set對比

假設網站有1億用戶, 每天獨立訪問的用戶有5千萬, 如果每天用集合類型和Bitmaps分別存儲活躍用戶可以得到表

set和Bitmaps存儲一天活躍用戶對比
數據類型 每個用戶id佔用空間 需要存儲的用戶量 全部內存量
集合類型 64位 50000000 64位*50000000 = 400MB
Bitmaps 1位 100000000 1位*100000000 = 12.5MB

很明顯, 這種情況下使用Bitmaps能節省很多的內存空間, 尤其是隨着時間推移節省的內存還是非常可觀的

set和Bitmaps存儲獨立用戶空間對比
數據類型 一天 一個月 一年
集合類型 400MB 12GB 144GB
Bitmaps 12.5MB 375MB 4.5GB

但Bitmaps並不是萬金油, 假如該網站每天的獨立訪問用戶很少, 例如只有10萬(大量的殭屍用戶) , 那麼兩者的對比如下表所示, 很顯然, 這時候使用Bitmaps就不太合適了, 因爲基本上大部分位都是0。

set和Bitmaps存儲一天活躍用戶對比(獨立用戶比較少)
數據類型 每個userid佔用空間 需要存儲的用戶量 全部內存量
集合類型 64位 100000 64位*100000 = 800KB
Bitmaps 1位 100000000 1位*100000000 = 12.5MB

1.2 HyperLogLog

簡介

在工作當中,我們經常會遇到與統計相關的功能需求,比如統計網站PV(PageView頁面訪問量),可以使用Redis的incr、incrby輕鬆實現。

但像UV(Unique Visitor,獨立訪客)、獨立IP數、搜索記錄數等需要去重和計數的問題如何解決?這種求集合中不重複元素個數的問題稱爲基數問題

解決基數問題有很多種方案:

(1)數據存儲在MySQL表中,使用distinct count計算不重複個數

(2)使用Redis提供的hash、set、bitmaps等數據結構來處理

以上的方案結果精確,但隨着數據不斷增加,導致佔用空間越來越大,對於非常大的數據集是不切實際的。

能否能夠降低一定的精度來平衡存儲空間?Redis推出了HyperLogLog

Redis HyperLogLog 是用來做基數統計的算法,HyperLogLog 的優點是,在輸入元素的數量或者體積非常非常大時,計算基數所需的空間總是固定的、並且是很小的。

在 Redis 裏面,每個 HyperLogLog 鍵只需要花費 12 KB 內存,就可以計算接近 2^64 個不同元素的基數。這和計算基數時,元素越多耗費內存就越多的集合形成鮮明對比。

但是,因爲 HyperLogLog 只會根據輸入元素來計算基數,而不會儲存輸入元素本身,所以 HyperLogLog 不能像集合那樣,返回輸入的各個元素。

什麼是基數?

比如數據集 {1, 3, 5, 7, 5, 7, 8}, 那麼這個數據集的基數集爲 {1, 3, 5 ,7, 8}, 基數(不重複元素)爲5。 基數估計就是在誤差可接受的範圍內,快速計算基數。

命令

1、pfadd

(1)格式

pfadd <key>< element> [element ...]  

添加指定元素到 HyperLogLog 中

img

(2)實例

img

​ 將所有元素添加到指定HyperLogLog數據結構中。如果執行命令後HLL估計的近似基數發生變化,則返回1,否則返回0。

2、pfcount

(1)格式

pfcount<key> [key ...] 

計算HLL的近似基數,可以計算多個HLL,比如用HLL存儲每天的UV,計算一週的UV可以使用7天的UV合併計算即可

img

(2)實例

img

3、pfmerge

(1)格式

pfmerge<destkey><sourcekey> [sourcekey ...]  

將一個或多個HLL合併後的結果存儲在另一個HLL中,比如每月活躍用戶可以使用每天的活躍用戶來合併計算可得

img

(2)實例

img

1.3 Geospatial

簡介

Redis 3.2 中增加了對GEO類型的支持。GEO,Geographic,地理信息的縮寫。該類型,就是元素的2維座標,在地圖上就是經緯度。redis基於該類型,提供了經緯度設置,查詢,範圍查詢,距離查詢,經緯度Hash等常見操作。

命令

1、geoadd

(1)格式

geoadd<key>< longitude><latitude><member> [longitude latitude member...]  

添加地理位置(經度,緯度,名稱)

img

(2)實例

geoadd china:city 121.47 31.23 shanghai
geoadd china:city 106.50 29.53 chongqing 114.05 22.52 shenzhen 116.38 39.90 beijing

img

兩極無法直接添加,一般會下載城市數據,直接通過 Java 程序一次性導入。

有效的經度從 -180 度到 180 度。有效的緯度從 -85.05112878 度到 85.05112878 度。

當座標位置超出指定範圍時,該命令將會返回一個錯誤。

已經添加的數據,是無法再次往裏面添加的。

2、geopos

(1)格式

geopos  <key><member> [member...]  

獲得指定地區的座標值

img

(2)實例

img

3、geodist

(1)格式

geodist<key><member1><member2>  [m|km|ft|mi ]  

獲取兩個位置之間的直線距離

img

(2)實例

獲取兩個位置之間的直線距離

img

單位:

  • m 表示單位爲米[默認值]。
  • km 表示單位爲千米。
  • mi 表示單位爲英里。
  • ft 表示單位爲英尺。

如果用戶沒有顯式地指定單位參數, 那麼 GEODIST 默認使用米作爲單位

4、georadius

(1)格式

georadius<key>< longitude><latitude>radius m|km|ft|mi  

以給定的經緯度爲中心,找出某一半徑內的元素

img

經度 緯度 距離 單位

(2)實例

img

第二章 Redis6.0 新功能

2.1 ACL

簡介

Redis ACL是Access Control List(訪問控制列表)的縮寫,該功能允許根據可以執行的命令和可以訪問的鍵來限制某些連接。

在Redis 5版本之前,Redis 安全規則只有密碼控制 還有通過rename 來調整高危命令比如 flushdb , KEYS* , shutdown 等。Redis 6 則提供ACL的功能對用戶進行更細粒度的權限控制 :

(1)接入權限:用戶名和密碼

(2)可以執行的命令

(3)可以操作的 KEY

參考官網:https://redis.io/topics/acl

命令

1、使用acl list命令展現用戶權限列表

(1)數據說明

img

2、使用acl cat命令

(1)查看添加權限指令類別

img

(2)加參數類型名可以查看類型下具體命令

img

3、使用acl whoami命令查看當前用戶

img

4、使用aclsetuser命令創建和編輯用戶ACL

(1)ACL規則

下面是有效ACL規則的列表。某些規則只是用於激活或刪除標誌,或對用戶ACL執行給定更改的單個單詞。其他規則是字符前綴,它們與命令或類別名稱、鍵模式等連接在一起。

ACL規則
類型 參數 說明
啓動和禁用用戶 on 激活某用戶賬號
off 禁用某用戶賬號。注意,已驗證的連接仍然可以工作。如果默認用戶被標記爲off,則新連接將在未進行身份驗證的情況下啓動,並要求用戶使用AUTH選項發送AUTH或HELLO,以便以某種方式進行身份驗證。
權限的添加刪除 + 將指令添加到用戶可以調用的指令列表中
從用戶可執行指令列表移除指令
+@ 添加該類別中用戶要調用的所有指令,有效類別爲@admin、@set、@sortedset…等,通過調用ACL CAT命令查看完整列表。特殊類別@all表示所有命令,包括當前存在於服務器中的命令,以及將來將通過模塊加載的命令。
-@ 從用戶可調用指令中移除類別
allcommands +@all的別名
nocommand -@all的別名
可操作鍵的添加或刪除 ~ 添加可作爲用戶可操作的鍵的模式。例如~*允許所有的鍵

(2)通過命令創建新用戶默認權限

acl setuser user1

img

在上面的示例中,我根本沒有指定任何規則。如果用戶不存在,這將使用just created的默認屬性來創建用戶。如果用戶已經存在,則上面的命令將不執行任何操作。

(3)設置有用戶名、密碼、ACL權限、並啓用的用戶

acl setuser user2 on >password ~cached:* +get

img

(4)切換用戶,驗證權限

img

2.2 IO多線程

簡介

Redis6終於支撐多線程了,告別單線程了嗎?

IO多線程其實指客戶端交互部分網絡IO交互處理模塊多線程,而非執行命令多線程。Redis6執行命令依然是單線程。

原理架構

Redis 6 加入多線程,但跟 Memcached 這種從 IO處理到數據訪問多線程的實現模式有些差異。Redis 的多線程部分只是用來處理網絡數據的讀寫和協議解析,執行命令仍然是單線程。之所以這麼設計是不想因爲多線程而變得複雜,需要去控制 key、lua、事務,LPUSH/LPOP 等等的併發問題。整體的設計大體如下:

img

另外,多線程IO默認也是不開啓的,需要再配置文件中配置

io-threads-do-reads  yes
io-threads 4

2.3 工具支持 Cluster

之前老版Redis想要搭集羣需要單獨安裝ruby環境,Redis 5 將 redis-trib.rb 的功能集成到 redis-cli 。另外官方 redis-benchmark 工具開始支持 cluster 模式了,通過多線程的方式對多個分片進行壓測。

img

2.4 Redis新功能持續關注

Redis6新功能還有:

1、RESP3新的 Redis 通信協議:優化服務端與客戶端之間通信

2、Client side caching客戶端緩存:基於 RESP3 協議實現的客戶端緩存功能。爲了進一步提升緩存的性能,將客戶端經常訪問的數據cache到客戶端。減少TCP網絡交互。

3、Proxy集羣代理模式:Proxy 功能,讓 Cluster 擁有像單實例一樣的接入方式,降低大家使用cluster的門檻。不過需要注意的是代理不改變 Cluster 的功能限制,不支持的命令還是不會支持,比如跨 slot 的多Key操作。

4、Modules API

Redis 6中模塊API開發進展非常大,因爲Redis Labs爲了開發複雜的功能,從一開始就用上Redis模塊。Redis可以變成一個框架,利用Modules來構建不同系統,而不需要從頭開始寫然後還要BSD許可。Redis一開始就是一個向編寫各種系統開放的平臺。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章