Redis學習筆記(2):進階功能

3 進階功能

3.1 慢查詢

image-20200212121241917

說明

  • 慢查詢發生在第3階段(執行命令階段)
  • 客戶端超時不一定慢查詢,但慢查詢是客戶端超時的一個可能

配置

  1. slowlog-man-len

    1. 先進先出隊列
    2. 固定長度
    3. 保存在內存內,即,隨重啓而重置
  2. slowlog-log-slower-than

    1. 慢查詢閾值(微秒)
    2. slowlog-log-slower-than = 0 , 記錄所有命令
    3. slowlog-log-slower-than < 0, 不記錄任何命令

配置方法

  1. 默認值
    1. config get slowlog-man-len = 128
    2. config slowlog-log-slower-than = 10000
  2. 修改配置文件重啓
    • 一旦Redis運行之後,不建議進行重啓操作
  3. 動態配置
    1. config get slowlog-man-len value
    2. config slowlog-log-slower-than value

命令

  • slowlog get [n] 獲取慢查詢隊列
  • slowlog len 獲取慢查詢隊列長度
  • slowlog reset 清空慢查詢隊列

tips

  1. slowlog-man-len 不要設置過大。默認10ms,通常設置1ms
  2. slowlog-log-slower-than 不要設置過小,通常設置1000
  3. 理解生命週期
  4. 定期持久化查詢

3.2 pipeline

通常情況下,執行一條命令就需要一次客戶端和服務端的交互。而redis的命令時間是微秒級別的,那麼提高redis的執行效率的一個主要方向就是減少服務器與客戶端的交互頻率。

pipeline的功能就是將一組命令打包併發送到服務器,在服務器依次執行之後,再將結果打包返回給客戶端,這樣一來客戶端與服務端就只需要交互一次,在涉及大量交互的情境下無疑十分地便利。

tips

  1. 注意每次使用pipeline的數據攜帶量
  2. 一個redis服務器一次只能運行一條pipeline

對比

這裏我使用python對redis做了小實驗。寫入100000條數據的情況下,使用pipeline和不適用pipeline的耗時對比。

補充說明,這裏使用了遠程的redis服務器,更好地體現出交互過程在整個redis數據庫操作中所佔的時間比重。

def try_pipeline():
    start = time.time()
    with client.pipeline(transaction=False) as p:
        for foo in range(100000):
            key = 'uuid_{}'.format(foo)
            p.pfadd(key,foo)
        p.execute()
    print(time.time() - start)

def without_pipeline():
    start = time.time()
    for foo in range(100000):
        key = 'uuid_{}'.format(foo)
        client.pfadd(key,foo)
    print(time.time() - start)

輸出結果如下

try_pipeline : 2.6968681812286377
without_pipeline : 3320.136715888977

3.3 發佈訂閱

Redis 發佈訂閱(pub/sub)是一種消息通信模式:發送者(pub)發送消息,訂閱者(sub)接收消息。

Redis 客戶端可以訂閱任意數量的頻道。

當有新消息通過 PUBLISH 命令發送給頻道 channel1 時, 這個消息就會被髮送給訂閱它的三個客戶端:

p21

類比生產者-消費者模型進行理解。發送者對應生產者,訂閱者對應消費者。

常用命令

  • subscribe channel 進行訂閱監聽
  • unsubscribe channel 解除訂閱
  • publish channel message 進行發佈消息廣播

應用

顧名思義,發佈訂閱的一個典型的應用場景就是實現自動更新的訂閱功能(類比於門戶網站的__關注__功能)。

還有一個應用場景就是實時聊天系統。

個人(redis初學者)感覺redis的訂閱功能很粗糙,如果追求更加細緻的發佈訂閱動能可以考慮諸如__ActiveMQ__等。

通過一個bit位來表示某個元素對應的值或者狀態,其中的key就是對應元素本身。Bitmaps 本身不是一種數據結構,實際上它就是字符串(key 對應的 value 就是上圖中最後的一串二進制),但是它可以對字符串的位進行操作。 Bitmaps 單獨提供了一套命令,所以在 Redis 中使用 Bitmaps 和使用字符串的方法不太相同。可以把 Bitmaps 想象成一個以 位 爲單位的數組,數組的每個單元只能存儲 0 和 1,數組的下標在Bitmaps中叫做偏移量。

如,zxj這個字符串

z 對應的二進制值爲 01111010

x 對應的二進制值爲 01111000

j 對應的二進制值爲 01101010

常用命令

  • GETBIT key offset 獲取字符串值指定偏移量上的位(bit)

  • SETBIT key offset value 對 key 所儲存的字符串值,設置或清除指定偏移量上的位(bit)。

  • BITCOUNT key [start end] 計算給定字符串中,被設置爲 1 的比特位的數量

  • bitop op dtstkey key [key…] 做多個bitmap的and(交集),or(並集),not(非),xor(異或)操作並將結果保存在destkey中

    • bitpos key targetBit [start] [end]  計算位圖指定範圍(start到end,單位爲字節,如果不指定就是獲取全部)第一個偏移量對應的值等於targetBit的位置 
      
127.0.0.1:6379[1]> set zxj zxj2333
OK
127.0.0.1:6379[1]> GETBIT zxj 1
(integer) 1
127.0.0.1:6379[1]> SETBIT zxj 1 0
(integer) 1
127.0.0.1:6379[1]> get zxj
":xj2333"
127.0.0.1:6379[1]> BITCOUNT zxj
(integer) 27

127.0.0.1:6379[1]> set tt tt
OK
127.0.0.1:6379[1]> BITOP and zxj tt
(integer) 2
127.0.0.1:6379[1]>

3.4 bitmap

應用:

參考自redis 用setbit(bitmap)統計活躍用戶

如果一個網站有1億用戶,假如user_id用的是整型,長度爲32位,每天有5千萬獨立用戶訪問,如何判斷是哪5千萬用戶訪問了網站

方式一:用set來保存

使用set來保存數據運行一天需要佔用的內存爲

32bit * 50000000 = (4 * 50000000) / 1024 /1024 MB,約爲200MB

運行一個月需要佔用的內存爲6G,運行一年佔用的內存爲72G

30 * 200 = 6G

方式二:使用bitmap的方式

如果user_id訪問網站,則在user_id的索引上設置爲1,沒有訪問網站的user_id,其索引設置爲0,此種方式運行一天佔用的內存爲

1 * 100000000 = 100000000 / 1024 /1024/ 8MB,約爲12.5MB

運行一個月佔用的內存爲375MB,一年佔用的內存容量爲4.5G

由此可見,使用bitmap可以節省大量的內存資源

補充

  • bitmap是string類型,單個值最大可以使用的內存容量爲512MB
  • setbit時是設置每個value的偏移量,可以有較大耗時
  • bitmap不是絕對好,用在合適的場景最好

有關redis bitmap的更詳細知識可以參考掘金的dzzgml寫的Redis-BitMap

3.5 HyperLogLog

Redis 在 2.8.9 版本添加了 HyperLogLog 結構。

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

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

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

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

命令

  • PFADD key element [element …] 新增元素
  • PFCOUNT key [key…] 獲取基數的估計值
  • PFMERGE destkey sourcekey [sourcekey] 將多個 HyperLogLog 合併爲一個 HyperLogLog

命令演示

127.0.0.1:6379[1]> PFADD 2020_02_09:unique:ids 'uuid-1' 'uuid-2' 'uuid-3' 'uuid-4'
(integer) 1
127.0.0.1:6379[1]> PFCOUNT 2020_02_09:unique:ids
(integer) 4
127.0.0.1:6379[1]> PFADD 2020_02_09:unique:ids 'uuid-1' 'uuid-90'
(integer) 1
127.0.0.1:6379[1]> PFCOUNT 2020_02_09:unique:ids
(integer) 5

向其中注入100000條數據,看看數據庫的大小變化如何

# 注入數據之前
# Memory
used_memory:830624
used_memory_human:811.16K
used_memory_rss:7327744
used_memory_peak:908432
used_memory_peak_human:887.14K
used_memory_lua:33792
mem_fragmentation_ratio:8.82
mem_allocator:jemalloc-3.6.0

# 注入數據之後(with HyperLogLog)
# Memory
used_memory:890456
used_memory_human:869.59K
used_memory_rss:10792960
used_memory_peak:18084664
used_memory_peak_human:17.25M
used_memory_lua:33792
mem_fragmentation_ratio:12.12
mem_allocator:jemalloc-3.6.0


# 注入數據之後(without HyperLogLog)
# Memory
used_memory:9760408
used_memory_human:9.31M
used_memory_rss:18481152
used_memory_peak:18084664
used_memory_peak_human:17.25M
used_memory_lua:33792
mem_fragmentation_ratio:1.89
mem_allocator:jemalloc-3.6.0

很明顯,使用HyperLogLog注入10萬條數據佔用的內存爲 869.59K -811.16K = 58.43k , 而直接使用set鍵值對的方法,佔用的內存接近__9M__ 。

這個差距是非常巨大的,但是天下沒有免費的午餐,那麼HyperLogLog低內存的代價是什麼呢?

127.0.0.1:6379> PFCOUNT loglog
(integer) 99556

查詢一下基數估計值,發現並不是我們所插入的10萬條那麼多。

這就引出了HyperLogLog的一個最大的缺點,有一定的錯誤率 ,根據官方的數據來看,這個錯誤率大約是0.81%.

同時,HyperLogLog還有一個很顯著的缺點,在於 沒法取出單條數據

綜上,在使用HyperLogLog之前,一定要衡量好是否可以接受它的缺點所帶來的損失

補充

更多關於HyperLogLog的知識可以看rainybowe的blog

3.6 GEO(geospatial)

GEO 特性是 Redis 3.2 版本的特性

官網的介紹如下,總的來說,就是用來進行地理位置的相關操作的(如:存儲經緯度,計算兩地距離,範圍計算等)

Adds the specified geospatial items (latitude, longitude, name) to the specified key. Data is stored into the key as a sorted set, in a way that makes it possible to later retrieve items using a query by radius with theGEORADIUS or GEORADIUSBYMEMBER commands.

The command takes arguments in the standard format x,y so the longitude must be specified before the latitude. There are limits to the coordinates that can be indexed: areas very near to the poles are not indexable. The exact limits, as specified by EPSG:900913 / EPSG:3785 / OSGEO:41001 are the following:

    Valid longitudes are from -180 to 180 degrees.
    Valid latitudes are from -85.05112878 to 85.05112878 degrees.

The command will report an error when the user attempts to index coordinates outside the specified ranges.

Note: there is no GEODEL command because you can use ZREM in order to remove elements. The Geo index structure is just a sorted set.

常用命令

  • geoadd key longitude latitude member [longitude latitude member …] 增加地理位置信息 預處理

  • geopos key member [member …] 獲取地理位置信息

  • geodist key member1 member2 [unit] 獲取兩個地理位置之間的距離

  • GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [ASC|DESC] [COUNT count] 獲取指定位置範圍的地理信息位置集合

    • WITHDIST : 在返回位置元素的同時, 將位置元素與中心之間的距離也一併返回。 距離的單位和用戶給定的範圍單位保持一致
    • WITHCOORD : 將位置元素的經度和維度也一併返回
    • WITHHASH : 以 52 位有符號整數的形式, 返回位置元素經過原始 geohash 編碼的有序集合分值。 這個選項主要用於底層應用或者調試, 實際中的作用並不大。 命令默認返回未排序的位置元素。 通過以下兩個參數, 用戶可以指定被返回位置元素的排序方式
    • COUNT : 指定返回結果的數量
    • ASC : 根據中心的位置, 按照從近到遠的方式返回位置元素。DESC : 根據中心的位置, 按照從遠到近的方式返回位置元素
    • store key : 將返回結果的地理位置信息保存到指定鍵
    • storedist key :將返回結果距離中心節點的距離保存到指定鍵
  • GEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [ASC|DESC] [COUNT count] 獲取指定元素範圍的地理信息位置集合

命令演示

127.0.0.1:6379[1]> GEOADD cities:locations 116.28 39.55 bejing
(integer) 1
127.0.0.1:6379[1]> GEOADD cities:locations 117.12 39.08 tianjing
(integer) 1
127.0.0.1:6379[1]> GEOADD cities:locations 114.29 38.02 shijiazhuang 118.01 39.38 tangshan 115.29 38.51 baoding (integer) 3
127.0.0.1:6379[1]> GEOPOS cities:locations tianjing
1) 1) "117.12000042200088501"
   2) "39.0800000535766543"
127.0.0.1:6379[1]> GEODIST cities:locations bejing tianjing
"89206.0576"
127.0.0.1:6379[1]> GEORADIUSBYMEMBER cities:locations bejing 150 km
1) "bejing"
2) "tianjing"
3) "tangshan"
4) "baoding"

應用

例如

  • 微信__搖一搖__功能(即:檢索特定地理範圍內的使用者)
  • 美團__附近美食__

補充

更多的GEO知識可以參看Redis GEO 特性簡介Redis GEO & 實現原理深度分析

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