前言
本文根據貴金屬使用Redis的經驗,整理了Redis服務端配置模板、哨兵配置模板、監控項部署、持久化解決方案、Jedis客戶端連接池配置說明,旨在減少大家在使用Redis過程中因爲配置不當引發的問題。
後續的文章鏈接中也給出了之前遇到的一些問題,以及對默認配置項進行選擇的原因,供大家參考。(Redis Server端版本2.8.19,客戶端使用Jedis2.6.0),截止到本文發表前Redis4.0已經release,但並不影響本文的配置選擇,4.0的新特性我們也會持續跟進,歡迎大家一起討論。
1. Redis哨兵模板
哨兵的部署至少3臺,物理機獨立部署,奇數個;
哨兵模板見附錄1
2. Redis Server模板
Server模板見附錄2
配置模板需要根據使用情況做調整:
1)根據Redis用途需要指定不同的key淘汰策略
Redis用作緩存(允許數據淘汰) | Redis作爲內存數據庫(不允許淘汰) |
---|---|
maxmemory-policy { allkeys-lruvolatile-lruallkeys-randomvolatile-randomvolatile-ttl } | maxmemory-policy noeviction |
2)持久化方案選擇
cpu、磁盤性能是否支持持久化
支持 | 不支持 |
---|---|
參考下面2種因素 | Master關閉持久化Slave開啓rdb定時rdb同步 |
使用內存上限
超過10G | 不超過10G |
---|---|
Master開啓aofslave開啓rdb定時腳本執行bgrewriteaof | Master開啓rdbSlave開啓rdb |
能否容忍少量數據丟失
能 | 不能 |
---|---|
Master開啓rdbslave開啓rdb | Master開啓aofSlave開啓rdb |
需要根據使用場景綜合考慮三個因素的影響,評估可接受的方案。
備註:
1)Rdb定時同步主要防止主從切換失敗時手動啓動Master或誤重啓導致數據丟失(腳本見附錄3)。 2)不建議主備都開啓aof,slave開啓rdb可以防止aof文件損壞造成數據無法恢復。 3)選擇10G作爲rdb是否適用的閾值是因爲:
- 新浪微博給的建議是不超過20G,而我們虛機上的測試,要想保證應用毛刺不明顯,內存建議在控制在10G以下。
- 內存空間達到40G(考慮每個頁表條目消耗 8 個字節),那麼頁表大小就有80M,複製頁表有些虛擬機需要200ms以上,我們設置慢日誌的閾值是50ms,爲保證不被慢日誌捕獲內存也建議控制在10G以下。
3. Redis監控方案及閾值設置
1)連接數 監控項:check.redis.connected_clients.XXX 案例舉例:方法內部有耗時操作,導致連接數歸還緩慢,連接數上升;沒有正確歸還連接,導致連接數上升。
2)ops 監控項:check.redis.instantaneous_ops_per_sec.XXX 案例舉例:業務代碼有bug,導致頻繁的操作redis,導致ops上升。
3)內存使用 監控項:check.redis.used_memory.XXX 案例舉例:客戶端連續的hgetAll操作,請求數據過多,響應數據放入緩衝區,佔用了redis內存空間,導致內存使用突然飆升。
4)慢日誌開啓 在redis配置文件中配置慢日誌門限 slowlog-log-slower-than 50000 //表示redis操作超過50ms的操作記錄慢日誌 slowlog-max-len 1024 //慢日誌記錄最多保留1024個 通過在redis服務端使用slowlog get命令可以獲取最新的慢日誌記錄,通過慢日誌記錄排查操作耗時的命令並進行相應的調整。
5)cpu steal、cpu load 監控項:system.cpu.util.steal、system.cpu.load cpu steal或者cpu load過高,都有可能卡redis實例,導致業務超時等問題。 cpu steal過高如果是由於共享cpu導致的,可考慮調整爲獨享的方式;cpu load過高需要排查看是該機器上什麼操作影響的。
報警方案根據應用的具體情況來設置:
1)內存最大容量6G, 報警門限4G (75%左右) 2)連接數超過5000(最高10000)報警 (50%左右) 3)操作數每秒超過50000(最高100000)報警 (50%左右) 4)慢日誌50ms報警
4. 客戶端jedis連接池配置建議
JedisPoolConfig參考配置
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxIdle" value="30" /> //JedisPool最大空閒連接數 <property name="minIdle" value="10" /> //JedisPool最小空閒連接數,也即初始化連接數 <property name="testOnBorrow" value="false" /> //從JedisPool獲取jedis實例時檢查連接的有效性,默認是false <property name="testWhileIdle" value="false" /> //表示有一個idle object evitor線程對idle object進行掃描,如果validate失敗,此object會被從pool中drop掉 <property name="testOnReturn" value="true" /> //將jedis實例歸還連接池時檢查連接的有效性,默認是false ;test開啓太多會影響性能,都不開啓異常連接可能會被使用,建議至少開啓一個 <property name="maxTotal" value="300"/> //JedisPool最大連接數 <property name="maxWaitMillis" value="4000"/> //從JedisPool獲取連接等待毫秒數,超時則拋異常;若blockWhenExhausted爲false,該配置項無效 <property name="blockWhenExhausted" value="false"/> //blockWhenExhausted 表示連接耗盡時是否阻塞, false報異常,ture阻塞maxWaitMillis直到超時 ;不配默認是true;建議配置爲false </bean>
注:jedis的讀超時和連接超時都是timeout
配置模板參數設置原因可以參考 http://tech.lede.com/2017/07/03/rd/server/redisconfig/
附錄1
port {port} daemonize yes pidfile “/{HOME}/log/sentinel.pid” logfile “/{HOME}/log/sentinel.log” sentinel monitor master {ip address} {port} {quorum} /當哨兵數爲3的時候,quorum需配置爲2,哨兵數爲5的時候,quorum需配置爲3/ sentinel down-after-milliseconds master 60000 /哨兵與master失連1分鐘則主觀下線/ sentinel failover-timeout master 180000 sentinel config-epoch master 0
附錄2
1)Master配置: port {port} daemonize yes pidfile /{HOME}/log/redis.pid logfile /{HOME}/log/redis.log dir /{HOME}/data dbfilename dump.rdb requirepass {password} masterauth {password} timeout 0 loglevel notice databases 16 rdbcompression yes maxclients 10000 maxmemory {maxmemory} maxmemory-policy noeviction save 900 1 save 300 10 save 60 300 appendonly no appendfsync everysec no-appendfsync-on-rewrite yes auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb slowlog-log-slower-than 50000 slowlog-max-len 1024
client-output-buffer-limit normal 10mb 5mb 10 client-output-buffer-limit slave 1024mb 256mb 300 client-output-buffer-limit pubsub 32mb 8mb 60 lua-time-limit 1000
rename-command FLUSHALL SUPER_FLUSHALL rename-command FLUSHDB SUPER_FLUSHDB rename-command SHUTDOWN SUPER_SHUTDOWN rename-command KEYS SUPER_KEYS rename-command MONITOR SUPER_MONITOR
2)Slave配置: port {port} daemonize yes pidfile /{HOME}/log/redis.pid logfile /{HOME}/log/redis.log dir /{HOME}/data dbfilename dump.rdb requirepass {password} masterauth {password} timeout 0 loglevel notice databases 16 rdbcompression yes maxclients 10000 maxmemory {maxmemory} maxmemory-policy noeviction save 900 1 save 300 10 save 60 300
appendonly no appendfsync everysec no-appendfsync-on-rewrite yes auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb slowlog-log-slower-than 50000 slowlog-max-len 1024
client-output-buffer-limit normal 10mb 5mb 10 client-output-buffer-limit slave 1024mb 256mb 300 client-output-buffer-limit pubsub 32mb 8mb 60 lua-time-limit 1000
slaveof {ip address} {port}
rename-command FLUSHALL SUPER_FLUSHALL rename-command FLUSHDB SUPER_FLUSHDB rename-command SHUTDOWN SUPER_SHUTDOWN rename-command KEYS SUPER_KEYS rename-command MONITOR SUPER_MONITOR
附錄3
#!/bin/sh project=$1 backup_dir="/home/redisInstance/$project/data/rdb_bak/" if [ ! -d "$backup_dir" ]; then mkdir -p "$backup_dir" fi list=`ls /home/redisInstance/$project/data/rdb_bak/ | wc -l ` echo "[$(date +%Y%m%d-%H:%M:%S)] the backup files number is $list" result=$(find "$backup_dir" -amin +60 -name dump.rdb.* -print) if [ $list -gt 13 ] then if [ x"$result" = x ] then echo "[$(date +%Y%m%d-%H:%M:%S)] no backup files found to delete!" else echo -e "[$(date +%Y%m%d-%H:%M:%S)] backup files found to delete : \"$result\" !" fi find "$backup_dir" -amin +60 -name "dump.rdb.*" -exec rm -rf {} \; else echo "[$(date +%Y%m%d-%H:%M:%S)] the backup files number is less than 13, no files allowed to delete" fi backuptime=$(date +%Y%m%d%H%M) eval rsync -a /home/redisInstance/"$project"/data/dump.rdb "$backup_dir"dump.rdb."$backuptime" cp "$backup_dir"dump.rdb."$backuptime" "$backup_dir"dump.rdb if [ $? -eq 0 ] then echo "[$(date +%Y%m%d-%H:%M:%S)] the rdb file backup to local dir (rdb_bak) is OK" else echo "[$(date +%Y%m%d-%H:%M:%S)] the rdb file backup to local dir (rdb_bak) is error" fi rsynctime=$(date -d "-5 min" +%Y%m%d%H%M) eval rsync -avzP /home/redisInstance/"$project"/data/rdb_bak/dump.rdb [email protected]::"$project" --password-file=/etc/rsyncd.secrets if [ $? -eq 0 ] then echo "[$(date +%Y%m%d-%H:%M:%S)] the rdb file backup to remote host(10.120.117.165) dir (data) is OK" else echo "[$(date +%Y%m%d-%H:%M:%S)] the rdb file backup to remote host(10.120.117.165) dir (data) is error" fi rm -rf "$backup_dir"dump.rdb