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