Redis状态监控

2018年5月31日 星期四

09:52

背景

这个更简单,管理员不会做,所以得我们做。

需求

需求就对Redis进行监控,当然,这个需求说了和没说一样。

分析

既然要监控,那么就先理清监控流程,然后结合流程编写脚本就好。

监控流程

因为Redis可以多实例部署,所以要自动发现(主要是太懒所致)。

  1. 运行脚本发现Redis实例监听端口;
  2. 测试端口Redis是否正常响应,如正常则返回实例信息。
  3. 根据实例信息,添加监控项目。
  4. 监控项目通过脚本获取监控数据。

监控参数

从网上了解到的信息,Redis的监控可以分为以下2类:

  1. 状态,是否在正常运行;
  2. 性能,是否存在瓶颈;

系统资源我就不说了,默认监控着的。

Redis自带的redis-cli名有一个monitor的选项,用于实时查看系统的操作,可以Debug用。

状态指标

指标名称 说明 阈值
redis_ping Redis存活 !=1
uptime_in_days 已启动天数 <1
rdb_last_save_time 持久化时的上次保存时间 >1800
rdb_changes_since_last_save 未保存的操作数量 >1000
cluster_enabled 集群模式 !=1
cluster_info 集群状态 !=ok
cluster_slots 集群slot数量 !=16384
cluster_slots_fail 集群故障slots数量 >0
cluster_known_nodes 集群节点数量 <N(最小提供服务或者已知节点数量)。
connected_slaves 已连接的Slave数量 !=N(实际的Slave数量)
last_interaction_seconds Master和Slave上次交互后的时间 >30
link_down_since_seconds Master和Salve连接断开后的时间 >60

性能指标

指标名称 说明 阈值
connected_clients 当前连接的客户端数量 -
blocked_clients 正在等待的客户端数量 >100
rejected_connections 达到maxclient限制后拒绝的连接数量 >200
key 数据库中的键数量 -
keys_hit_rate 键空间的命中率,命中/(命中+未命中) <0.8
key_misses 查询失败的键数量 -
instantaneous_ops_per_sec 每秒执行命令数 >100000
latest_fork_usec fork阻塞时间
latency 延迟时间
used_memory 已分配的内存总量 >最大可用内存
mem_fragmentation_ratio 内存碎片百分比 >1.5
evicted_keys 被驱逐的键数量 >100

解决方案

使用说明

本地Redis,自动发现

zabbix_agentd的配置中增加如下参数:

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即可。

设置密码

使用-a参数指定密码。

支持参数

redis_info支持参数如下:

  • ping;
  • mem_utilization
  • hit_rate
  • 其他info模式支持的参数

脚本

具体脚本内容如下,请保存为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 $@

遗留问题

  1. latency的监控暂未实现,因为没有发现只让它运行5秒就结束的方式;

其他

  1. 在Redis官网上,看到一个config resetstat用于重置统计数据,可能系统需要在进行这种操作时取消告警;
  2. 根据优化依据来进行告警或者运维自动化工作是一个非常靠谱的做法;
  3. 在添加模板时,注意将结果类型调整为float
  4. 如果不使用redis-cli的全路径,会找不到路径。

参考

  1. How to Monitor Redis
  2. Monitor
  3. redis监控指标
  4. 关于redis性能问题分析和优化
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,843评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,538评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,187评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,264评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,289评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,231评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,116评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,945评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,367评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,581评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,754评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,458评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,068评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,692评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,842评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,797评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,654评论 2 354

推荐阅读更多精彩内容