redis的一些坑
from:http://my.oschina.net/u/875730/blog/378086
0 redis跨機房使用問題
? 一般地,redis的每個實例都是一個master加上一個slave,這一主一備一般要放在同一個機房idc,否則會出現各種莫名其妙的問題。為了防止一個idc出問題,可以用scp或者rsync命令把redis數據定時(譬如每隔10分鐘或者半小時)地備份到另一個機房。
1?redisContext盡量在一個線程內使用
? ?《從hiredis使用出core談談redis多線程的使用》一文中提到:redis是單線程異步模型,hiredis這個客戶端看來也只支持單線程。
2 發送二進制數據
《Redis C語言客戶端庫hiredis文檔翻譯》一文提到:
當你需要發送二進制安全的命令可以采用%b的格式化方式,同時需要一個字符串指針和size_t類型的字符串長度參數,如下
reply = redisCommand(context, "SET foo %b", value, (size_t) valuelen);
在API內部,Hiredis根據不同的參數分割命令轉化為操作redis數據庫的標準命令,你可以格式化多個參數來構造redis的命令,如下
reply = redisCommand(context, "SET key:%s %s", myid, value);
《C++ Redis mset 二進制數據接口封裝方案》一文作者貌似不知道這個用法,他通過redisCommandArgv這個函數繞了一圈來發送二進制數據。
3 兩級hash
http://www.cnblogs.com/restran/p/4295184.html
每個key-vaulue結構,Redis本身的維護開銷就要80幾字節,即便value存儲的是純數字(會使用long類型,占用4個字節),也依然很大,1000萬的數據,就要占用快1G內存。
依據官方文檔的內存優化方法,以及這篇文章 節約內存:Instagram的Redis實踐,建議對ID分段作為key,并使用 hash 來存儲第一級 key 的 value,第二級存儲較少的數據量(推薦1000),因此第二級的key使用ID的后3位。
4 redis-cli 在非交互模式下直接執行命令時附帶模糊參數
? ?redis-cli -h 127.0.0.1 -p 6379 keys '*'
or redis-cli ?-h 127.0.0.1 -p 6379 keys "*"
5 老版本的sentinel問題注意
最近使用v2.8.19的sentinel,監控一個服務器的配置為:
sentinel monitor server1 127.0.0.1 36379 1
sentinel down-after-milliseconds server1 3000
sentinel parallel-syncs server1 1
sentinel failover-timeout server1 15000
sentinel auth-pass server1 r23456
測試時候一切正常,但是在線上服務器部署后,發生主fail的情況的時候,主從切換并沒有發生,檢查了線上版本的sentinel版本,為v2.6.11。
講過一番檢查,添加了can-failover,就正常了,修改后的配置項為:
sentinel monitor server1 127.0.0.1 36379 1
sentinel can-failover server1 yes
sentinel down-after-milliseconds server1 3000
sentinel parallel-syncs server1 1
sentinel failover-timeout server1 15000
sentinel auth-pass server1 r123456
另外,使用這個版本的sentinel的時候請把conf文件中原有的mymaster相關配置注釋掉,否則就坑爹了,你會發現你的監控項多了一項mymaster。
6 在一個腳本中批量執行多個寫入操作
先把插入操作放入操作文本insert.bat:
?
| 1 2 3 4 | set?a?b set?1?2 set?h?w set?f?u |
如果是在unix上寫的insert.bat,請用命令"unix2dos ?insert.bat"轉換其格式。
然后執行命令:cat insert.bat | ./redis-cli --pipe,或者如下腳本:
?
| 1 2 3 4 5 | #!/bin/sh host=$1 port=$; password=$3 cat?insert.bat?|?./redis-cli?-h?$host?-p?$port?-a?$password?--pipe |
7 twemproxy及時感知死掉的redis server
from:http://www.oschina.net/translate/twemproxy-a-twitter-redis-proxy?評論
我在虛擬機上安裝了twemproxy,使用的是nutcracker-0.2.2.tar。配置文件如下:
lpha:
listen: 127.0.0.1:22121
hash: fnv1a_64
distribution: ketama
auto_eject_hosts: true
redis: true
server_retry_timeout: 2000
server_failure_limit: 1
servers:
- 127.0.0.1:6379:1
- 127.0.0.1:6380:1
- 127.0.0.1:6381:1
三個redis都啟動時,服務正常。當我把 127.0.0.1:6379停掉時,該服務節點不自動摘除,執行set命令時一直有服務拒絕的命令。
[root@localhost?redis]# ./redis-cli -p 22121 set 1 1
(error) ERR Connection refused
當我把故障的redis恢復后,發現服務正常了。結果全部是OK
以上測試可以看出,故障節點沒有自動摘除。
請問專家,這是為何?我沒有配置好?
server_retry_timeout: 2000->60000
server_failure_limit: 1->0
試試修改以上兩個配置,第一個retry的間隔時間要拉長,不然你的nutcracker一直在重試連接,自然一直摘不掉機器;第二個容忍的錯誤數可以設置成0容忍,就是說有錯誤立馬摘掉這個機器。
我把server_retry_timeout: 20000000這個重連時間改的更長了
這次真的摘除了~謝謝啊!
原來這個參數代表的是發現故障后,恢復連接間隔時間,我還一直以為重試是內部機制呢,原來不是。。這個有點坑爹
8 persistence
? redis的數目備份有rdb和aof兩種格式,rdb可以認為是一個時刻的redis內存數據的二進制鏡像,而aof則是redis數據的mysql的binlog式的寫請求日志文件。
?rdb文件保存方式特點在于:1 在數據非常多的情況下,使用rdb會占用比aof文件更少的磁盤,也更適合遠程數據備份,一旦創建完畢就不會再被修改;2 redis啟動后能夠很快加載rdb文件,如果要重放aof的命令則會很耗費時間;3 rdb文件是某個時間點redis所有數據的image,redis會fork一個進程來進行工作,短則數毫秒長則一秒多內外部客戶端的請求不會被及時處理,不能及時保持所有時刻的數據,一旦發生事故,最近一段時間內的寫請求的數據就會丟失;4 redis執行rdb文件保存的時候,會fork一個子進程創建一個臨時文件進行數據保存任務,數據保存完畢后它會刪除老的文件并把新的文件rename為老文件的名字;
? aof文件保存方式的特點在于:1 aof保存有三種策略:無fsync(即不保存數據把redis作為一個cache)、每秒鐘進行一次fsync和每次寫請求都執行fsync,默認是fsync每秒,這種策略被執行的時候redis會創建一個線程進行fsync任務,所以不會影響主線程的工作,就算發生事故也僅僅丟掉了一秒鐘內的請求數據;2 aof保存的是文本格式的請求log,如果出現用戶不小心執行了flushall這種命令,用戶可以手工修改aof文件后重啟redis即可;3 aof文件的缺點就在于size太大,而且執行數據恢復的時間太長;4 redis執行aof任務的時候與rdb流程比較相似,redis先fork一個子進程創建一個新的aof文件,然后把當前進程中的數據以客戶端與服務端的通訊方式的寫請求形式保存下來,保存過程中如果有新的寫請求,主進程會把這些寫請求寫進老的aof文件的同時也創建一個內存buffer,以保存這批新的請求命令,子進程完成任務后會發送signal給父進程,父進程會delete old aof file并且rename new aof file,然后把buffer中的寫請求追加到new aof file中。
? ? 所以一般安全點的方法就是兩種文件保存方法并用。如果redis正在執行rdb保存任務,而用戶發送了BGREWRITEAOF 命令給redis,則redis會把任務排隊,返回ok給client,當redis執行完畢rdb任務的時候才會執行aof任務。當redis啟動執行recovery的時候,它會優先采用aof文件,因為aof文件的數據總比rdb新。
? ? redis執行aof任務主要由rewriteAppendOnlyFileBackground->rewriteAppendOnlyFile完成,查看這個函數的源碼,可以看到所有的db都存在server.db(容量為server.dbnum)之中,每個db類型的redisDb,其主要成員為dict *dict,即所有key都是按照hashtable羅列的,這個hashtable的優點是可以按照iterator那樣去遍歷。
9 codis
?我們線上的?redis?集群最大單服務的是?800G?左右,?分成32個分片,?對應?codis?的32個?Server?group,?總的?qps?大概?10w?左右,?我們用了?2個?codis-proxy?抗著,基本沒壓力 。rocksdb?的存儲引擎:https://github.com/reborndb/qdb,其實啟動后就是個?redis-server,支持了?PSYNC?協議,所以可以直接當成redis從來用 。
codis改進了一下redis缺點:
1 redis數據量太大的話(22G以上),他的處理性能就開始下降;
2 無法區分冷熱數據,內存浪費嚴重;
3 RDB Block住整個服務;
4 寫操作太頻繁,AOF刷盤太多,很容易rewrite
總結
- 上一篇: HLS视频协议第一弹--centos下面
- 下一篇: Redis命令——Keys相关