《Redis开发与运维》读书笔记一
?之前這本書看了大概二分之一,后面就沒有再堅持下去,這次在我球管理redis-manager的機會,重新撿起這本書,深度的閱讀,以防止自己記憶碎片,整理文檔。Redis開發與運維這本書的內容太多,網上沒有找到檢索,記錄下來自己認為重要的信息片段,供檢所使用。
書籍地址:https://github.com/singgel/Study-Floder
目錄
redis可以做什么:
redis可執行文件:
redis版本:
redis的API:
慢查詢分析:
redis-cli:
redis-benchmark:
pipeline:
事物:
Lua:
Redis如何管理Lua:
Bitmaps:
HyperLogLog:
發布訂閱:
GEO:
客戶端通信協議:
Jedis:
Python的redis-py:
客戶端api:
輸入緩沖區:
輸出緩沖區:
客戶端存活狀態:
客戶端限制:
客戶端常見異常:
持久化觸發機制:
RDB文件處理:
AOF使用:
redis可以做什么:
- 緩存
- 排行榜系統
- 計數器應用
- 社交網絡
- 消息隊列系統
redis可執行文件:
- redis-server
- redis-cli
- redis-benchmark #基準測試工具
- redis-check-aof #aof持久化文件檢測和修復工具
- redis-check-dump #rdb持久化文件檢測和修復工具
- redis-sentinel
redis版本:
- 2.6 bind多地址 sentinel哨兵 主從復制
- 3.0 embedded編碼 migrate連接緩存
- 3.2 quicklist編碼
- 4.0 非阻塞del和flush命令 memory命令
redis的API:
- 全局:keys dbsize exists del expire(好幾個時間級別) type rename ttl
- 數據結構:object encoding?
- String:set|mset key value?[ex second]?[px milliseconds]?[nx|xx]? (編碼:int embstr raw)
- hash:hset|hmset key field value?[field value ...] (編碼:ziplist<512個 64kb hashtable)
- list:rpush key value?[value ...]{linsert listkey before key key}?(編碼:ziplist<512個 64kb linkedlist quicklist)
- set:sadd key element?[element ...](編碼:inset<512個? linkedlist quicklist)
- zset:zadd key score member?[score member ...]?(編碼:ziplist<512個 64kb skiplist)
- migrate: migrate host port key|"" destination-db timeout?[copy]?[replace]?
- sacn:在scan過程中出現鍵的變化(增加刪除修改),會出現新增沒有遍歷到、出現鍵的重復
- config rewrite將配置持久化到本地
慢查詢分析:
- 預設閥值slowlog-log-slower-than<10000微秒(高QPS建議1ms)
- 慢查詢記錄showlog-max-len最多紀錄多少條(線上可設置大一些,不會占用大量內存)
- showlog get?[n]
redis-cli:
-r(重復次數repeat)
-i(間隔時間interval 單位s)redis-cli -r 100 -i 1 info|grep used_memory_human
-x(標準輸入stdin)echo "world" | redis-cli -x set hello
-c(集群模式cluster)
-a(密碼auth)
--scan --pattern(掃描指定模式的鍵)
--slave 把客戶端模擬成Redis的從節點
--rdb 生成RDB持久化文件
--pipe 將命令封裝發送
--bigkeys 用scan對redis采樣,找出大key
--eval 執行指定lua腳本
--latency 檢測網絡延遲 redis-cli -h?{machineB} --latency
--stat 實時獲取redis統計信息
--raw 返回原始文本
redis-server:
--test-memory 用來檢測但前操作系統能否穩定的分配指定容量內存給redis
redis-benchmark:
-c 代表客戶端的并發數量(默認50)
-n 代表客戶端請求總數(默認100000)
-q 僅僅顯示redis-benchmark的requests per second信息
-r 在一個redis上執行命令會發現只有3個鍵,想插入更多使用-r(random)
-p 每個請求的pipeline數量 (默認1)
-k 代表客戶端是否使用keepalive 1使用 0不使用(默認1)
-t 指定基準測試模式 eg:-t get set
--csv 將結果按照csv格式輸出
pipeline:
redis提供了批量操作的命令(mget mset之類)但大部分不支持(例如hgetall)
注意:一次組裝pipeline量過大會增加client等待時間,還會造成網絡阻塞,分成多個pipeline來完成
事物:
multi和exec之間,multi代表事物開始,exec代表事物結束
停止事物的話使用discard命令
出現語法錯誤(eg:sett),導致事物無法執行
運行時錯誤(eg:sadd–zadd),導致執行,結果無法回滾
若要確保事物中的key沒有被其他客戶端修改:watch
Lua:
boolean、numbers、strings、tables
| localhost?int?sum=0 for?i=1,?100 do ????sum=sum+1 end print(sum) ? ? //函數定義 function funName() ????... end contract拼接字符串 function contract(str1,str2) ????return?str1 .. str2 end --"hello world" print(contract("hello",?"world")) |
eval:eval 腳本內容 key個數 key列表 參數列表
? ? ? ? ? eg:eval?'return "hello " .. KEYS[1] .. ARGV[1]'?1?redis world? 輸出:"hello redisworld"
redis-cli --eval執行客戶端寫好的腳本
evalsha:首先將Lua腳本加載到Redis服務器,得到該腳本的SHA1校驗和
? ? ? ? ? ? ? redis-cli script load “$(cat lua_get.lua)” 輸出 “SHA1值”
? ? ? ? ? ? ? evalsha 腳本的SHA1值 key個數 key列表 參數列表
redis.call函數 訪問Redis
redis.log函數 將Lua腳本日志輸出到redis中
Redis如何管理Lua:
- script load:將Lua腳本加載到內存
- script exists:判斷SHA1是否在
- script flush:清除已經加載的所有Lua腳本
- script kill:殺掉正在執行的Lua腳本
Bitmaps:
以位為單位的數組,數組每個單元只能存儲0和1
setbit key offset 0|1
getbit key offset
bitcount?[start][end]
bitop是一個復合操作 做多個bitmap的交集(and) 并集(or) 非(not) 異或(xor)
bitops key targetBit計算第一個值為targetBit的偏移量
用途:
存儲一個網站一天活躍用戶
HyperLogLog:
用途:
存儲IP、Email、ID等,存在誤差0.81%
pfadd key element?[element ...] 添加
pfcount key?[key ...]計算獨立用戶數
pfmerge destkey sourcekey?[sourcekey ...]合并,求并集
發布訂閱:
publish channel message發布消息
subscribe channel?[channnel ...]訂閱消息
新訂閱的客戶端無法接受到消息,因為redis不持久化消息
unsubscribe?[channel [channnel ...]]取消訂閱
psubscribe pattern?[pattern ...]批量訂閱
punsubscribe?[pattern [pattern ...]]批量取消訂閱
pubsub channels?[pattern]查看活躍的頻道
pubsub numsub?[channel ...]查看頻道訂閱數
pubsub numpat查看訂閱數
用途:
聊天室、公告牌、服務之間的消息解耦
GEO:
geoadd key longitude latitude member?[longitude latitude member ...]
geopos key member?[member ...]
geolist key member1 member2?[unit]獲取兩地之間的位置信息
獲取指定范圍內的地理信息georadius georadiusbymember
geohash key member?[member ...]獲取geohash,GEO的數據類型為ZSET
geohash編碼和經緯度是可以相互轉換的
zrem key member 刪除地理位置信息
客戶端通信協議:
一:TCP協議之上
二:RESP序列化協議
想要看到RESP的真是結果,可以使用nc、telnet、socket程序
Jedis:
太簡單,算了。。。
對了pipeline值得講一下
eg:批量刪除
public void mdel(List<String> keys){
? ? Jedis jedis = new Jedis("127.0.0.1");
? ? Pipeline pipeline = jedis.pipelined();
? ? for(String key : keys){
? ? ? ?pipeline.del(key);
? ? }
? ? pipeline.sync();
}
pipeline.syncAndReturnAll()獲取返回結果
lua腳本也得來一下:
eg:scriptLoad發送腳本的形式
String key = "hello";
String script = "return redis.call('get',KEYS[1])";
Object result = jedis.eval(script, 1, key);
System.out.println(result);
eg:evalsha服務端宿主的形式
String key = "hello";
Object result = jedis.evalsha(scriptSha, 1, key);
System.out.println(result);
Python的redis-py:
算了吧,這個我不用。。。
套路和jedis差不多
客戶端api:
client list能夠列出與Redis服務端相連的所有客戶端信息
id:客戶端連接的唯一標識,id隨著redis自增,重啟后置為0
addr:客戶端的ip和端口
fd:socket的文件描述符,fd=-1代表客戶端不是外部客戶端,是Redis內部的偽裝客戶端
name:客戶端的名字
輸入緩沖區:
Redis為每一個客戶端分配了輸入緩沖區,動態規劃的,最大為1G,超過后客戶端將被關閉
qbuf:代表客戶端緩沖區的總容量
qbuf-free:代表了客戶端的剩余容量
輸入緩沖區不收maxmemory控制
解釋:
假設一個Redis實例設置了maxmemory為4G,已經存儲了2G數據
如果此時輸入緩沖區使用了3G,可能會造成數據丟失、鍵值淘汰、OOM的情況
原因:
Redis的處理速度跟不上輸入緩沖區的輸入速度,并且每次輸入緩沖區的命令包含了大量的bigkey
Redis發生阻塞,短期內不能處理命令,造成客戶端命令積壓在輸入緩沖區,造成緩沖區過大
解決:
定期執行client list命令,手機qbuf和qbuf-free記錄
通過info clients找出最大輸入緩沖區,可以將client_biggest_input_buf設置超過10M就報警
Redis為每個客戶端分配了輸出緩沖區,保證執行結果返回給客戶端
輸出緩沖區:
輸出緩沖區的容量可以通過參數client-output-buffer-limit進行設置
普通客戶端、發布訂閱客戶端、slave客戶端
client-out-buffer-limit <class> <hard limit> <soft limit> <soft seconds>
<class>:客戶端類型:normal普通客戶端、slave客戶端、pubsub發布訂閱客戶端
<hard limit>:緩沖區大小,>該值客戶端立即關閉
<soft limit> <soft seconds>:如果客戶端使用的緩沖區超過soft limit并持續soft limit秒,客戶端立即關閉
跟輸入緩沖區一樣,使用不當將會造成數據丟失、鍵值淘汰、OOM的
?
組成:
由固定緩沖區和動態緩沖區組成
固定緩沖區村較小的執行結果(使用字節數組)
動態緩沖區存較大的結果,較大的字符串、hgetall、smembres(使用列表)
obl:固定緩沖區長度
oll:動態緩沖區長度
omem:使用的字節數
解決:
監控、設置閥值
限制客戶端緩沖區的大小
適當增大slave的緩沖區
限制容易讓輸出緩沖區增大的命令
及時監控內存,發現內存抖動頻繁,有可能是輸出緩沖區過大造成
客戶端存活狀態:
age:已經連接的時間
idle:最近一次空閑的時間
客戶端限制:
maxclients:限制最大客戶端連接數(默認10000)
timeout:連接最大空閑時間
client setname|getname設置名字
client kill ip:port殺掉
client pause timeout暫停,對于slave無效
monitor監聽服務端執行的命令
tcp-keepalive進行活性檢測,防止大量死連接占用系統資源(默認0)
tcp-backlog TCP握手后的連接隊列(默認511)
客戶端常見異常:
無法從連接池獲取到連接:
blockWhenExhausted=flase不等待、存在慢查詢阻塞了連接池
客戶端讀寫超時:
讀寫超時間設置過短、命令本身慢、網絡不正常、Redis自身阻塞
客戶端連接超時:
連接超時設置過短、Redis阻塞、網絡不正常
客戶端緩沖區異常:
輸出緩沖區慢、長時間時間限制連接被主動斷開、不正常并發讀寫
Lua腳本正在執行:
Busy Redis is busy running a script
Redis正在持久化文件:
Loading Redis is loading the dataset in memory
Redis內存超過maxmemory設置:
OOM command not allowed when use memory
客戶端連接數過大:
ERR max number of clients reached
主從內存不一致:
緩沖區的大小占用了大量內存空間
客戶端周期性超時:
運維層面架空慢查詢、開發層面加強對Redis理解
持久化觸發機制:
save:阻塞Redis服務器,對于內存較大的實例會造成長時間的阻塞(已經廢棄)
bgsave:Redis進程執行fork操作創建子進程,阻塞只發生在fork階段
觸發:
save m n表示m秒內數據存在n次修改觸發bgsave
從節點執行全量復制操作,主節點生成RDB文件發送給從節點
debug reload命令重新加載Redis時
默認情況下執行shutdown命令時,如果沒有開啟AOF持久化功能自動執行bgsave
執行流程:
info stats:
latest_fork_usec可以獲取最近一個fork操作的耗時(微秒)
rdb_last_save_time最后一次生成RDB的時間
RDB文件處理:
config set dir?{newDir}遇見磁盤寫滿時,切換完路徑執行bgsave切換
config set dbfilename?{newFileName}下次運行的時候RDB會保存到新的位置
config set rdbcompression?{yes|no}采用LZF算法生成RDB壓縮
優點:
RDB是緊湊型的二進制文件,用作災難恢復
RDB恢復速度快于AOF
缺點:
沒有辦法做到實時/秒級,針對這個問題可以使用AOF來解決
RDB的版本演進,導致無法兼容新的RDB格式
AOF使用:
問題:
1.AOF為什么采用文本?
文本具有很好的兼容性、直接采用協議格式避免二次處理開銷、文本具有可讀性
2.AOF為什么不直接將命令追加到aof_buf?
性能取決于當前硬盤的負載、另一個好處多緩沖區同步
appendfsync控制同步策略
write、fsync、alway(SATA)、no、everysec(默認)
重寫壓縮數據:bgrewriteaof手動觸發、auto-aof-rewrite-min-size、auto-aof-rewrite-percentage
進程內超時的數據不再寫入
進程內整個流程無效的數據不再寫入
多條命令合為一條
總結
以上是生活随笔為你收集整理的《Redis开发与运维》读书笔记一的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java虚拟机(JVM)默认字符集详解
- 下一篇: 從三種方式看SQL的使用程度