一 应用场景描述

   目前上线的一款游戏后端游戏数据全部存入Redis数据库中,Redis是一种单线程的数据库,所以在多CPU核心的服务器上可以运行多个Redis实例,只要内存充足就行。我们部署的时候是每个游戏区服使用一个Redis实例,占用一个端口。如一区使用6501,二区使用6502.由于每台服务器上的Redis数量和端口不固定,所以不能使用常规的固定端口监控,需要使用到zabbix的自动发现功能先检测到一台服务器上的Redis端口,然后再通过Redis自带的命令INFO获取Redis当前的状态,比如内存使用量,当前处理的连接数等信息。

二 Redis监控参数

   关于Redis INFO命令详细使用信息可以参考 http://redis.io/commands/info 。

   直接使用INFO命令,将显示Redis实例的所有相关信息, 还可以使用INFO Server这样的形式,显示当个部分的信息。

$ redis-cli -p 6501 INFO|grep '^#'

# Server                      

# Clients

# Memory

# Persistence

# Stats

# Replication

# CPU

# Keyspace

比较重要的几个参数如下:

used_memory  Redis分配的内存。

Redis使用内存分配器mem_allocator分配用于存储用户数据和其他一些中间数据的内存,这里分配的内存不包括一些由于内存碎片消耗的内存,所以这里的内存大小总是和操作系统分配给Redis的内存大小不同。

Redis的内存使用情况是影响Redis性能的一个很重要的因素,如果used_memroy的值大于物理内存,那么Redis将会使用swap分区将一些旧的内存页面写入到磁盘,这将会影响依靠Redis的服务。还需要注意的是,如果开启了Redis的快照功能,即RDB持久化方式,那么Redis将通过fork方式把全部的数据在内存中复制一次用于写入磁盘生成RDB文件。当不使用快照的时候,当used_memory可以达到可用内存的95%左右,如果使用快照的话,used_memory只能达到可用内存的45%左右。可以在redis.conf文件中设置maxmemory和maxmemory-policy来设置Redis实例能够使用的最大内存和当内存使用达到最大时对老的keys的过期处理策略。根据是否使用快照持久化方式,maxmemory可以设置的值为可用内存的45%或95%,需要注意的是如果一台服务器上有多个Redis实例,每个maxmeory的值要根据情况设定。


total_commands_processed  Redis实例处理的总的命令数量


connected_clients   连接到Redis实例的客户端数量

默认情况下,允许连接到Redis实例的客户端数量是10000,由于Redis是单线程,所以连接到同一个Redis实例的客户端数量越多,每个客户端等待Redis实例处理的时间就越长,就会影响Redis的性能

可以通过再redis.conf中设置maxclients 10000,也可以redis-cli设置config set maxclients 10000.


mem_fragmentation_ratio  显示操作系统分配给Redis实例的内存(used_memory_rss)和Redis实例通过内存分配器(mem-allocator)分配的内存(used_memory)的比率

                                           used_memory_rss

                mem_fragmentation_ratio = --------------------

                                           used_memory


used_memory 和 used_memory_rss 都包括两个部分 User-defined data 和 Internal overhead。即包括用于存储用户自定义数据的内存和Redis内部消耗的内存。

RSS 代表Resident Set Size,是操作系统为Redis实例分配的物理内存,除了User-defined data和Internal overhead,used_memory_rss 还包括操作系统分配内存给Redis实例时产生的内存碎片。


对于追踪Redis实例的性能,mem_fragmentation_ratio  是一个非常重要的参考指标。 这个值需要稍微大于1,表示较低的内存碎片和没有内存交换。如果这个值大于1.5,则表示操作系统产生了明显的内存碎片,Redis实例实际消耗了它需要内存的150%,如果这个值小于1,则Redis内存分配超过了可用物理内存,操作系统开始使用swap分区。

如果mem_fragmentation_ratio 的值在1到1.5,那么要么是操作系统或是Redis实例管理内存不当。可以通过以下几种方法

  1. 重新启动Redis实例。重新启动Redis实例之前最好做下save操作,将数据保存到磁盘。

  2. 限制内存交换。内存交换会严重影响Redis的性能。

  3. 更换内存分配器(glibc's maclloc, tcmalloc,jemalloc)。


三 Zabbix Low-level Discovery功能

对于一些非固定项目的监控,如一台服务器上的分区大小,一台服务器上的多个Redis实例监控,一台服务器上的多个MySQL实例监控,这些监控需求特别适合使用Zabbix的Low-level Discovery功能来监控,先发现一台服务器上有多个分区,有多少个Redis实例,有多少个MySQL实例,然后再针对每个分区或实例进行监控。可以参考官方文档https://www.zabbix.com/documentation/2.2/manual/discovery/low_level_discovery

进行详细了解。

创建Low-level Discovery的大体流程是这样的

Configuration --> Template --> Discovery --> Create discovery rule --> Create item prototype --> Create trigger prototype --> Create graph prototype

从zabbix 2.0以后默认支持net.if.discovery和vfs.fs.discovery两个自动发现item

$ /usr/local/zabbix/bin/zabbix_get -s 192.168.1.187 -k "net.if.discovery"
{
	"data":[
		{
			"{#IFNAME}":"lo"},
		{
			"{#IFNAME}":"eth0"},
		{
			"{#IFNAME}":"eth1"}]}


zabbix agent返回的内容应该是JSON格式的,并包含特定的宏->值。

{#IFNAME}就是需要定义的宏,这个用于后面添加item,trigger,graph等

宏定义名称可以包含0-9,A-Z,-,. 不允许包含小写字母


四 Zabbix自动发现Redis

参考文章

http://blog.cunss.com/?p=139

http://dl528888.blog.51cto.com/2382721/1366309

本文主要参考了以上两篇文章的内容,并作了一些修改。


第一步需要编写Redis端口发现的脚本,然后再编写获取Redis数据的脚本。


Redis发现端口脚本redis_port.py

#/usr/bin/python
#This script is used to discovery redis port on the server
import subprocess
import json
args="netstat -tanp|awk -F':' '/redis-server/&&/LISTEN/{print $2}'|awk '{print $1}'"
t=subprocess.Popen(args,shell=True,stdout=subprocess.PIPE).communicate()[0]
ports=[]

for port in t.split('\n'):
    if len(port) != 0:
       ports.append({'{#REDISPORT}':port})
print json.dumps({'data':ports},indent=4,separators=(',',':'))

这里对原作者的脚本作了下修改,从Python2.4以后subporcess用来替代os.popen
默认情况下netstat只能以root方式执行,所以需要让zabbix运行的用户也能够有权限执行netstat操作


chmod a+s /bin/netstat


获取Redis数据的脚本redis_stats.sh

#!/bin/bash
METRIC="$1"
HOSTNAME=127.0.0.1
PORT="${2:-6379}"
CACHE_FILE="/tmp/redis_$PORT.cache"

    (echo -en "INFO\r\n"; sleep 1;) | nc $HOSTNAME $PORT > $CACHE_FILE 2>/dev/null || exit 1

grep "^$METRIC:" $CACHE_FILE |awk -F':' '{print $2}'

这里也将原作者的脚本作了下修改。


编辑zabbix_agentd.conf添加

UnsafeUserParameters=1

Include=/usr/local/zabbix/etc/zabbix_agentd.conf.d/


编辑/usr/local/zabbix/etc/zabbix_agentd.conf.d/redis_status.conf

### Option: UserParameter
#       User-defined parameter to monitor. There can be several user-defined parameters.
#       Format: UserParameter=<key>,<shell command>
#       See 'zabbix_agentd' directory for examples.
#
# Mandatory: no
# Default:
# UserParameter=
UserParameter=redis.discovery,/usr/bin/python /usr/local/zabbix/bin/redis_port.py
UserParameter=redis[*],/usr/local/zabbix/bin/redis_stats.sh $1 $2


重新启动zabbix-agent,在zabbix server或zabbix porxy上通过zabbix-get检测是否能够获取redis数据

$  /usr/local/zabbix/bin/zabbix_get -p 10055 -s 192.168.1.187  -k redis.discovery
{
    "data":[
        {
            "{#REDISPORT}":"6801"
        },
        {
            "{#REDISPORT}":"6400"
        },
        {
            "{#REDISPORT}":"6501"
        },
        {
            "{#REDISPORT}":"6410"
        }
    ]
}


$ /usr/local/zabbix/bin/zabbix_get -p 10055 -s 192.168.1.187  -k redis[used_memory,6501]
350356552



wKioL1PLT8uTM5ixAAIncblm5TI648.jpg

wKiom1PLTrOTEodKAAduI_f9wWI723.jpg

wKioL1PLT86QjJV3AALFwVc08QY763.jpg

wKiom1PLTrSBaqIAAAPQX6NUQ2Q644.jpg

wKioL1PLT8_hLVopAAPLKUZ65WQ968.jpg

wKiom1PLTrWSalsEAAPi0Kg2kB0916.jpg