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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

03:小功能大用处

發布時間:2023/12/18 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 03:小功能大用处 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

03:小功能大用處

文章目錄

    • 03:小功能大用處
  • 1、本章知識
    • 1.1 本章內容
    • 1.2 重點
  • 2、慢查詢分析
    • 2.1 慢查詢的兩個配置參數
    • 2.2 慢查詢最佳實踐
  • 3、Redis Shell
    • 3.1 redis-cli常用命令
    • 3.2 redis-cli命令總結
    • 3.2 redis-benchmark命令
    • 3.3 Pipeline
      • 3.3.1 執行過程
      • 3.3.2 Pipeline性能測試
      • 3.3.3 原生批量命令與Pipeline對比
      • 3.3.4 最佳實踐
    • 3.4 Redis與Lua
    • 3.5 Bitmaps
      • 3.5.1 數據結構模型
      • 3.5.2 命令
      • 3.5.3 Bitmaps分析
    • 3.6 HyperLogLog
      • 3.6.1 HyperLogLog命令
    • 3.7 發布訂閱
      • 3.7.1 命令
    • 3.8 GEO(地理信息定位)

1、本章知識

1.1 本章內容

  • 慢查詢分析:通過慢查詢分析,找到有問題的命令進行優化。
  • Redis Shell:功能強大的Redis Shell會有意想不到的實用功能。
  • Pipeline:通過Pipeline(管道或者流水線)機制有效提高客戶端性能。
  • 事務與Lua:制作自己的專屬原子命令。
  • Bitmaps:通過在字符串數據結構上使用位操作,有效節省內存,為開 發提供新的思路。
  • HyperLogLog:一種基于概率的新算法,難以想象地節省內存空間。
  • 發布訂閱:基于發布訂閱模式的消息通信機制。
  • GEO:Redis3.2提供了基于地理位置信息的功能。

1.2 重點

  • 1)慢查詢中的兩個重要參數slowlog-log-slower-than和slowlog-max-len。
  • 2)慢查詢不包含命令網絡傳輸和排隊時間。
  • 3)有必要將慢查詢定期存放。
  • 4)redis-cli一些重要的選項,例如–latency、–-bigkeys、-i和-r組合。
  • 5)redis-benchmark的使用方法和重要參數。
  • 6)Pipeline可以有效減少RTT次數,但每次Pipeline的命令數量不能無節制。
  • 7)Redis可以使用Lua腳本創造出原子、高效、自定義命令組合。
  • 8)Redis執行Lua腳本有兩種方法:eval和evalsha。
  • 9)Bitmaps可以用來做獨立用戶統計,有效節省內存。
  • 10)Bitmaps中setbit一個大的偏移量,由于申請大量內存會導致阻塞。
  • 11)HyperLogLog雖然在統計獨立總量時存在一定的誤差,但是節省的內存量十分驚人。

2、慢查詢分析

所謂慢查詢日志就是系統在命令執行前后計算每條命令的執行時間,當超過預設閥值,就將這條命令的相關信息(例如:發生時 間,耗時,命令的詳細信息)記錄下來,Redis也提供了類似的功能。

Redis客戶端執行一條命令分為如下4個部分:

  • 一條客戶端命令的生命周期:
    • 發送命令
    • 命令排隊
    • 命令執行
    • 返回結果

需要注意,慢查詢只統計(命令執行)的時間,所以沒有慢查詢并不代表客戶端沒有超時問題。

2.1 慢查詢的兩個配置參數

  • 對于慢查詢功能,需要明確兩件事:
    • 預設閥值怎么設置?
    • 慢查詢記錄存放在哪?

Redis提供了slowlog-log-slower-than和slowlog-max-len配置來解決這兩個問題。

  • slowlog-log-slower-than

從字面意思就可以看出,slowlog-log-slower-than就是那個預設閥值, 它的單位是微秒(1秒=1000毫秒=1000000微秒),默認值是10000即10毫秒,假如執 行了一條很慢的命令(例如keys*),如果它的執行時間超過了10000微秒,那么它將被記錄在慢查詢日志中。

注意:如slowlog-log-slower-than = 0會記錄所有的命令,slowlog-log-slower-than < 0對于任何命令都不會進行記錄。

  • slowlog-max-len

從字面意思看,只是說明了慢查詢日志最多存儲多少條,并沒有說明存放在哪里?
實際上Redis使用了一個列表來存儲慢查詢日志,slowlog-max-len就是列表的最大長度。
一個新的命令滿足慢查詢條件時 被插入到這個列表中,當慢查詢日志列表已處于其最大長度時,最早插入的 一個命令將從列表中移出,例如slowlog-max-len設置為5,當有第6條慢查詢插入的話,那么隊頭的第一條數據就出列,第6條慢查詢就會入列。

  • 在Redis中有兩種修改配置的方法:
    • 一種是修改配置文件
    • 另一種是使用config set命令動態修改

下面使用config set命令將slowlog-log-slower- than設置為20000微秒,slowlog-max-len設置為256

命令行查看修改配置文件項config get | config set | config rewrite

192.168.49.171:6392> config get slow* 1) "slowlog-log-slower-than" 2) "10000" 3) "slowlog-max-len" 4) "128" 192.168.49.171:6392> config set slowlog-log-slower-than 20000 OK 192.168.49.171:6392> config set slowlog-max-len 256 OK 192.168.49.171:6392> config rewrite OK 192.168.49.171:6392> config get slow* 1) "slowlog-log-slower-than" 2) "20000" 3) "slowlog-max-len" 4) "256" 192.168.49.171:6392>

要Redis將配置持久化到本地配置文件,需要執行config rewrite命令,config rewrite命令重寫配置文件

192.168.49.171:6392> slowlog get 1) 1) (integer) 02) (integer) 15740618273) (integer) 148324) 1) "DEL"2) "baobao" 192.168.49.171:6392> slowlog len (integer) 1 192.168.49.171:6392>
  • 慢查詢日志數據結構

  • 那么記錄的中的1)2)3)4)分別表示什么呢?
    • 1)表示日志唯一標識符uid
    • 2)命令執行時系統的時間戳
    • 3)命令執行的時長,以微妙來計算
    • 4)命令和命令的參數
192.168.49.171:6392> slowlog len --當前Redis中有1條慢查詢 (integer) 1 192.168.49.171:6392> slowlog reset --慢查詢日志重置 OK 192.168.49.171:6392> slowlog len (integer) 0 192.168.49.171:6392>

2.2 慢查詢最佳實踐

  • 慢查詢功能可以有效地幫助我們找到Redis可能存在的瓶頸,但在實際 使用過程中要注意以下幾點:
    • slowlog-max-len配置建議:線上建議調大慢查詢列表,記錄慢查詢時 Redis會對長命令做截斷操作,并不會占用大量內存。增大慢查詢列表可以減緩慢查詢被剔除的可能,例如線上可設置為1000以上。
    • slowlog-log-slower-than配置建議:默認值超過10毫秒判定為慢查詢,需要根據Redis并發量調整該值。由于Redis采用單線程響應命令,對于高流量的場景,如果命令執行時間在1毫秒以上,那么Redis最多可支撐OPS不到 1000。因此對于高OPS場景的Redis建議設置為1毫秒。
    • 慢查詢只記錄命令執行時間,并不包括命令排隊和網絡傳輸時間。因此客戶端執行命令的時間會大于命令實際執行時間。因為命令執行排隊機制,慢查詢會導致其他命令級聯阻塞,因此當客戶端出現請求超時,需要檢 查該時間點是否有對應的慢查詢,從而分析出是否為慢查詢導致的命令級聯阻塞。
    • 由于慢查詢日志是一個先進先出的隊列,也就是說如果慢查詢比較多 的情況下,可能會丟失部分慢查詢命令,為了防止這種情況發生,可以定期執行slow get命令將慢查詢日志持久化到其他存儲中(例如MySQL),然后 可以制作可視化界面進行查詢。

3、Redis Shell

Redis提供了redis-cli、redis-server、redis-benchmark等Shell工具。

可執行文件作用
redis-server啟動redis
redis-cliredis命令行工具
redis-benchmark基準測試工具
redis-check-aofAOF持久化文件檢測工具和修復工具
redis-check-dumpRDB持久化文件檢測工具和修復工具
redis-sentinel啟動redis-sentinel

3.1 redis-cli常用命令

1. -r(repeat)選項代表將命令執行多次,例如下面操作將會執行三次ping命令:[root@manager01 ~]# redis-cli -r 3 -h 192.168.49.171 -p 6393 ping PONG PONG PONG2.-i(interval)選項代表每隔幾秒執行一次命令,但是-i選項必須和-r選項一起使用,下面的操作會每隔1秒執行一次ping命令,一共執行5次:[root@manager01 ~]# redis-cli -h 192.168.49.171 -p 6393 -r 5 -i 1 ping PONG PONG PONG PONG PONG注意-i的單位是秒,不支持毫秒為單位,但是如果想以每隔10毫秒執行一次,可以用-i 0.01,例如:[root@manager01 ~]# redis-cli -h 192.168.49.171 -p 6393 -r 5 -i 0.01 ping PONG PONG PONG PONG PONG例如下面的操作利用-r和-i選項,每隔1秒輸出內存的使用量,一共輸出5次:[root@manager01 ~]# redis-cli -h 192.168.49.171 -p 6393 -r 5 -i 1 info |grep used_memory_human used_memory_human:40.34M used_memory_human:40.34M used_memory_human:40.34M used_memory_human:40.31M used_memory_human:40.34M3.-x選項代表從標準輸入(stdin)讀取數據作為redis-cli的***一個參數,例如下面的操作會將字符串world作為set hello的值:[root@manager01 ~]# echo "world" | redis-cli -h 192.168.49.171 -p 6393 -x set hello OK[root@manager01 ~]# redis-cli -h 192.168.49.171 -p 6393 get hello "world\n"[root@manager01 ~]# echo -n "world_1" | redis-cli -h 192.168.49.171 -p 6393 -x set hello_1 --因為echo命令是默認帶有回車\n的,不帶回車需要echo –n命令:從標準輸入讀入一個參數到redis,就不會有回車符. OK [root@manager01 ~]# redis-cli -h 192.168.49.171 -p 6393 get hello_1 "world_1" [root@manager01 ~]# 4.-c(cluster)選項是連接Redis Cluster節點時需要使用的,-c選項可以防止moved和ask異常。[root@manager01 ~]# redis-cli -h 192.168.49.173 -p 6379 -c 192.168.49.173:6379> info cluster # Cluster cluster_enabled:1 192.168.49.173:6379> 5.-a 如果Redis配置了密碼,可以用-a(auth)選項,有了這個選項就不需要手動輸入auth命令。6.--scan選項和--pattern選項用于掃描指定模式的鍵,相當于使用scan命令。7.--slave選項是把當前客戶端模擬成當前Redis節點的從節點,可以用來獲取當前Redis節點的更新操作,有關于Redis復制將在第6章進行詳細介紹。合理的利用這個選項可以記錄當前連接Redis節點的一些更新操作,這些更新操作很可能是實際開發業務時需要的數據。下面開啟***個客戶端,使用--slave選項,看到同步已完成: $ redis-cli --slave SYNC with master, discarding 72 bytes of bulk transfer... SYNC done. Logging commands from master. 再開啟另一個客戶端做一些更新操作: redis-cli 127.0.0.1:6379> set hello world OK 127.0.0.1:6379> set a b OK 127.0.0.1:6379> incr count 1 127.0.0.1:6379> get hello "world" ***個客戶端會收到Redis節點的更新操作: redis-cli --slave SYNC with master, discarding 72 bytes of bulk transfer... SYNC done. Logging commands from master. "PING" "PING" "PING" "PING" "PING" "SELECT","0" "set","hello","world" "set","a","b" "PING" "incr","count" PING命令是由于主從復制產生的,第6章會對主從復制進行介紹。8.--rdb選項會請求Redis實例生成并發送RDB持久化文件,保存在本地。可使用它做持久化文件的定期備份。9.--pipe選項用于將命令封裝成Redis通信協議定義的數據格式,批量發送給Redis執行: [root@manager01 ~]# echo -en "PING\r\n SET w3ckey redis\r\nGET w3ckey\r\nINCR visitor\r\nINCR visitor\r\nINCR visitor\r\n" | redis-cli -h 192.168.49.171 -p 6392 PONG OK "redis" (integer) 1 (integer) 2 (integer) 310、--bigkeys統計bigkey的分布,使用scan命令對redis的鍵進行采樣,從中找到內存占用比較大的鍵,這些鍵可能是系統的瓶頸。11、--eval用于執行lua腳本12、--latency [root@manager01 ~]# redis-cli -h 192.168.49.171 -p 6393 --latency min: 0, max: 4, avg: 0.30 (3757 samples)有三個選項,--latency、--latency-history、--latency-dist。它們可檢測網絡延遲,展現的形式不同。13、--stat 可實時獲取redis的重要統計信息。info命令雖然比較全,但這里可看到一些增加的數據,如requests(每秒請求數)14、--raw 和 --no-raw --no-raw 要求返回原始格式。--raw 顯示格式化的效果。 [root@manager01 ~]# redis-cli -h 192.168.49.171 -p 6393 --stat ------- data ------ --------------------- load -------------------- - child - keys mem clients blocked requests connections 8 40.31M 8 0 2798512 ( 0) 19198 8 40.35M 8 0 2798517 ( 5) 19198 8 40.35M 8 0 2798525 ( 8) 19198

3.2 redis-cli命令總結

  • 字符串命令

  • 修改字符串操作命令

  • 修改數字值操作命令

  • 位圖命令

  • 列表命令

  • 其他列表命令

  • 哈希命令


*其他哈希命令

  • 集合命令

集合并交差運算操作命令

*有序集合命令

  • 其他有序集合命令

  • 發布訂閱命令

  • 連接操作相關的命令

  • 服務端相關命令

與客戶端連接、獲取命令信息相關的命令

與配置文件、磁盤操作相關的命令

其他命令

  • 腳本命令

  • 對KEY操作的命令

  • Hyperloglog命令

  • 地理空間命令

  • 事務命令

  • 集群命令


連接操作相關的命令默認直接連接 遠程連接-h 192.168.1.20 -p 6379 ping:測試連接是否存活如果正常會返回pong echo:打印 select:切換到指定的數據庫,數據庫索引號 index 用數字值指定,以 0 作為起始索引值 quit:關閉連接(connection) auth:簡單密碼認證服務端相關命令time:返回當前服務器時間 client list: 返回所有連接到服務器的客戶端信息和統計數據 參見http://redisdoc.com/server/client_list.html client kill ip:port:關閉地址為 ip:port 的客戶端 save:將數據同步保存到磁盤 bgsave:將數據異步保存到磁盤 lastsave:返回上次成功將數據保存到磁盤的Unix時戳 shundown:將數據同步保存到磁盤,然后關閉服務 info:提供服務器的信息和統計 config resetstat:重置info命令中的某些統計數據 config get:獲取配置文件信息 config set:動態地調整 Redis 服務器的配置(configuration)而無須重啟,可以修改的配置參數可以使用命令 CONFIG GET * 來列出 config rewrite:Redis 服務器時所指定的 redis.conf 文件進行改寫 monitor:實時轉儲收到的請求 slaveof:改變復制策略設置發布訂閱相關命令psubscribe:訂閱一個或多個符合給定模式的頻道 例如psubscribe news.* tweet.* publish:將信息 message 發送到指定的頻道 channel 例如publish msg "good morning" pubsub channels:列出當前的活躍頻道 例如PUBSUB CHANNELS news.i* pubsub numsub:返回給定頻道的訂閱者數量 例如PUBSUB NUMSUB news.it news.internet news.sport news.music pubsub numpat:返回客戶端訂閱的所有模式的數量總和 punsubscribe:指示客戶端退訂所有給定模式。 subscribe:訂閱給定的一個或多個頻道的信息。例如 subscribe msg chat_room unsubscribe:指示客戶端退訂給定的頻道。exists(key):確認一個key是否存在 del(key):刪除一個key type(key):返回值的類型 keys(pattern):返回滿足給定pattern的所有key randomkey:隨機返回key空間的一個 keyrename(oldname, newname):重命名key dbsize:返回當前數據庫中key的數目 expire:設定一個key的活動時間(s) ttl:獲得一個key的活動時間 move(key, dbindex):移動當前數據庫中的key到dbindex數據庫 flushdb:刪除當前選擇數據庫中的所有key flushall:刪除所有數據庫中的所有key對String操作的命令set(key, value):給數據庫中名稱為key的string賦予值value get(key):返回數據庫中名稱為key的string的value getset(key, value):給名稱為key的string賦予上一次的value mget(key1, key2,…, key N):返回庫中多個string的value setnx(key, value):添加string,名稱為key,值為value setex(key, time, value):向庫中添加string,設定過期時間time mset(key N, value N):批量設置多個string的值 msetnx(key N, value N):如果所有名稱為key i的string都不存在 incr(key):名稱為key的string增1操作 incrby(key, integer):名稱為key的string增加integer decr(key):名稱為key的string減1操作 decrby(key, integer):名稱為key的string減少integer append(key, value):名稱為key的string的值附加value substr(key, start, end):返回名稱為key的string的value的子串對List操作的命令rpush(key, value):在名稱為key的list尾添加一個值為value的元素 lpush(key, value):在名稱為key的list頭添加一個值為value的 元素 llen(key):返回名稱為key的list的長度 lrange(key, start, end):返回名稱為key的list中start至end之間的元素 ltrim(key, start, end):截取名稱為key的list lindex(key, index):返回名稱為key的list中index位置的元素 lset(key, index, value):給名稱為key的list中index位置的元素賦值 lrem(key, count, value):刪除count個key的list中值為value的元素 lpop(key):返回并刪除名稱為key的list中的首元素 rpop(key):返回并刪除名稱為key的list中的尾元素 blpop(key1, key2,… key N, timeout):lpop命令的block版本。 brpop(key1, key2,… key N, timeout):rpop的block版本。 rpoplpush(srckey, dstkey):返回并刪除名稱為srckey的list的尾元素,并將該元素添加到名稱為dstkey的list的頭部對Set操作的命令sadd(key, member):向名稱為key的set中添加元素member srem(key, member) :刪除名稱為key的set中的元素member spop(key) :隨機返回并刪除名稱為key的set中一個元素 smove(srckey, dstkey, member) :移到集合元素 scard(key) :返回名稱為key的set的基數 sismember(key, member) :member是否是名稱為key的set的元素 sinter(key1, key2,…key N) :求交集 sinterstore(dstkey, (keys)) :求交集并將交集保存到dstkey的集合 sunion(key1, (keys)) :求并集 sunionstore(dstkey, (keys)) :求并集并將并集保存到dstkey的集合 sdiff(key1, (keys)) :求差集 sdiffstore(dstkey, (keys)) :求差集并將差集保存到dstkey的集合 smembers(key) :返回名稱為key的set的所有元素 srandmember(key) :隨機返回名稱為key的set的一個元素對Hash操作的命令hset(key, field, value):向名稱為key的hash中添加元素field hget(key, field):返回名稱為key的hash中field對應的value hmget(key, (fields)):返回名稱為key的hash中field i對應的value hmset(key, (fields)):向名稱為key的hash中添加元素field hincrby(key, field, integer):將名稱為key的hash中field的value增加integer hexists(key, field):名稱為key的hash中是否存在鍵為field的域 hdel(key, field):刪除名稱為key的hash中鍵為field的域 hlen(key):返回名稱為key的hash中元素個數 hkeys(key):返回名稱為key的hash中所有鍵 hvals(key):返回名稱為key的hash中所有鍵對應的value hgetall(key):返回名稱為key的hash中所有的鍵(field)及其對應的value

3.2 redis-benchmark命令

redis-benchmark可以為Redis做基準性能測試,它提供了很多選項幫助開 發和運維人員測試Redis的相關性能

序號選項描述默認值
1-h指定服務器主機名127.0.0.1
2-p指定服務器端口6379
3-s指定服務器 socket
4-c指定并發連接數50
5-n指定請求數10000
6-d以字節的形式指定 SET/GET 值的數據大小2
7-k1=keep alive 0=reconnect1
8-rSET/GET/INCR 使用隨機 key, SADD 使用隨機值
9-P通過管道傳輸 請求1
10-q強制退出 redis。僅顯示 query/sec 值
11–csv以 CSV 格式輸出
12-l生成循環,永久執行測試
13-t僅運行以逗號分隔的測試命令列表。
14-IIdle 模式。僅打開 N 個 idle 連接并等待。
以上實例中主機為 192.168.49.171,端口號為 6392,執行的命令為 set,lpush,請求數為 10000,通過 -q 參數讓結果只顯示每秒執行的請求數。 [root@manager01 ~]# redis-benchmark -h 192.168.49.171 -p 6392 -t set,lpush -n 100000 -q SET: 43917.44 requests per second LPUSH: 51786.64 requests per second[root@manager01 ~]# redis-benchmark -h 192.168.49.171 -p 6392 -c 100 -n 100000 -q PING_INLINE: 42607.59 requests per second PING_BULK: 50864.70 requests per second SET: 51706.31 requests per second GET: 50581.69 requests per second INCR: 50125.31 requests per second LPUSH: 50684.23 requests per second RPUSH: 57142.86 requests per second LPOP: 49043.65 requests per second RPOP: 51948.05 requests per second SADD: 51177.07 requests per second SPOP: 51334.70 requests per second LPUSH (needed to benchmark LRANGE): 50864.70 requests per second LRANGE_100 (first 100 elements): 24758.60 requests per second LRANGE_300 (first 300 elements): 11036.31 requests per second LRANGE_500 (first 450 elements): 8940.54 requests per second LRANGE_600 (first 600 elements): 7476.08 requests per second MSET (10 keys): 30797.66 requests per second[root@manager01 ~]# redis-benchmark -h 192.168.49.171 -p 6392 -c 100 -n 20000 -r 10000 ====== PING_INLINE ======20000 requests completed in 0.58 seconds100 parallel clients3 bytes payloadkeep alive: 10.28% <= 1 milliseconds 91.85% <= 2 milliseconds 98.81% <= 3 milliseconds 99.81% <= 4 milliseconds 99.99% <= 5 milliseconds 100.00% <= 5 milliseconds 34246.57 requests per second====== PING_BULK ======20000 requests completed in 0.45 seconds100 parallel clients3 bytes payloadkeep alive: 11.61% <= 1 milliseconds 99.28% <= 2 milliseconds 99.72% <= 3 milliseconds 99.90% <= 4 milliseconds 100.00% <= 4 milliseconds 44543.43 requests per second====== SET ======20000 requests completed in 0.45 seconds100 parallel clients3 bytes payloadkeep alive: 16.17% <= 1 milliseconds 96.38% <= 2 milliseconds 99.87% <= 3 milliseconds 100.00% <= 3 milliseconds 44843.05 requests per second====== GET ======20000 requests completed in 0.39 seconds100 parallel clients3 bytes payloadkeep alive: 128.71% <= 1 milliseconds 99.81% <= 2 milliseconds 100.00% <= 3 milliseconds 100.00% <= 3 milliseconds 50890.59 requests per second====== INCR ======20000 requests completed in 0.41 seconds100 parallel clients3 bytes payloadkeep alive: 16.71% <= 1 milliseconds 98.00% <= 2 milliseconds 99.75% <= 3 milliseconds 99.96% <= 4 milliseconds 100.00% <= 4 milliseconds 48899.75 requests per second====== LPUSH ======20000 requests completed in 0.40 seconds100 parallel clients3 bytes payloadkeep alive: 15.18% <= 1 milliseconds 93.09% <= 2 milliseconds 99.61% <= 3 milliseconds 100.00% <= 3 milliseconds 49875.31 requests per second====== RPUSH ======20000 requests completed in 0.42 seconds100 parallel clients3 bytes payloadkeep alive: 17.76% <= 1 milliseconds 87.24% <= 2 milliseconds 98.24% <= 3 milliseconds 99.54% <= 4 milliseconds 99.72% <= 5 milliseconds 99.88% <= 6 milliseconds 100.00% <= 6 milliseconds 47846.89 requests per second====== LPOP ======20000 requests completed in 0.44 seconds100 parallel clients3 bytes payloadkeep alive: 11.74% <= 1 milliseconds 81.83% <= 2 milliseconds 99.30% <= 3 milliseconds 99.73% <= 4 milliseconds 99.90% <= 5 milliseconds 100.00% <= 5 milliseconds 45248.87 requests per second====== RPOP ======20000 requests completed in 0.41 seconds100 parallel clients3 bytes payloadkeep alive: 15.95% <= 1 milliseconds 99.17% <= 2 milliseconds 99.76% <= 3 milliseconds 100.00% <= 4 milliseconds 49140.05 requests per second====== SADD ======20000 requests completed in 0.41 seconds100 parallel clients3 bytes payloadkeep alive: 16.28% <= 1 milliseconds 97.25% <= 2 milliseconds 99.98% <= 3 milliseconds 100.00% <= 3 milliseconds 49019.61 requests per second====== SPOP ======20000 requests completed in 0.39 seconds100 parallel clients3 bytes payloadkeep alive: 115.18% <= 1 milliseconds 99.61% <= 2 milliseconds 100.00% <= 2 milliseconds 51679.59 requests per second====== LPUSH (needed to benchmark LRANGE) ======20000 requests completed in 0.44 seconds100 parallel clients3 bytes payloadkeep alive: 13.17% <= 1 milliseconds 77.82% <= 2 milliseconds 97.53% <= 3 milliseconds 99.60% <= 4 milliseconds 99.76% <= 5 milliseconds 99.93% <= 6 milliseconds 100.00% <= 6 milliseconds 45871.56 requests per second====== LRANGE_100 (first 100 elements) ======20000 requests completed in 0.81 seconds100 parallel clients3 bytes payloadkeep alive: 10.01% <= 1 milliseconds 19.49% <= 2 milliseconds 92.38% <= 3 milliseconds 98.71% <= 4 milliseconds 99.69% <= 5 milliseconds 99.96% <= 6 milliseconds 100.00% <= 6 milliseconds 24600.25 requests per second====== LRANGE_300 (first 300 elements) ======20000 requests completed in 1.86 seconds100 parallel clients3 bytes payloadkeep alive: 10.00% <= 2 milliseconds 0.81% <= 3 milliseconds 27.92% <= 4 milliseconds 47.61% <= 5 milliseconds 80.65% <= 6 milliseconds 90.54% <= 7 milliseconds 93.58% <= 8 milliseconds 96.07% <= 9 milliseconds 97.94% <= 10 milliseconds 98.86% <= 11 milliseconds 99.26% <= 12 milliseconds 99.69% <= 13 milliseconds 99.92% <= 14 milliseconds 99.97% <= 15 milliseconds 99.99% <= 16 milliseconds 100.00% <= 16 milliseconds 10746.91 requests per second====== LRANGE_500 (first 450 elements) ======20000 requests completed in 1.82 seconds100 parallel clients3 bytes payloadkeep alive: 10.00% <= 1 milliseconds 0.06% <= 2 milliseconds 0.45% <= 3 milliseconds 24.24% <= 4 milliseconds 41.03% <= 5 milliseconds 69.07% <= 6 milliseconds 83.25% <= 7 milliseconds 90.21% <= 8 milliseconds 94.71% <= 9 milliseconds 97.28% <= 10 milliseconds 98.53% <= 11 milliseconds 98.98% <= 12 milliseconds 99.35% <= 13 milliseconds 99.63% <= 14 milliseconds 99.80% <= 15 milliseconds 99.89% <= 16 milliseconds 99.96% <= 17 milliseconds 99.99% <= 18 milliseconds 100.00% <= 18 milliseconds 10970.93 requests per second====== LRANGE_600 (first 600 elements) ======20000 requests completed in 2.76 seconds100 parallel clients3 bytes payloadkeep alive: 10.00% <= 3 milliseconds 0.38% <= 4 milliseconds 11.99% <= 5 milliseconds 23.41% <= 6 milliseconds 51.24% <= 7 milliseconds 64.32% <= 8 milliseconds 73.74% <= 9 milliseconds 86.28% <= 10 milliseconds 93.30% <= 11 milliseconds 96.13% <= 12 milliseconds 97.79% <= 13 milliseconds 98.67% <= 14 milliseconds 98.98% <= 15 milliseconds 99.24% <= 16 milliseconds 99.44% <= 17 milliseconds 99.61% <= 18 milliseconds 99.72% <= 19 milliseconds 99.79% <= 20 milliseconds 99.85% <= 21 milliseconds 99.90% <= 22 milliseconds 99.94% <= 23 milliseconds 99.97% <= 24 milliseconds 100.00% <= 25 milliseconds 7256.89 requests per second====== MSET (10 keys) ======20000 requests completed in 0.85 seconds100 parallel clients3 bytes payloadkeep alive: 10.00% <= 1 milliseconds 3.28% <= 2 milliseconds 24.63% <= 3 milliseconds 59.44% <= 4 milliseconds 84.07% <= 5 milliseconds 96.65% <= 6 milliseconds 98.99% <= 7 milliseconds 99.67% <= 8 milliseconds 99.97% <= 9 milliseconds 100.00% <= 9 milliseconds 23668.64 requests per second

3.3 Pipeline

3.3.1 執行過程

Redis客戶端執行一條命令分為如下四個過程:

1)發送命令 2)命令排隊 3)命令執行 4)返回結果 ;其中1) 4)稱為Round Trip Time(RTT,往返時間)。

Redis提供了批量操作命令(例如mget、mset等),有效地節約RTT。但 大部分命令是不支持批量操作的,例如要執行n次hgetall命令,并沒有 mhgetall命令存在,需要消耗n次RTT。Redis的客戶端和服務端可能部署在不 同的機器上。例如客戶端在北京,Redis服務端在上海,兩地直線距離約為1300公里,那么1次RTT時間=1300×2/(300000×2/3)=13毫秒(光在真空中 傳輸速度為每秒30萬公里,這里假設光纖為光速的2/3),那么客戶端在1秒 內大約只能執行80次左右的命令,這個和Redis的高并發高吞吐特性背道而馳。

Pipeline(流水線)機制能改善上面這類問題,它能將一組Redis命令進行組裝,通過一次RTT傳輸給Redis,再將這組Redis命令的執行結果按順序返回給客戶端,為沒有使用Pipeline執行了n條命令,整個過程需要n次 RTT

redis-cli的–pipe選項實際上就是使用Pipeline機制,例如下面操作將set hello world和incr counter兩條命令組裝

[root@manager01 ~]# echo -en '*3\r\n$3\r\nSET\r\n$5\r\nhello\r\n$5\r\nworld\r\n*2\r\n$4\r\nincr\r\n$7\r\ncounter\r\n' | redis-cli -h 192.168.49.171 -p 6393 --pipe All data transferred. Waiting for the last reply... Last reply received from server. errors: 0, replies: 2 [root@manager01 ~]#

3.3.2 Pipeline性能測試

  • 給出了在不同網絡環境下非Pipeline和Pipeline執行10000次set操作 的效果,可以得到如下兩個結論:
    • Pipeline執行速度一般比逐條執行要快。
    • 客戶端和服務端的網絡延時越大,Pipeline的效果越明顯。

在不同網絡下,10000條set非Pipeline和Pipeline的執行時間對比

3.3.3 原生批量命令與Pipeline對比

  • Pipeline模擬出批量操作的效果與原生批量命令的區別:
    • 原生批量命令是原子的,Pipeline是非原子的。
    • 原生批量命令是一個命令對應多個key,Pipeline支持多個命令。
    • 原生批量命令是Redis服務端支持實現的,而Pipeline需要服務端和客戶端的共同實現。

3.3.4 最佳實踐

Pipeline雖然好用,但是每次Pipeline組裝的命令個數不能沒有節制,否 則一次組裝Pipeline數據量過大,一方面會增加客戶端的等待時間,另一方 面會造成一定的網絡阻塞,可以將一次包含大量命令的Pipeline拆分成多次 較小的Pipeline來完成。

Pipeline只能操作一個Redis實例,但是即使在分布式Redis場景中,也可 以作為批量操作的重要優化手段

3.4 Redis與Lua

3.5 Bitmaps

3.5.1 數據結構模型

在我們平時的開發過程中,會有-些 bool 型數據需要存取,比如用戶1年的簽到記錄,簽了是1,沒簽是0,要記錄 365 天。如果使用普通的 key/value ,每個用戶
要記錄 365 個,當用戶數上億的時候,需要的存儲空間是驚人的。

為了解決這個問題, Redis 提供了位圖數據結構,這樣每天的簽到記錄只占據一個位, 365 天就是 365 個位, 46 個字節(一個稍長一點的字符串)就可以完全容納下,
這就大大節約了存儲空間。位圖的最小單位是比特(bit ),每個 bit 的取值只能是0或1

3.5.2 命令

  • 設置值setbit key offset value

設置鍵的第offset個位的值(從0算起),假設現在有20個用戶, userid=0,5,11,15,19的用戶對網站進行了訪問,那么當前Bitmaps初始化結果如圖所示。
如果此時有一個userid=50的用戶訪問了網站,那么Bitmaps的結構變成了下圖,第20位~49位都是0(補零)。

192.168.49.171:6392> setbit unique:users:2019-11-19 0 1 (integer) 0 192.168.49.171:6392> setbit unique:users:2019-11-19 5 1 (integer) 0 192.168.49.171:6392> setbit unique:users:2019-11-19 11 1 (integer) 0 192.168.49.171:6392> setbit unique:users:2019-11-19 15 1 (integer) 0 192.168.49.171:6392> setbit unique:users:2019-11-19 19 1 (integer) 0 192.168.49.171:6392> setbit unique:users:2019-11-19 50 1 (integer) 0 192.168.49.171:6392> bitcount unique:users:2019-11-19 --計算2019-11-19這天的獨立訪問用戶數量(獲取Bitmaps指定范圍值為1的個數) (integer) 6 192.168.49.171:6392> bitcount unique:users:2019-11-19 0 20 (integer) 6 192.168.49.171:6392> bitcount unique:users:2019-11-19 1 5 --[start][end]代表起始和結束字節數;面操作計算用戶id在第1個字節 到第3個字節之間的獨立訪問用戶數,對應的用戶id是11,15,19 (integer) 3
  • Bitmaps間的運算

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

利用bitop and命令計算兩天都訪問網站的用戶

3.5.3 Bitmaps分析

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

3.6 HyperLogLog

先思考一個常見的業務問題:如果你負責開發維護一個大型的網站,有一天老板技產品經理要網站上每個網頁每天的 UV 數據,然后讓你來開發這個統計模塊,你會如何實現?

如果統計 PV ,那非常好辦,給每個網頁配一個獨立的 Redis 計數器就可以了,把這個計數器的 key 后綴加上當天的日期。這樣來一個請求,執行 incrby 指令一次,最終就可以統計出所有的 PV 數據。

但是 UV 不一樣,它要去重,同一個用戶一天之內的多次訪問請求只能計數一次。這就要求每一個網頁請求都需要帶上用戶的 ID ,無論是登錄用戶還是未登錄用戶都需要一個唯一 來標識。
你也許已經想到了一個簡單的方案,那就是為每一個頁面設置一個獨立的 set集合來存儲所有當天訪問過此頁面的用戶囚。當一個請求過來時,我們使用 sadd 將用戶ID 塞進去就可以了。通過 scard 可以取出這個集合的大小,這個數字就是這個頁
面的 UV 數據。沒錯,這是一個非常簡單的可行方案。

但是,如果你的頁面訪問量非常大,比如一個爆款頁面可能有幾千萬個 UV ,你就需要一個很大的 set 集合來統計,這就非常浪費空間。如果這樣的頁面很多,那所需要的存儲空間是驚人的。為這樣一個去重功能就耗費這樣多的存儲空間,值得嗎?
其實老板所需要的數據并不需要太精確, 105 萬和 106 萬這兩個數字對于老板來說并沒有多大區別。那么,有沒有更好的解決方案呢?

3.6.1 HyperLogLog命令

HyperLogLog并不是一種新的數據結構(實際類型為字符串類型),而 是一種基數算法,通過HyperLogLog可以利用極小的內存空間完成獨立總數的統計,數據集可以是IP、Email、ID等。

  • HyperLogLog提供了3個命令:pfmerge
    • pfadd 增加計數
    • pfcount 計算獨立用戶數
    • pfmerge 可以求出多個HyperLogLog的并集并賦值給destkey
192.168.49.171:6392> pfadd 2016_03_06:unique:ids "uuid-1" "uuid-2" "uuid-3" "uuid-4" --添加四個元素 (integer) 1 192.168.49.171:6392> pfadd 2016_03_06:unique:ids "uuid-1" "uuid-2" "uuid-3" "uuid-90" (integer) 1 192.168.49.171:6392> pfcount 2016_03_06:unique:ids --計算獨立用戶數 (integer) 5 192.168.49.171:6392> pfadd 2016_03_05:unique:ids "uuid-4" "uuid-5" "uuid-6" "uuid-7" (integer) 1 192.168.49.171:6392> pfmerge 2016_03_05_06:unique:ids 2016_03_05:unique:ids 2016_03_06:unique:ids --合并 OK 192.168.49.171:6392> pfcount 2016_03_05_06:unique:ids (integer) 8 192.168.49.171:6392>

集合類型和HyperLogLog占用空間對比

HyperLogLog內存占用量非常小,但是存在錯誤率

  • 結構選型時只需要確認如下兩條即可:
    • 只為了計算獨立總數,不需要獲取單條數據。
    • 可以容忍一定誤差率,畢竟HyperLogLog在內存的占用量上有很大的優勢。

3.7 發布訂閱

Redis提供了基于“發布/訂閱”模式的消息機制,此種模式下,消息發布 者和訂閱者不進行直接通信,發布者客戶端向指定的頻道(channel)發布消 息,訂閱該頻道的每個客戶端都可以收到該消息

3.7.1 命令

1.發布消息 publish channel message

2.訂閱消息 subscribe channel [channel …]

3.取消訂閱 unsubscribe [channel [channel …]]

4.按照模式訂閱和取消訂閱 psubscribe pattern [pattern…] punsubscribe [pattern [pattern …]]

5.查詢訂閱
(1)查看活躍的頻道 pubsub channels [pattern]
(2)查看頻道訂閱數 pubsub numsub [channel …]
(3)查看模式訂閱數 pubsub numpat

--redis源端192.168.49.171:6392> publish channel:xiaomidou "A baby" (integer) 0--redis接收端192.168.49.171:6392> subscribe channel:xiaomidou Reading messages... (press Ctrl-C to quit) 1) "subscribe" 2) "channel:xiaomidou" 3) (integer) 1--redis源端再發送一次信息192.168.49.171:6392> publish channel:xiaomidou "baby pig" (integer) 1 192.168.49.171:6392> 192.168.49.171:6392> subscribe channel:xiaomidou Reading messages... (press Ctrl-C to quit) 1) "subscribe" 2) "channel:xiaomidou" 3) (integer) 1 1) "message" 2) "channel:xiaomidou" 3) "baby pig"
  • 如果有多個客戶端同時訂閱了;有關訂閱命令有兩點需要注意:
    • 客戶端在執行訂閱命令之后進入了訂閱狀態,只能接收subscribe、 psubscribe、unsubscribe、punsubscribe的四個命令。
    • 新開啟的訂閱客戶端,無法收到該頻道之前的消息,因為Redis不會對 發布的消息進行持久化。

3.8 GEO(地理信息定位)

Redis3.2版本提供了GEO地理信息定位功能, 支持存儲地理位置信息用來實現諸如附近位置、 搖一搖這類依賴于地理位置信息的功能, 對于需要實現這些功能的開發者來說是一大福音。

geoadd key longitude latitude member [longitude latitude member …] 增加地理位置信息
geopos key member 獲取地理位置信息
longitude、 latitude、 member分別是該地理位置的經度、 緯度、 成員, 表3-7展示5個城市的經緯度

192.168.49.171:6392> geoadd cities:locations 116.28 39.55 beijing --增加地理位置信息 (integer) 1 192.168.49.171:6392> geoadd cities:locations 116.28 39.55 beijing --返回結果為1, 如果已經存在則返回0 (integer) 0 192.168.49.171:6392> geoadd cities:locations 117.12 39.08 tianjin 114.29 38.02 shijiazhuang 118.01 39.38 tangshan 115.29 38.51 baoding --geoadd命令可以同時添加多個地理位置信息 (integer) 4

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

  • 其中unit代表返回結果的單位,包含以下四種:
    • m(meters) 代表米。
    • km(kilometers) 代表公里。
    • mi(miles) 代表英里。
    • ft( feet) 代表尺
192.168.49.171:6392> geopos cities:locations tianjin --獲取天津的經維度 1) 1) "117.12000042200088501"2) "39.0800000535766543"
  • 獲取指定位置范圍內的地理信息位置集合

georadius key longitude latitude radiusm|km|ft|mi [withcoord] [withdist] [withhash] [COUNT count] [asc|desc] [store key] [storedist key]

georadiusbymember key member radiusm|km|ft|mi [withcoord] [withdist] [withhash] [COUNT count] [asc|desc] [store key] [storedist key]

georadius和georadiusbymember兩個命令的作用是一樣的, 都是以一個地理位置為中心算出指定半徑內的其他地理信息位置,不同的是georadius命令的中心位置給出了具體的經緯度,georadiusbymember只需給出成員即可。其中radiusm|km|ft|mi是必需參數,指定了半徑(帶單位),

  • 這兩個命令有很多可選參數, 如下所示:
    • withcoord: 返回結果中包含經緯度。
    • withdist: 返回結果中包含離中心節點位置的距離。
    • withhash: 返回結果中包含geohash, 有關geohash后面介紹。
    • COUNT count: 指定返回結果的數量。
    • asc|desc: 返回結果按照離中心節點的距離做升序或者降序。
    • store key: 將返回結果的地理位置信息保存到指定鍵。
    • storedist key: 將返回結果離中心節點的距離保存到指定鍵
192.168.49.171:6392> georadiusbymember cities:locations beijing 150 km --獲取兩個地理位置的距離 1) "beijing" 2) "tianjin" 3) "tangshan" 4) "baoding" 192.168.49.171:6392> geohash cities:locations beijing --Redis使用geohash將二維經緯度轉換為一維字符串, 下面操作會返回beijing的geohash值。 1) "wx48ypbe2q0" 192.168.49.171:6392> type cities:locations zset 192.168.49.171:6392> zrem key cities:locations beijing (integer) 0 192.168.49.171:6392> geohash cities:locations beijing 1) "wx48ypbe2q0" 192.168.49.171:6392>

總結

以上是生活随笔為你收集整理的03:小功能大用处的全部內容,希望文章能夠幫你解決所遇到的問題。

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