2018年5月31日 星期四
09:52
背景
這個(gè)更簡(jiǎn)單,管理員不會(huì)做晶疼,所以得我們做。
需求
需求就對(duì)Redis進(jìn)行監(jiān)控又憨,當(dāng)然翠霍,這個(gè)需求說了和沒說一樣。
分析
既然要監(jiān)控蠢莺,那么就先理清監(jiān)控流程壶运,然后結(jié)合流程編寫腳本就好。
監(jiān)控流程
因?yàn)镽edis可以多實(shí)例部署浪秘,所以要自動(dòng)發(fā)現(xiàn)(主要是太懶所致)蒋情。
- 運(yùn)行腳本發(fā)現(xiàn)Redis實(shí)例監(jiān)聽端口;
- 測(cè)試端口Redis是否正常響應(yīng)耸携,如正常則返回實(shí)例信息棵癣。
- 根據(jù)實(shí)例信息,添加監(jiān)控項(xiàng)目夺衍。
- 監(jiān)控項(xiàng)目通過腳本獲取監(jiān)控?cái)?shù)據(jù)狈谊。
監(jiān)控參數(shù)
從網(wǎng)上了解到的信息,Redis的監(jiān)控可以分為以下2類:
- 狀態(tài),是否在正常運(yùn)行河劝;
- 性能壁榕,是否存在瓶頸;
系統(tǒng)資源我就不說了赎瞎,默認(rèn)監(jiān)控著的牌里。
Redis自帶的redis-cli
名有一個(gè)monitor
的選項(xiàng),用于實(shí)時(shí)查看系統(tǒng)的操作务甥,可以Debug用牡辽。
狀態(tài)指標(biāo)
指標(biāo)名稱 | 說明 | 閾值 |
---|---|---|
redis_ping | Redis存活 | !=1 |
uptime_in_days | 已啟動(dòng)天數(shù) | <1 |
rdb_last_save_time | 持久化時(shí)的上次保存時(shí)間 | >1800 |
rdb_changes_since_last_save | 未保存的操作數(shù)量 | >1000 |
cluster_enabled | 集群模式 | !=1 |
cluster_info | 集群狀態(tài) | !=ok |
cluster_slots | 集群slot數(shù)量 | !=16384 |
cluster_slots_fail | 集群故障slots數(shù)量 | >0 |
cluster_known_nodes | 集群節(jié)點(diǎn)數(shù)量 | <N(最小提供服務(wù)或者已知節(jié)點(diǎn)數(shù)量)。 |
connected_slaves | 已連接的Slave數(shù)量 | !=N(實(shí)際的Slave數(shù)量) |
last_interaction_seconds | Master和Slave上次交互后的時(shí)間 | >30 |
link_down_since_seconds | Master和Salve連接斷開后的時(shí)間 | >60 |
性能指標(biāo)
指標(biāo)名稱 | 說明 | 閾值 |
---|---|---|
connected_clients | 當(dāng)前連接的客戶端數(shù)量 | - |
blocked_clients | 正在等待的客戶端數(shù)量 | >100 |
rejected_connections | 達(dá)到maxclient限制后拒絕的連接數(shù)量 | >200 |
key | 數(shù)據(jù)庫中的鍵數(shù)量 | - |
keys_hit_rate | 鍵空間的命中率敞临,命中/(命中+未命中) | <0.8 |
key_misses | 查詢失敗的鍵數(shù)量 | - |
instantaneous_ops_per_sec | 每秒執(zhí)行命令數(shù) | >100000 |
latest_fork_usec | fork阻塞時(shí)間 | |
latency | 延遲時(shí)間 | |
used_memory | 已分配的內(nèi)存總量 | >最大可用內(nèi)存 |
mem_fragmentation_ratio | 內(nèi)存碎片百分比 | >1.5 |
evicted_keys | 被驅(qū)逐的鍵數(shù)量 | >100 |
解決方案
使用說明
本地Redis态辛,自動(dòng)發(fā)現(xiàn)
在zabbix_agentd
的配置中增加如下參數(shù):
UserParameter=redis_discovery[*], /usr/local/zabbixagent/scripts/redis_status.sh $1
UserParameter=redis_info[*], /usr/local/zabbixagent/scripts/redis_status.sh -p $1 -m info -f $2 $3
本地Redis,指定端口
直接使用redis_info
即可挺尿。
設(shè)置密碼
使用-a
參數(shù)指定密碼奏黑。
支持參數(shù)
redis_info
支持參數(shù)如下:
- ping;
- mem_utilization
- hit_rate
- 其他info模式支持的參數(shù)
腳本
具體腳本內(nèi)容如下编矾,請(qǐng)保存為redis_status.sh
攀涵。
#!/bin/bash
#
# -------------------- Copyright --------------------
# FileName: redis_status.sh
# Description: Get status of Redis.
# Version: 1.1
# Date: 2018/05/21
# Author: Rex Kang
# Email: rex.kang@qq.com
# -------------------- History --------------------
# 2018/05/21: First version
# 2018/05/31: fix bug of full path of redis-cli
# -------------------- End --------------------
CMD="/usr/local/bin/redis-cli"
fdiscover() {
json="{'data': ["
json_body=''
instances=`netstat -ntpl | grep "redis" | awk -F'[ :]+' '{print $5}'`
count=${#instances[@]}
$DEBUG && echo -e "REDIS_COUNT:\t$count"
for ((i=0; i<${count}; i++))
do
result="0"
result=`/usr/bin/redis-cli -h ${SERVER} -p ${instances[$i]} ping 2>/dev/null | grep -c PONG`
$DEBUG && echo -e "RESULT of ${instances[$i]}:\t$result"
if [ $result = "1" ]; then
json_body=${json_body}"{'{#${MACRO_VARNAME}}': '${instances[$i]}'},"
fi
done
[ -n "${json_body}" ] && json_body=${json_body%?}
$DEBUG && echo -e "\n"
echo $json${json_body}"]}"
return 0
}
finfo() {
value=0
$CLUSTER && CMD="$CMD -c"
CMD="$CMD -h $SERVER -p $PORT"
[ -n "$AUTH" ] && CMD="$CMD -a $AUTH"
if [ $FIELD = 'ping' ]; then
result=`$CMD ping 2>/dev/null 2>/dev/null | grep -c PONG`
[ -n "$result" ] && echo $result || echo 0
elif [ $FIELD = 'latency' ]; then
resutl=`$CMD --latency 2>/dev/null | awk {'print $6'} | tr -d '[:cntrl:]'`
[ -n "$result" ] && echo $result || echo 0
elif [ $FIELD = 'intrinsic-latency' ]; then
result=`$CMD --intrinsic-latency 5 2>/dev/null | grep 'avg latency' | awk {'print $6'} | tr -d '[:cntrl:]'`
[ -n "$result" ] && echo $result || echo 0
elif [ $FIELD = 'mem_utilization' ]; then
mem_total=`$CMD info | grep "^total_system_memory:" | awk -F':' '{print $2}' | tr -d '[:cntrl:]'`
mem_used=`$CMD info | grep "^used_memory:" | awk -F':' '{print $2}' | tr -d '[:cntrl:]'`
$DEBUG && echo -e "RESULT:\t\t$mem_used, $mem_total"
utilization=`echo "scale=4;$mem_used*100/$mem_total" | bc | awk '{printf("%0.2f", $0)}'`
echo $utilization
elif [ $FIELD = 'hit_rate' ]; then
hit_rate=0
hits=`$CMD info | grep "^keyspace_hits:" | awk -F':' '{print $2}' | tr -d '[:cntrl:]'`
misses=`$CMD info | grep "^keyspace_misses:" | awk -F':' '{print $2}' | tr -d '[:cntrl:]'`
$DEBUG && echo -e "RESULT:\t\t$hits + $misses"
total=`expr $hits + $misses`
if [ $total -ne 0 ]; then
hit_rate=`echo "scale=4;$hits*100/$total" | bc | awk '{printf("%0.2f", $0)}'`
fi
echo $hit_rate
else
result=`$CMD info | grep "^${FIELD}:"`
$DEBUG && echo -e "RESULT:\t$result"
$DEBUG && echo -e "CMD:\t $CMD info | grep '${FIELD}:'"
if [ -n "$result" ]; then
echo $result | awk -F':' '{print $2}'
else
echo 0
fi
fi
return 0
}
usage() {
echo -e "usage:\t$1 [-dh ][-s server] [-p port] [-a auth]"
echo -e "\t [-m discover|info] [-f field]"
echo -e "\nDiscover mode parameters:"
echo -e "-s server\t\tDefault is 127.0.0.1"
echo -e "-p port\t\tDefault is '6379"
echo -e "-a pass\t\tThe pass if configured"
echo -e "[-m discover]\t\tDefault mode is discover"
echo -e "\nInfo mode parameters:"
echo -e "-s server\t\tDefault is 127.0.0.1"
echo -e "-p port\t\tDefault is '6379"
echo -e "-a pass\t\tThe pass if configured"
echo -e "-m info\t\t\tGet info of redis"
echo -e "-f field\t\tGet info of specified field"
echo -e "\nPlease modified var CMD in this file.
return 0
}
main () {
DISCOVER=true
DEBUG=false
MACRO_VARNAME="REDIS_PORT"
SERVER="127.0.0.1"
PORT="6379"
AUTH=""
CLUSTER=false
# parameters
while getopts "s:p:a:m:f:cdh" OPT; do
case $OPT in
f)
FIELD="$OPTARG"
;;
m)
[ $OPTARG = "info" ] && DISCOVER=false
;;
s)
SERVER="$OPTARG"
;;
p)
PORT="$OPTARG"
;;
a)
AUTH="$OPTARG"
;;
c)
CLUSTER=true
;;
d)
DEBUG=true
;;
h)
usage $0
exit 0
;;
?)
usage $0
exit 1
;;
esac
done
VAR_OK=false
if $DEBUG; then
echo -e "SERVER: \t$SERVER"
echo -e "PORT: \t\t$PORT"
[ -n "$AUTH" ] && echo -e "AUTH: \t\t$AUTH" || echo -e "AUTH: \t\tFalse"
echo -e "DISCOVER: \t$DISCOVER"
echo -e "CLUSTER: \t$CLUSTER"
echo -e "FIELD: \t\t$FIELD"
echo -e "VAR_OK: \t$VAR_OK"
fi
# basic info check
if [ -n "$SERVER" ] && [ -n "$PORT" ]; then
if $DISCOVER; then
fdiscover
else
if [ -n "$FIELD" ]; then
finfo
else
echo "$0 missing parameters!"
usage
exit 2
fi
fi
else
echo "$0 missing parameters!"
usage
exit 1
fi
}
main $@
遺留問題
-
latency
的監(jiān)控暫未實(shí)現(xiàn),因?yàn)闆]有發(fā)現(xiàn)只讓它運(yùn)行5秒就結(jié)束的方式洽沟;
其他
- 在Redis官網(wǎng)上,看到一個(gè)
config resetstat
用于重置統(tǒng)計(jì)數(shù)據(jù)蜗细,可能系統(tǒng)需要在進(jìn)行這種操作時(shí)取消告警裆操; - 根據(jù)優(yōu)化依據(jù)來進(jìn)行告警或者運(yùn)維自動(dòng)化工作是一個(gè)非常靠譜的做法炉媒;
- 在添加模板時(shí)踪区,注意將結(jié)果類型調(diào)整為
float
。 - 如果不使用
redis-cli
的全路徑吊骤,會(huì)找不到路徑缎岗。