zabbix监控Memcached状态

一、安装 memcached

# yum -y installlibevent libevent-devel

#wget http://memcached.org/files/memcached-1.5.0.tar.gz

#tar -zxvf memcached-1.5.0.tar.gz

#cd memcached-1.5.0/

#./configure --with-libevent=/usr/

# make && make install

二、监控端配置

#启动memcached

#/usr/local/bin/memcached -d -m 128 -l 192.168.1.207 -p 11211 -u root



#配置zabbix-agent

# vi/etc/zabbix/zabbix_agentd.conf

PidFile=/var/run/zabbix/zabbix_agentd.pid

LogFile=/var/log/zabbix/zabbix_agentd.log

LogFileSize=0

Server=192.168.1.208

Hostname=192.168.1.207

Include=/etc/zabbix/zabbix_agentd.d/*.conf

UnsafeUserParameters=1



# vi/etc/zabbix/zabbix_agentd.d/userparameter_memcached.conf

UserParameter=memcached_stats[*],(echostats; sleep 1) | telnet 192.168.1.207 $1 2>&1 | awk '/STAT $2 / {print$NF}'



# systemctl start zabbix-agent



# Server端手动测试

#zabbix_get -s 192.168.1.207 -p 10050 -k'memcached_stats[11211,accepting_conns]'

三、WEB端配置

上传模板

模板下载地址:
http://download.csdn.net/detail/m0_37313242/9920278

未分类

Shell脚本监控并重启memcached进程

WEB服务器使用memcached,但是不知道为什么memcached老是挂掉(基本20分钟~50分钟左右),导致部分网站页面在访问的时候出错;定义日志后,查看日志也未能发现什么;初步判定由于之前更新libevent有关系。由于线上服务器,所以先用脚本来弥补下

#!/bin/sh 
pid=`ps aux|grep -v grep|grep memcached|awk '{print $2}'` 
memcached=`/usr/local/memcached/bin/memcached -u www &` 
nginx=`/usr/local/nginx/sbin/nginx -s reload &` 
if [ -z "$pid"] 
then 
echo $memcached 
echo $nginx 
fi

上面脚本主要温故2个知识点,一个是awk、一个是if的条件表达式;当然那些单引号、双引号、特殊单引号也是烦人的。只是一个基础脚本,很菜,不过可以实现我要的功能了,首先判断memcached进程是否存在,如果不存在则启动memcached和重载nginx。

最后加入到系统任务中,每隔5分钟判定一次:

*/15 * * * * /root/memcached.sh

完工!

Memcached key value数据库使用详解

简介

Memcached是一个开源、免费、高性能的分布式对象缓存系统,通过减少对数据库的读取以提高Web应用的性能;Memcached基于一个存储键/值对的hashmap。其守护进程(daemon )是用 C 写的,但是客户端可以用任何语言来编写,并通过memcached协议与守护进程通信。当某个服务器停止运行或崩溃了,所有存放在该服务器上的键/值对都将丢失。

Memcached的服务器端没有提供分布式功能,各个Memcached应用不会互相通信以共享信息。想要实现分布式通过,可以多搭建几个Memcached应用,通过算法实现此效果;

Memcached里有两个重要概念:

  • slab:为了防止内存碎片化,Memcached服务器端会预先将数据空间划分为一系列slab;举个例子,现在有一个100立方米的房间,为了合理规划这个房间放置东西,会在这个房间里放置 30 个 1 立方米的盒子、20 个 1.25 立方米的盒子、15 个 1.5 立方米的盒子…这些盒子就是slab;

  • LRU:最近最少使用算法;当同一个slat的格子满了,这时需要新加一个值时,不会考虑将这个新数据放到比当前slat更大的空闲slat,而是使用LRU移除旧数据,放入这个新数据;

部署

Memcached能够在大多数 Linux 和 类 BSD 系统上运行;官方没有给出Windows上安装Memcached的支持;

对于Debian / Ubuntu系统:

apt-get install memcached

对于Redhat / Fedora / CentOs系统:

yum install memcached

通过memcached -h查看帮助,同时也算是测试是否安装成功;
如果遇到错误,可参考官方上的FAQ;

使用

服务器端

启动一个Memcached应用,常见的启动方式是这样的:
开启一个memcached应用作守护进程,TCP连接,端口号是 11211;-u参数是运行Memcached应用的用户(这个参数也只有 root用户才能使用);

memcached -u root -p 11211 -d -vvv

其他常见的参数也有

  • -m :分配给Memcached应用使用的内存大小,默认是 64M;
  • -l :设置能访问Memcached应用的IP(默认:所有都允许;无论内外网或者本机更换IP,有安全隐患;若设置为127.0.0.1就只能本机访问);
  • -c :设置最大运行的并发连接数,默认是 1024;
  • -f :设置slat大小增长因子;默认是 1.25;比如说 10号slab大小是752,那么11号slab大小就是 752 * 1.25;

客户端

Memcached客户端与服务器端的通信比较简单,使用的基于文本的协议,而不是二进制协议;因此可以通过telnet进行交互;

telnet [host] [port]

按下Ctrl + ],并回车,即可回显;

Storage命令

set
存储数据。如果set的key已经存在,该命令可以更新该key所对应的原来的数据,也就是实现更新的作用。详细命令指南可参考菜鸟教程 – Memcached set 命令;

add
只有在set的key不存在的情况下,才会存储数据;详细命令指南可参考菜鸟教程 – Memcached add 命令;

replace
只有在set的key存在的情况下,才会替换数据;详细命令指南可参考菜鸟教程 – Memcached replace 命令;

append
向已存在的元素值后追加数据;详细命令指南可参考菜鸟教程 – Memcached append 命令;

prepend
向已存在的元素值的头部追加数据;详细命令指南可参考菜鸟教程 – Memcached prepend 命令;

cas
命令用于执行一个”检查并设置”的操作。它仅在当前客户端最后一次取值后,该key 对应的值没有被其他客户端修改的情况下,才能够将值写入。检查是通过cas_token参数进行的, 这个参数是Memcach指定给已经存在的元素的一个唯一的 64 位值。详细命令指南可参考菜鸟教程 – Memcached cas 命令;

Retrive命令

get
根据元素的键名获取值;详细命令指南可参考菜鸟教程 – Memcached get 命令;

gets
获取带有CAS令牌的数据值;详细命令指南可参考菜鸟教程 – Memcached gets 命令;

delete
删除已存在的元素;详细命令指南可参考菜鸟教程 – Memcached delete 命令;

incr/decr
对于已存在的键值进行自增或自减操作;详细命令指南可参考菜鸟教程 – Memcached incr/decr 命令;

Statistics命令

stats
查看memcached所有的统计信息;详细命令指南可参考菜鸟教程 – Memcached stats 命令;

stats items
显示各个slab中item的数目和存储时长等其它信息;详细命令指南可参考菜鸟教程 – Memcached stats items 命令;

stats slabs
显示各个slab的信息,包括chunk的大小、数目、使用情况等。详细命令指南可参考菜鸟教程 – Memcached stats slabs 命令;

stats sizes
用于显示所有item的大小和个数。该信息返回两列,第一列是 item 的大小,第二列是 item 的个数。详细命令指南可参考菜鸟教程 – Memcached stats sizes 命令;

flush_all
清除所有缓存数据;详细命令指南可参考菜鸟教程 – Memcached flush_all 命令;

分布式算法

取余算法

根据服务器节点数的余数来进行分散,就是通过hash函数求得的Key的整数哈希值再除以服务器节点数并取余数来选择服务器。这种算法取余计算简单,分散效果好,但是缺点是如果某一台机器宕机,那么应该落在该机器的请求就无法得到正确的处理,这时需要将当掉的服务器从算法从去除,此时候会有 (N-1) / N 的服务器的缓存数据需要重新进行计算;如果新增一台机器,会有N / (N+1)的服务器的缓存数据需要进行重新计算。对于系统而言,这通常是不可接受的颠簸(因为这意味着大量缓存的失效或者数据需要转移)。

【本段内容摘自大脸猫的博客】

一致性哈希

表现为一个封闭的圆环,圆环上的点分别代表0 ~ 2^32。各个memcached节点根据hash算法,分别占据圆环上的一个点,当某key进行存储操作,会针对key进行hash操作,hash后也是圆环上的一个点,那么这个key将被存储在顺时针方向的第一个节点上。

未分类

如上图:分配不均的节点,此时key将会被存储到节点C上。

此时,我们新增节点D,如下图。受影响的部分只有节点A~节点D中间的部分,这边分数据不会再映射到节点B上,而是映射到新增节点D上。减掉一个节点同理,只影响顺时针后面一个节点。

未分类

优点:动态的增删节点,服务器down机,影响的只是顺时针的下一个节点
缺点:当服务器进行hash后值较为接近会导致在圆环上分布不均匀,进而导致key的分布、服务器的压力不均匀。若中间某一权重较大的serverdown机,命中率下降明显;

在一致性哈希算法的基础上引入虚拟节点

未分类

引入虚拟节点的思想,解决一致性hash算法分布不均导致负载不均的问题。一个真实节点对应若干个虚拟节点,当key被映射到虚拟节点上时,则被认为映射到虚拟节点所对应的真实节点上。

优点:引入虚拟节点的思想,每个物理节点对应圆环上若干个虚拟节点(比如200~300个),当keyhash到虚拟节点,就会存储到实际的物理节点上,有效的实现了负载均衡;

【本段内容摘自鱼我所欲也的“memcached学习 – 分布式算法”文章】

工作中常见的问题

缓存雪崩现象

缓存雪崩一般是由某个缓存节点失效,导致其他节点的缓存命中率下降,缓存中缺失的数据去数据库查询,短时间内,造成数据库服务器崩溃;

重启DB,短期又被压垮,但缓存数据也多一些;DB反复多次启动多次,缓存重建完毕,DB才稳定运行;或者,是由于缓存周期性的失效,比如每 6 小时失效一次,那么每 6 小时,将有一个请求“峰值”,严重者甚至会令DB崩溃;

缓存的无底洞现象(multiget-hole)

该问题由 facebook 的工作人员提出的, facebook 在 2010 年左右,memcached节点就已经达3000 个.缓存数千 G 内容。

他们发现了一个问题,memcached 连接频率,效率下降了,于是加 memcached 节点,添加了后,发现因为连接频率导致的问题,仍然存在,并没有好转,称之为“无底洞现象”。

问题分析

以用户为例: user-133-age, user-133-name,user-133-height …..N 个 key,当服务器增多,133 号用户的信息,也被散落在更多的节点,所以,同样是访问个人主页,得到相同的个人信息, 节点越多,要连接的节点也越多。

对于 memcached 的连接数,并没有随着节点的增多,而降低。 于是问题出现。

multiget-hole 解决方案

把某一组key,按其共同前缀,来分布。比如 user-133-age, user-133-name,user-133-height 这 3 个 key,在用分布式算法求其节点时,应该以 ‘user-133’来计算,而不是以 user-133-age/name/height 来计算。

这样,3 个关于个人信息的 key,都落在同 1 个节点上,访问个人主页时,只需要连接 1 个节点。

永久数据被踢现象

网上有人反馈为”memcached 数据丢失”,明明设为永久有效,却莫名其妙的丢失了。

分析原因:

  • 如果 slab 里的很多 chunk,已经过期,但过期后没有被 get 过, 系统不知他们已经过期。
  • 永久数据很久没 get 了, 不活跃, 如果新增 item,则永久数据被踢了。
  • 当然,如果那些非永久数据被 get,也会被标识为 expire,从而不会再踢掉永久数据;

解决方案:永久数据和非永久数据分开放;

wordpress启用memcached加速访问

Memcached 是什么?

Memcached 是一种高性能的分布式内存对象缓存系统。在动态应用,Memcached 既能提高访问的速度,同时还减低了数据库的负载。

Danga Interactive 为提升 LiveJournal.com 的速度研发了 Memcached。目前,LiveJournal.com 每天已经在向一百万用户提供多达两千万次的页面访问。而这些,是由一个由 Web 服务器和数据库服务器组成的集群完成的。Memcached 几乎完全放弃了任何数据都从数据库读取的方式,同时,它还缩短了用户查看页面的速度、更好的资源分配方式,以及 Memcache 失效时对数据库的访问速度。

WordPress 和 Memcached

由于 WordPress 默认支持 Object Cache,所以在 WordPress 实现 Memcached 就是使用 Memcached 把 WordPress 的 Object Cache 写到内存中去,下次直接从内存中读取。相比直接从数据库去读取数据,或者从 Object Cache 数据存到文件,然后从硬盘中读取,Memcached 有很大的速度优势。

WordPress 如何启用 Memcached 缓存

  1. 需要你的服务器支持,就是你的 PHP 需要安装上 Memcached 相关的扩展,注意 PHP 有两个扩展:PHP Memcache 扩展 和 PHP Memcached 扩展,两者仅仅相差一个字母 D,你可以通过 phpinfo() 这个 PHP 函数来检测,你安装的是哪个扩展。
  2. 下载object-cache.php ,点击这里下载
  3. 把下载的:object-cache.php 复制到 wordpress的wp-content目录,这里值得注意不是 wp-content/plugins/

WordPress 会自动检查在 wp-content 目录下是否有 object-cache.php 文件,如果有,直接调用它作为 WordPress 对象缓存机制。查询数据次数明显减少

开启了之前 0.201 秒内总共 30次查询

开启之后 0.205 秒内总共 9 次查询

memcached优化方法及应用场景

memcached分布式

Memcached尽管是“分布式”的缓存系统,但服务器端并没有分布式功能。各个 Memcached不会互相通信以共享信息。分布式完全取决于客户端实现。
Memcached的分布式客户端
客户端可以通过配置SockIOPool的servers参数保存服务器地址列表,通过
weight参数配置每台服务器的权重。SockIOPool提供了连接池的服务,可以通过 SockIOPool来配置memcahce服务器相关信息,如最大连接数,最小连接数等。

一个key只能存放在一台Memcache服务器上,是不会在多个服务器上有多份拷贝的,这样的话既可以防止出现刷新不同步的情况,也可以避免磁盘空间的浪费

Memcached的分布式特点

1: 服务器端不关心分布式。

2: 依靠客户端来实现分布式 。

3: 客户端存储着可以访问到的Memcached服务器列表 。

4: 在客户端用算法来保证,对同样key值的数据,读写都操作同一个服务器。

Memcached 的调优的目标

  1. 提高内存利用率,减少内存浪费。

  2. 提高命中率。

调优方法:

  1. f参数:
    factor增长因子,默认为1.25,曾经为2,值越小,slab中chunk size差距 越小,内存浪费越小。1.25适合缓存几百字节的对象。
    建议:计算一下数据的预期平均长度,调整factor,以获得最恰当的设置。

  2. n参数:chunk初始值

  • slab尾部剩余空间
    解决办法:规划slab=chunk*n整数倍

  • slab中chunk利用率低:申请的slab只存放了一个Item
    解决办法:规划slab=chunk

  • chunk存储Item浪费
    如Item是100,存到128字节chunk,就有28字节浪费
    解决办法:规划chunk=Item

Memcached 的限制

  • 在Memcached中可以保存的item数据量是没有限制的,只要内存足够。

  • Memcached单进程最大使用内存为2G,要使用更多内存,可以分多个端口开启多
    个Memcached进程。

  • Memcached设置Item为最大30天的过期时间,设置为永久的也会在这个时间过期,
    常量REALTIME_MAXDELTA为606024*30控制。

  • Memcached本身是为缓存而设计的服务器,因此并没有过多考虑数据的永久性问
    题,当内容容量达到指定值之后,就基于LRU(Least Recently Used)算法自动删
    除不使用的缓存。

  • 最大键长为250字节,大于该长度无法存储,单个item最大数据是1MB,超过1MB数据不予存储。

Memcached 的使用目的

通过缓存数据库查询结果,减少数据库访问次

数;还有就是缓存热点数据,以提高Web应用的速度、提高可扩展性。

  1. 缓存简单的查询结果:查询缓存存储了给定查询语句对应的整个结果集,最合适
    缓存那些经常被用到,但不会改变的SQL语句对应查询到的结果集,比如载入特
    定的过滤内容。

  2. 缓存简单的基于行的查询结果。

  3. 缓存的不只是SQL数据,可以缓存常用的热点数据,比如页面,以节省CPU时间使用分层的缓存。

  4. 特别注意:当数据更新时需要更新缓存。

Memcached 的典型使用场景

  1. 分布式应用。

  2. 数据库前段缓存。

  3. 服务器间数据共享。

  4. 变化频繁,查询频繁的数据,但是不一定写入数据库,比如:用户在线状态 。

  5. 变化不频繁,查询频繁,不管是否入库,都比较适合使用。

Memcached 不适合使用Memcached的场景

1: 变化频繁, 一变化就要入库类的应用,比如股票,金融。

2: 那些不需要“分布”的,不需要共享的,或者干脆规模小到只有一台服务器的应用,
memcached不会带来任何好处,相反还会拖慢系统效率,因为网络连接同样需要资源。

3: 缓存对象的大小大于1MB。

4: key的长度大于250字符。

相关文章

Memcached 安装使用存储
http://www.jianshu.com/p/2b3c43c1778c

java 使用memcached以及spring 配置memcached
http://www.jianshu.com/p/6f264bf5d9f9

memcached优化
http://www.jianshu.com/p/789d208036f5

使用nginx ngx_http_memcached_module及memcached实现页面缓存

页面静态化是前端优化的一个重要方法,一般采用生成静态文件的方式实现。这里我尝试采用另外一种方式去实现,就是直接把页面用Memcached进行缓存,然后通过Nginx直接去访问。

采用Memcached缓存页面的好处是什么呢?

  1. 由于页面是缓存在内存里,所以减少了系统的I/O操作。
  2. 可以直接利用Memcached的分布式特性。
  3. 可以直接利用缓存的过期时间,方便对页面的过期时间进行处理。
  4. 部署简单,生成静态文件还需要考虑文件系统的问题。
    当然缺点也很明显,首先是对内存的性能依赖很大,其次由于页面直接放内存里,一旦Memcached挂掉或者服务器重启,内存里存储的页面就会全部消失。

问题来了

Nginx内置了Memcached模块ngx_http_memcached_module,可以很轻松的实现对Memcached的访问。我这里做一个示例,通过PHP缓存我们邮轮网站的首页,然后通过URLhttp://dev.hwtrip.com/cache/index.html去访问这个页面。

首先,我们对Nginx进行配置:

server {
    listen       80;
    server_name  dev.hwtrip.com;

    location ^~ /cache/ {
        set            $memcached_key $request_uri;
        memcached_pass 127.0.0.1:11211;
    }

    error_page     404 502 504 = @fallback;
}

location @fallback {
    proxy_pass     http://backend;
}

这个配置把所有请求URI前缀为/cache/的访问用Memcached模块进行内容的读取,同时使用请求URI作为Memcached的key。当缓存没有命中或者出错时,我们使用@fallback进行处理(例如访问实际的应用并重新写入缓存),这个不在这里展开了。

然后,我们用简单的代码把页面写进Memcached里:


$htmlContent = file_get_contents('http://youlun.hwtrip.com'); $memcached = new Memcache(); $memcached->addServer('127.0.0.1', 11211); $memcached->set('/cache/index.html', $htmlContent);

注意写缓存时的key,由于我们访问的URL是http://dev.hwtrip.com/cache/index.html,所以写进Memcached的key就是URI/cache/index.html。

执行完代码后,我们访问下http://dev.hwtrip.com/cache/index.html:
Nginx

可以看到,通过nginx很容易实现对Memcached进行访问,但是这离我们缓存页面的目标还差很多,因为有两个大问题还没有解决。

  • 首先,我们没有用到Memcached的分布式,我们上面的示例只是对一个Memcached的节点进行访问。
  • 其次,通过这种方式返回的页面的没有携带浏览器缓存相关的响应头。没有这些响应头,页面就不能缓存在浏览器了,会导致每次访问都会去请求服务器。

使Ngxin支持Memcached的分布式访问

Nginx可以通过upstream支持访问多个Memcached服务节点:


upstream memcached { server 127.0.0.1:11211; server 127.0.0.1:11212; server 127.0.0.1:11213; server 127.0.0.1:11214; } server { listen 80; server_name dev.hwtrip.com; location ^~ /cache/ { set $memcached_key $request_uri; memcached_pass memcached; } error_page 404 502 504 = @fallback; } ......

但是,upstream采用的是round-robin的轮询方式,而我们知道PHP的php_memcache扩展使用的是一致性哈希算法进行Memcached服务节点的选择。于是乎,我们在前端用PHP缓存的页面,通过nginx不一定能访问到。所以我们必须让Nginx也能通过一致性哈希算法去选择节点。

这里我们用到了ngx_http_upstream_consistent_hash这个第三方模块,这个模块实现了跟php_memcache这个PHP扩展一样的一致性哈希算法。

重新编译Nginx,添加好这个模块,我们修改下Nginx的配置文件的upstream部分:

upstream memcached {
    consistent_hash $request_uri;
    server 127.0.0.1:11211;
    server 127.0.0.1:11212;
    server 127.0.0.1:11213;
    server 127.0.0.1:11214;
}

......

我们修改下缓存页面的示例PHP代码:

$htmlContent = file_get_contents('http://youlun.hwtrip.com');

$memcached = new Memcache();
$memcached->addServer('127.0.0.1', 11211);
$memcached->addServer('127.0.0.1', 11212);
$memcached->addServer('127.0.0.1', 11213);
$memcached->addServer('127.0.0.1', 11214);

for ($i = 1; $i < 10; $i ++) { 
    $cacheIns->set("/cache/index$i.html", $htmlContent);
}

通过设置不同的key,我们测试下Nginx是否能获取到正确的内容。经测试,PHP设置的缓存,用Nginx都能正常访问到。

返回浏览器可缓存的页面

这是第一个例子里Nginx返回的页面的响应头:

Nginx

可以看到没有返回任何缓存相关的响应头,这样每次访问,浏览器都会去请求服务器,虽然服务器有缓存,但明显不符合我们对性能优化的追求。不过就算Nginx返回了相关的响应头,然后我们请求的时候包含了If-Modified-Since这个请求头,Ngxin的memcached模块也不会去判断这个请求有没有过期以及返回304 Not Modified。所以我们需要实现两件事,第一是能让Ngxin返回正确的响应头,第二是能让Nginx判断请求的资源是否过期,并正确返回响应码。

这里,我们借助另外一个Nginx的第三方模块:gx_http_enhanced_memcached_module。这个模块提供了很多功能,大家可以到它的github页面上了解。这里我们主要用到它的两个功能:

  • Send custom http headers, like Content-Type, Last-Modified. Http headers are stored in memcached, with your body data.
  • Reply 304 Not Modified for request with If-Modified-Since headers and content with Last-Modified in cache
    再次重新编译安装Nginx,添加好gx_http_enhanced_memcached_module模块,我们再次对Nginx的配置文件进行修改:
upstream memcached {
    consistent_hash $request_uri;
    server 127.0.0.1:11211;
    server 127.0.0.1:11212;
    server 127.0.0.1:11213;
    server 127.0.0.1:11214;
}

server {
    listen       80;
    server_name  dev.hwtrip.com;

    location ^~ /cache/ {
        set                     $enhanced_memcached_key $request_uri;
        enhanced_memcached_pass memcached;
    }

    error_page     404 502 504 = @fallback;
}

......

我们再次修改示例PHP文件:

$htmlContent = file_get_contents('http://youlun.hwtrip.com');

// 页面过期时间
$expiresTime = 60 * 5;

// Last-Modified头设置的时间
$lastModified = gmdate('D, d M Y H:i:s GMT', time());

// Expires头设置的时间
$expires = gmdate('D, d M Y H:i:s GMT', time() + $expiresTime);

// 最终缓存的内容
$cacheContent = "EXTRACT_HEADERS
Content-Type: text/html
Cache-Control:max-age=$expiresTime
Expires:$expires
Last-Modified:$lastModified

$htmlContent";

// 获取memcache实例
$memcached = new Memcache();
$memcached->addServer('127.0.0.1', 11211);
$memcached->addServer('127.0.0.1', 11212);
$memcached->addServer('127.0.0.1', 11213);
$memcached->addServer('127.0.0.1', 11214);

// 写入缓存
$memcached->set('/cache/index.html', $cacheContent, $expiresTime);

这次我们设置了缓存的过期时间,并在缓存内容前面添加了一些响应头。ngx_http_enhanced_memcached_module模块EXTRACT_HEADERS这个标记去识别并记录响应头,详情请看github页面的说明。

重新写入缓存后,我们再次访问页面:

Nginx

可以看到缓存相关的响应头都已正确返回。

后话

至此,我们已经简单的完成了使用Nginx和Memcached对缓存页面的访问,但这只是后端的简单实现,在前端还需要实现对页面缓存的管理等等的工作。

zabbix自动发现并监控本机的多memcached实例

本人在工作中一般喜欢把MySQL、Redis、Memcached、MongoDB等数据库按照实例的方式对外提供服务。一般都是一台高配的服务器上开启多个实例给每个业务使用。而监控是重中之重,我自己也尝试了多种监控方式,但对我来说感觉最简单最快的就是使用zabbix了,灵活定义key。

由于我是多实例,所以就需要用到zabbix的自动发现功能(LLD)。基本处理方式就是:

  • 1、写自动发现脚本。

  • 2、写状态取值脚本。

  • 3、添加配置文件。

  • 4、添加权限。

  • 5、配置zabbix web。

一、写自动发现脚本

$ cat /etc/zabbix/zabbix_agentd.d/scripts/memcached_discovery.py
#!/usr/bin/env python
import os
import json
t=os.popen("""sudo netstat -nltp|awk -F: '/memcached/&&/LISTEN/{print $2}'|awk '{print $1}'| grep -v grep | grep -v '^$'   """)
ports = []
for port in  t.readlines():
        r = os.path.basename(port.strip())
        ports += [{'{#MCPORT}':r}]
print json.dumps({'data':ports},sort_keys=True,indent=4,separators=(',',':'))

执行脚本看输出结果(最好使用zabbix用户执行,才能看出效果):

$ python /etc/zabbix/zabbix_agentd.d/scripts/memcached_discovery.py
{
    "data":[
        {
            "{#MCPORT}":"11211"
        },
        {
            "{#MCPORT}":"11212"
        }
}

我这个脚本中使用了sudo权限,zabbix用户在执行netstat时需要sudo权限。

二、写状态取值脚本

#!/bin/bash
#
#Auth: Pengdongwen
#Blog: www.ywnds.com
#Email: [email protected]
#Desc: memcached status monitoring 
#dependent:
#  1)yum install nc
#  2)python memcached_discovery.py
#########################

IP=127.0.0.1 
PORT="$1"
METRIC="$2"

if [ $# -lt 2 ];then
    echo "please set argument"
    exit 1
fi

STATUS=`echo "stats" | nc $IP $PORT | grep -w "$METRIC" | awk '{print $3}'`
case $METRIC in
    'version')
        echo $STATUS
        ;;
    'uptime')
        echo $STATUS 
        ;;
    'curr_connections')
        echo $STATUS
        ;;
    'total_connections')
        echo $STATUS
        ;;
    'cmd_get')
        echo $STATUS
        ;;
    'cmd_set')
        echo $STATUS
        ;;
    'get_hits')
        echo $STATUS
        ;;
    'get_misses')
        echo $STATUS
        ;;
    'bytes_read')
        echo $STATUS
        ;;
    'bytes_written')
        echo $STATUS
        ;;
    'curr_items')
        echo $STATUS
        ;;
    'total_items')
        echo $STATUS
        ;;
    'expired_unfetched')
        echo $STATUS
        ;;
    'evicted_unfetched')
        echo $STATUS
        ;;
    *)
        echo "Not selected metric"
        exit 0
        ;;
esac

脚本很简单,需要传给脚本两个参数,一个是端口号,另一个是监控值。

有几个特别需要说明的就是:

  • 1)这个脚本不支持redis加密。

  • 2)需要指定redis-cli的绝对路径。

  • 3)需要安装dos2unix工具(yum install dos2unix)。

三、添加配置文件

$ cat /etc/zabbix/zabbix_agentd.d/userparameter_memcached.conf
UserParameter=memcached.discovery[*],python /etc/zabbix/zabbix_agentd.d/scripts/memcached_discovery.py
UserParameter=memcached[*],/bin/bash /etc/zabbix/zabbix_agentd.d/scripts/memcached_status.sh $1 $2

这里定义三个key,第一个key是用于自动发现的。第二个key是用于取不同实例的状态值的,传了两个参数,$1是端口号(从自动发现中获取的),第二个是传的参数。端口号和参数我会在zabbix页面配置传给memcached[*]这个key。

都配置完后就可以添加重启一下zabbix-agent了。

$ service zabbix-agent restart

四、添加权限

需要给zabbix用户添加sudo权限。

$ cat /etc/sudoers.d/zabbix
Defaults:zabbix    !requiretty
zabbix ALL=(ALL) NOPASSWD: SUPERVISORCTLZB
Cmnd_Alias SUPERVISORCTLZB = /sbin/ss,/usr/sbin/ss,/sbin/dmidecode,/usr/sbin/dmidecode,/sbin/service,/usr/sbin/service,/bin/netstat

另外需要注意的是,普通用户zabbix默认环境变量有如下这些:

$ echo $PATH
/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin

所以你要确认你所有的执行程序都在这些路径下,不然zabbix是获取不到值的。

使用zabbix用户执行看是否正常。

$ sudo -u zabbix `which zabbix_agentd` -t redis.discovery[*]
{
    "data":[
        {
            "{#MCPORT}":"11211"
        },
        {
            "{#MCPORT}":"11212"
        }
}

五、配置zabbix web

前期工作都做完了,下面就可以配置zabbix web了。

首先创建一个模板(Template Linux Memcached Discovery),然后在模板中创建一个自动发现规则(Linux Memcached Discovery)。

监控

在这个自动发现规则内创建一个item。

监控

然后可以创建trigger等。

下面我提供一个模板Github:https://github.com/dongwenpeng/zabbix

Zabbix监控Memcached PHP-FPM Tomcat Nginx MySQL 网站日志

Zabbix作为监控软件非常的灵活,支持的数据类型非常丰富,比如数字(无正负),数字(浮点),日志,文字等。我们需要做的就是使用脚本来收集好数据,然后zabbix收集并画图,设置告警线。这里我们来学习使用Zabbix监控Memcached、PHP-FPM、Tomcat、Nginx、MySQL及网站日志。

 

Memcached监控

 

自定义键值

 

  1. UserParameter=memcached.stat[*],/data/sh/memcached-status.sh "$1"

memcached-status.sh脚本内容为:

  1. #!/bin/bash
  2.  
  3. item=$1
  4. ip=127.0.0.1
  5. port=11211
  6. (echo "stats";sleep 0.5) | telnet $ip $port 2>/dev/null | grep "STAT $itemb" | awk ‘{print $3}’

 

导入模板

 

memcached zabbix模板下载

 

PHP-FPM监控

 

配置php-fpm状态页

 

打开php-fpm.conf配置文件,添加如下配置后重启php:

  1. pm.status_path = /fpm_status

 

自定义键值

 

  1. UserParameter=php-fpm[*],/data/sh/php-fpm-status.sh "$1"

php-fpm-status.sh脚本内容:

  1. #!/bin/bash
  2. ##################################
  3. # Zabbix monitoring script
  4. #
  5. # php-fpm:
  6. #  – anything available via FPM status page
  7. #
  8. ##################################
  9. # Contact:
  10. [email protected]
  11. ##################################
  12. # ChangeLog:
  13. #  20100922        VV        initial creation
  14. ##################################
  15.  
  16. # Zabbix requested parameter
  17. ZBX_REQ_DATA="$1"
  18.  
  19. # FPM defaults
  20. URL="http://localhost/fpm_status"
  21. WGET_BIN="/usr/bin/wget"
  22.  
  23. #
  24. # Error handling:
  25. #  – need to be displayable in Zabbix (avoid NOT_SUPPORTED)
  26. #  – items need to be of type "float" (allow negative + float)
  27. #
  28. ERROR_NO_ACCESS_FILE="-0.9900"
  29. ERROR_NO_ACCESS="-0.9901"
  30. ERROR_WRONG_PARAM="-0.9902"
  31. ERROR_DATA="-0.9903" # either can not connect /        bad host / bad port
  32.  
  33. # save the FPM stats in a variable for future parsing
  34. FPM_STATS=$($WGET_BIN -q $URL -O – 2> /dev/null)
  35.  
  36. # error during retrieve
  37. if [ $? -ne 0 -o -z "$FPM_STATS" ]; then
  38.   echo $ERROR_DATA
  39.   exit 1
  40. fi
  41.  
  42. #
  43. # Extract data from FPM stats
  44. #
  45. RESULT=$(echo "$FPM_STATS" | sed -n -r "s/^$ZBX_REQ_DATA: +([0-9]+)/1/p")
  46. if [ $? -ne 0 -o -z "$RESULT" ]; then
  47.     echo $ERROR_WRONG_PARAM
  48.     exit 1
  49. fi
  50.  
  51. echo $RESULT
  52.  
  53. exit 0

 

导入模板

 

php-fpm zabbix模板下载

 

Tomcat监控

 

刚开始决定监控Tomcat时,使用的是JMX,不过这货设置太复杂了,而且对防火墙要求还挺高,需要开放几个端口。只好使用Tomcat自带的状态页来监控了。

 

自定义键值

 

  1. UserParameter=tomcat.status[*],/data/sh/tomcat-status.py $1

因为需要解析到xml,所以还是决定用python实现比较方便。
/data/sh/tomcat-status.py脚本内容:

  1. #!/usr/bin/python
  2. import urllib2
  3. import xml.dom.minidom
  4. import sys
  5.  
  6. url = ‘http://127.0.0.1:8080/manager/status?XML=true’
  7. username = ‘username’
  8. password = ‘password’
  9.  
  10. passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
  11. passman.add_password(None, url, username, password)
  12. authhandler = urllib2.HTTPBasicAuthHandler(passman)
  13. opener = urllib2.build_opener(authhandler)
  14. urllib2.install_opener(opener)
  15. pagehandle = urllib2.urlopen(url)
  16. xmlData = pagehandle.read()
  17. doc = xml.dom.minidom.parseString(xmlData) 
  18.  
  19. item = sys.argv[1]
  20.  
  21. if item == "memory.free":
  22. print  doc.getElementsByTagName("memory")[0].getAttribute("free")
  23. elif item == "memory.total":
  24. print  doc.getElementsByTagName("memory")[0].getAttribute("total")
  25. elif item == "memory.max":
  26. print  doc.getElementsByTagName("memory")[0].getAttribute("max")
  27. elif item == "threadInfo.maxThreads":
  28. print  doc.getElementsByTagName("threadInfo")[0].getAttribute("maxThreads")
  29. elif item == "threadInfo.currentThreadCount":
  30. print  doc.getElementsByTagName("threadInfo")[0].getAttribute("currentThreadCount")
  31. elif item == "threadInfo.currentThreadsBusy":
  32. print  doc.getElementsByTagName("threadInfo")[0].getAttribute("currentThreadsBusy")
  33. elif item == "requestInfo.maxTime":
  34. print  doc.getElementsByTagName("requestInfo")[0].getAttribute("maxTime")
  35. elif item == "requestInfo.processingTime":
  36. print  doc.getElementsByTagName("requestInfo")[0].getAttribute("processingTime")
  37. elif item == "requestInfo.requestCount":
  38. print  doc.getElementsByTagName("requestInfo")[0].getAttribute("requestCount")
  39. elif item == "requestInfo.errorCount":
  40. print  doc.getElementsByTagName("requestInfo")[0].getAttribute("errorCount")
  41. elif item == "requestInfo.bytesReceived":
  42. print  doc.getElementsByTagName("requestInfo")[0].getAttribute("bytesReceived")
  43. elif item == "requestInfo.bytesSent":
  44. print  doc.getElementsByTagName("requestInfo")[0].getAttribute("bytesSent")
  45. else:
  46. print "unsupport item."

这个脚本是监控Tomcat7的,Tomcat6没有试过,应该区别在状态页的url以及管理页面的用户密码设置上。以上脚本可运行需要在tomcat-users.xml里添加用户,至少权限为manager-status。

 

导入模板

 

tomcat zabbix模板下载

 

Nginx监控

 

配置Nginx状态页

 

在nginx配置文件server{}中加入:

  1. location /nginx_status {
  2.     stub_status on;
  3.     access_log off;
  4. }

 

自定义键值

 

  1. UserParameter=nginx[*],/data/sh/nginx-status.sh "$1"

nginx-status.sh脚本内容:

  1. #!/bin/bash
  2. ##################################
  3. # Zabbix monitoring script
  4. #
  5. # nginx:
  6. #  – anything available via nginx stub-status module
  7. #
  8. ##################################
  9. # Contact:
  10. [email protected]
  11. ##################################
  12. # ChangeLog:
  13. #  20100922        VV        initial creation
  14. ##################################
  15.  
  16. # Zabbix requested parameter
  17. ZBX_REQ_DATA="$1"
  18. ZBX_REQ_DATA_URL="$2"
  19.  
  20. # Nginx defaults
  21. URL="http://127.0.0.1/nginx_status"
  22. WGET_BIN="/usr/bin/wget"
  23.  
  24. #
  25. # Error handling:
  26. #  – need to be displayable in Zabbix (avoid NOT_SUPPORTED)
  27. #  – items need to be of type "float" (allow negative + float)
  28. #
  29. ERROR_NO_ACCESS_FILE="-0.9900"
  30. ERROR_NO_ACCESS="-0.9901"
  31. ERROR_WRONG_PARAM="-0.9902"
  32. ERROR_DATA="-0.9903" # either can not connect /        bad host / bad port
  33.  
  34. # save the nginx stats in a variable for future parsing
  35. NGINX_STATS=$($WGET_BIN -q $URL -O – 2> /dev/null)
  36.  
  37. # error during retrieve
  38. if [ $? -ne 0 -o -z "$NGINX_STATS" ]; then
  39.   echo $ERROR_DATA
  40.   exit 1
  41. fi
  42.  
  43. #
  44. # Extract data from nginx stats
  45. #
  46. case $ZBX_REQ_DATA in
  47.   active_connections)   echo "$NGINX_STATS" | head -1             | cut -f3 -d’ ‘;;
  48.   accepted_connections) echo "$NGINX_STATS" | grep -Ev ‘[a-zA-Z]’ | cut -f2 -d’ ‘;;
  49.   handled_connections)  echo "$NGINX_STATS" | grep -Ev ‘[a-zA-Z]’ | cut -f3 -d’ ‘;;
  50.   handled_requests)     echo "$NGINX_STATS" | grep -Ev ‘[a-zA-Z]’ | cut -f4 -d’ ‘;;
  51.   reading)              echo "$NGINX_STATS" | tail -1             | cut -f2 -d’ ‘;;
  52.   writing)              echo "$NGINX_STATS" | tail -1             | cut -f4 -d’ ‘;;
  53.   waiting)              echo "$NGINX_STATS" | tail -1             | cut -f6 -d’ ‘;;
  54.   *) echo $ERROR_WRONG_PARAM; exit 1;;
  55. esac
  56.  
  57. exit 0

 

导入模板

 

nginx zabbix模板下载

 

MySQL监控

 

MySQL的监控,zabbix是默认支持的,已经有现成的模板,现成的键值,我们需要做的只是在/var/lib/zabbix里新建一个.my.cnf文件,内容如下:

  1. [client]
  2. host=127.0.0.1
  3. port=1036
  4. user=root
  5. password=root

 

网站日志监控

 

配置日志格式

 

我们假设你用的web服务器是Nginx,我们添加一个日志格式,如下:

  1. log_format withHost  ‘$remote_addrt$remote_usert$time_localt$hostt$requestt’
  2.                 ‘$statust$body_bytes_sentt$http_referert’
  3.                 ‘$http_user_agent’;

我们使用tab作分隔符,为了方便awk识别列的内容,以防出错。
然后再设置全局的日志,其它server就不需要设置日志了:

  1. access_log  /data/home/logs/nginx/$host.log withHost;

 

定时获取一分钟日志

 

设置一个定时任务:

  1. * * * * * /data/sh/get_nginx_access.sh

脚本内容为:

  1. #!/bin/bash
  2.  
  3. logDir=/data/home/logs/nginx/
  4. logNames=`ls ${logDir}/*.*.log  |awk -F"/" ‘{print $NF}’`
  5.  
  6. for $logName in $logNames;
  7. do
  8. #设置变量
  9. split_log="/tmp/split_$logName"
  10. access_log="${logDir}/$logName"
  11. status_log="/tmp/$logName"
  12.  
  13. #取出最近一分钟日志
  14. tac $access_log  | awk ‘
  15. BEGIN{
  16. FS="t"
  17. OFS="t"
  18. cmd="date -d "1 minute ago" +%H%M%S"
  19. cmd|getline oneMinuteAgo
  20. }
  21. {
  22. $3 = substr($3,13,8)
  23. gsub(":","",$3)
  24. if ($3>=oneMinuteAgo){
  25. print
  26. } else {
  27. exit;
  28. }
  29. }’ > $split_log
  30.  
  31.  
  32. #统计状态码个数
  33. awk -F’t’ ‘{
  34. status[$4" "$6]++
  35. }
  36. END{
  37. for (i in status)
  38. {
  39. print i,status[i]
  40. }
  41. }
  42. ‘ $split_log  > $status_log
  43. done

这个定时任务是每分钟执行,因为我们监控的频率是每分钟。添加这个任务是为了取得最近一分钟各域名的日志,以及统计各域名的所有状态码个数,方便zabbix来获取所需的数据。

 

自定义键值

 

  1. UserParameter=nginx.detect,/data/sh/nginx-detect.sh
  2. UserParameter=nginx.access[*],awk -v sum=0 -v domain=$1 -v code=$2 ‘{if($$1 == domain && $$2 == code ){sum+=$$3} }END{print sum}’ /tmp/$1.log
  3. UserParameter=nginx.log[*],awk -F’t’ -v domain=$1 -v code=$2 -v number=$3 -v sum=0 -v line="" ‘{if ($$4 == domain && $$6 == code ){sum++;line=line$$5"n" }}END{if (sum > number) print line}’ /tmp/split_$1.log | sort | uniq -c | sort -nr | head -10 | sed -e ‘s/^/<p>/’ -e ‘s/$/</p>/’

nginx-detect.sh脚本内容为:

  1. #!/bin/bash
  2.  
  3. function json_head {
  4.     printf "{"
  5.     printf ""data":["
  6. }
  7.  
  8. function json_end {
  9.     printf "]"
  10.     printf "}"
  11. }
  12.  
  13. function check_first_element {
  14.     if [[ $FIRST_ELEMENT -ne 1 ]]; then
  15.         printf ","
  16.     fi
  17.     FIRST_ELEMENT=0
  18. }
  19.  
  20. FIRST_ELEMENT=1
  21. json_head
  22.  
  23. logNames=`ls /data/home/logs/nginx/*.*.log |awk -F"/" ‘{print $NF}’`
  24. for logName in $logNames;
  25. do
  26. while read domain code count;do
  27.         check_first_element
  28.         printf "{"
  29.         printf ""{#DOMAIN}":"$domain","{#CODE}":"$code""
  30.         printf "}"
  31. done < /tmp/$logName
  32. done
  33. json_end

这里我们定义了三个键值,nginx.detect是为了发现所有域名及其所有状态码,nginx.access[*]是为了统计指定域名的状态码的数量,nginx.log[*]是为了测试指定域名的状态码超过指定值时输出排在前十的url。我们监控nginx访问日志用到了zabbix的自动发现功能,当我们增加域名时,不需要修改脚本,zabbix会帮助我们自动发现新增的域名并作监控。

 

配置探索规则

 

添加一个探索规则,用来发现域名及状态码,如图:
监控

 

配置监控项原型

 

监控所有的域名及状态码:
监控
域名状态码404超过200次监控:
监控
域名状态码500超过50次监控:
监控

 

配置触发器

 

404状态码超过200告警:
监控

监控
500状态码超过50告警:
监控

wordpress启用memcached

wordpress启用memcached需要环境符合两个条件,1,安装了php-memcached扩展,2,安装了memcached
1、启用方法很简单,如果你的memcached启用的是默认端口11211,则只需要下载object-cache.php文件到wp-content目录即可。
2、如果端口不是11211或者需要配置多台memcached,则需要修改wp-config.php文件,在文件中加入下面代码。

  1. global $memcached_servers;
  2. $memcached_servers = array(‘default’ => array(‘127.0.0.1:11211′,’192.168.1.101:11211’)); // 这里是你的 memcached 地址和端口
  3. global $blog_id;
  4. $blog_id = ‘centos_blog’; // 这里是用于区分服务器上有多个 wordpress 而避免使用同一内存缓存

CentOS安装mysql分布式缓存服务器memcached

Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提供动态、数据库驱动网站的速度。下面我们来一步步安装memcached。
1、首先为PHP安装扩展memcache。参考如下教程。
http://devops.webres.wang/2011/11/linux-install-php-memcache/
2、安装libevent

  1. yum -y install libevent-devel

3、下载memcached

  1. wget -c http://memcached.googlecode.com/files/memcached-1.4.9.tar.gz
  2. tar xzf memcached-1.4.9.tar.gz
  3. cd memcached-1.4.9

4、开始编译安装memcached

  1. ./configure –prefix=/usr/local/memcached
  2. make
  3. make install

5、配置memcached
1)下载启动脚本

  1. wget http://devops.webres.wang/wp-content/uploads/2011/11/memcached -O /etc/init.d/memcached
  2. chmod +x /etc/init.d/memcached

2)创建文件/usr/local/memcached/memcached.conf,并写入以下代码。

  1. PORT="11211"
  2. USER="memcached"
  3. MAXCONN="2048"
  4. CACHESIZE="64"
  5. OPTIONS=""

PORT=”11211″:指定端口为11211
USER=”memcached”:以memcached用户运行
MAXCONN=”2048″:最大连接数
CACHESIZE=”64″:设置缓存内存为64M
3)建立用户memcached,加入启动项,并启动memcached

  1. groupadd memcached
  2. useradd -g memcached memcached
  3. chkconfig –add memcached
  4. chkconfig memcached on
  5. service memcached start