监控
NinGoo's blog

使用jpgraph绘制数据库监控图形

对于数据库的监控,可以分成两种类型,一种是实时的错误告警,需要尽快将一些错误信息发送给相关责任人,这更多的属于救火的性质。另外一种就是关键指标历史趋势的展示和分析,可以帮助DBA更加直观的发现数据库的指标的异常波动,提前发现问题。

市面上有不少商品的数据库监控产品,数据库厂商们也在不遗余力的推广自己的解决方案,其中不乏优秀的东西,不过能做到多产品兼容、可扩展伸缩和高度可定制的产品就凤毛麟角了。所以很多公司会自己开发一些数据库监控产品,不求大而全,只要能满足自己的业务需求就足矣。

对于自己开发的轻量级监控产品,使用LAMP等开源产品是比较合适的。数据的抽取和告警的发送,可以使用shell或者perl,几个简单的脚本就可以实现,放在crontab里定期跑跑就行,监控数据库使用MySQL存放,如果需要实现高可用的监控,考虑一下冗余,MySQL可以使用Master-Master Replication。而展示可以使用php等搭建一个简单的web网站,成本不高,效率很高。

对于历史趋势的展示,图形绘制是必须的,一图胜千言。如果使用的是PHP,jpgraph或者是pChart都是不错的选择。相对而言,jpgraph的文档和开发都还在不断的丰富,最新版本3.0.6发布于2009-10-10,而pChart的最新版本则是2008-10-06发布的1.27d,因此建议使用jpgraph。如果使用java来架构监控网站,则anysqlDataReport是值得推荐的一款产品,简单易上手,功能很强大很邪恶。

扯的有点远了,回到这篇文章的标题。jpgraph只是一个图形绘制的库,如果需要比较方便的用于数据库监控中,最好在上面再封装一层,以实现根据SQL语句查询的结果集自动绘制图形,这样可以更方便的做到批量化的增加关键指标的图形展示。另外,jpgraph对于中文的支持,因为使用了truetype字体的关系,有一点点复杂,需要从windows复制c:\windows\fonts\simsun.ttc和c:\windows\fonts\simhei.ttc到linux的/usr/share/fonts/truetype目录。jpgraph默认会将所有的中文转化成UTF8字符,如果数据库和web使用的是gb2312,则这个转化会导致乱码,解决办法是修改jpgraph_ttf.inc.php,注释掉转化部分的代码:

     /*   elseif( $aFF === FF_SIMSUN ) {
            // Do Chinese conversion
            if( $this->g2312 == null ) {
                include_once 'jpgraph_gb2312.php' ;
                $this->g2312 = new GB2312toUTF8();
            }
            return $this->g2312->gb2utf8($aTxt);
        }*/

绘制图形时,在需要使用中文的地方,显式的调用字体设置函数,将字体设置为simsun,即可正确的显示中文:

$graph->title->SetFont(FF_SIMSUN,FS_BOLD);
$graph->title->Set("中文测试");

最后,贴两张用jpgraph绘制的Oracle数据库监控效果图:
sql_executions

sequential_reads

使用Oracle正则表达式监控应用到数据库的连接情况

Oracle从10g开始支持正则表达式,在一些特殊的应用场景下,可以发挥超乎想象的便利。

通过v$session,可以监控应用服务器到数据库的连接的情况。假设应用服务器的名字都是有规律的,典型的如字母+数字+.+后缀的格式,例如app123.idc1表示位于idc1机房的app应用的123机器。当然,机器名的规则要根据具体的场景来分析得出,本文以上述规则来演示如何利用正则表达式来得到每组不同的应用服务器到数据库的连接情况。

对于数据库来说,可能有多组不同的应用服务器需要连接。典型的监控指标可以包括:每组应用服务器的机器数,每组应用服务器当前总的连接数,每组应用服务器中单台最大的连接数,每组应用服务器中单台最少的连接数。通过如下的sql语句,使用正则表达式,可以轻松获取上述四个指标:

select b.machine,
         count(*) machine_nums,
         b.cnt total_sessions,
         max(a.cnt) max_sessions,
         min(a.cnt) min_sessions
from
    (select machine,count(*) cnt
       from v$session
      group by machine) a,
    (select regexp_replace(regexp_replace(machine,'[0-9]','#'),'#+','#') machine,
            count(*) cnt
       from v$session
      group by  regexp_replace(regexp_replace(machine,'[0-9]','#'),'#+','#')
     ) b
where regexp_replace(regexp_replace(a.machine,'[0-9]','#'),'#+','#')=b.machine
group by b.machine,b.cnt
MACHINE        MACHINE_NUMS TOTAL_SESSIONS MAX_SESSIONS MIN_SESSIONS
--------------- ----------- -------------- ------------ ------------
db#.idc#                  1            22            22           22
test#.idc#                2            10             5            5
appa#.idc#               30           166            10            5
appb#.idc#               17            18             2            1

上面的sql中,使用了正则表达式函数REGEXP_REPLACE将数字替换成#,以方便对同组应用的机器进行分组统计。只要根据相应的规则进行修改,就可以适用到不同的场景。然后利用该sql固定时间如五分钟来采集数据,就可以得到趋势展示,绘成图形,直观的分析应用服务器到数据库的连接情况。

如何监控MemCached的状态

使用MemCached以后,肯定希望知道cache的效果,对于MemCached的一些运行状态进行监控是必要的。MemCached也提供了stats接口输出一些信息,最简单的方式,就是telnet上去输入stats查看:

telnet 127.0.0.1 11211
Trying 127.0.0.1 ...
Connected to memcache_test_host (127.0.0.1 ).
Escape character is '^]'.
stats
STAT pid 7186
STAT uptime 1695
STAT time 1238401344
STAT version 1.2.6
STAT pointer_size 64
STAT rusage_user 0.003999
STAT rusage_system 0.002999
STAT curr_items 1
STAT total_items 54
STAT bytes 135
STAT curr_connections 2
STAT total_connections 111
STAT connection_structures 4
STAT cmd_get 3
STAT cmd_set 54
STAT get_hits 0
STAT get_misses 3
STAT evictions 0
STAT bytes_read 5957
STAT bytes_written 50914
STAT limit_maxbytes 2147483648
STAT threads 1
END

这种方式相当的不方便,所以网上就有各种不同客户端接口写的工具,比如用perl写的这个memcache-tool

./memcached_tool
Usage: memcached-tool  [mode]

       memcached-tool 10.0.0.5:11211 display    # shows slabs
       memcached-tool 10.0.0.5:11211            # same.  (default is display)
       memcached-tool 10.0.0.5:11211 stats      # shows general stats
       memcached-tool 10.0.0.5:11211 move 7 9   # takes 1MB slab from class #7
                                                # to class #9.

You can only move slabs around once memory is totally allocated, and only
once the target class is full.  (So you can't move from #6 to #9 and #7
to #9 at the same itme, since you'd have to wait for #9 to fill from
the first reassigned page)

$ ./memcached_tool 127.0.0.1:11211 stats
#127.0.0.1:11211 Field       Value
                   bytes         135
              bytes_read        5964
           bytes_written       51394
                 cmd_get           3
                 cmd_set          54
   connection_structures           4
        curr_connections           3
              curr_items           1
               evictions           0
                get_hits           0
              get_misses           3
          limit_maxbytes  2147483648
                     pid        7186
            pointer_size          64
           rusage_system    0.002999
             rusage_user    0.003999
                 threads           1
                    time  1238401521
       total_connections         112
             total_items          54
                  uptime        1872
                 version       1.2.6

命令行的方式,在批处理调用的时候比较方便。但是在展现方面还是web方式更加直观有效,所以就有了php写的memcache.php,是的,用一次就知道这是我想要的。

用jQuery+Tablesorter实现客户端分页与排序

最近花了比较多的时间在自己开发的一个数据库监控系统上。监控系统的架构很简单,主要用shell+perl+SQL采集数据到一个MySQL数据库中,然后使用php来做web展示。对于仅仅定位于团队内部使用的小系统来说,这样的架构足够了,简单有效。

为了将数据库中的一些详细数据展示到web页面,采用了PEAR::HTML_Table,可以将SQL查询的结果直接转换成html表格。HTML_Table功能比较单一,如果要实现分页与排序的功能,还需要借助SQL语句。在MySQL中,如果要根据选择的任何一列都能用来排序的话,只要该列没有索引,就必须filesort进行实际的排序。由于系统中没有引入cache层,每次页面刷新都要到数据库中执行排序的SQL,性能是比较差的。

因此便想用javascript在客户端实现分页与排序,数据库中只要一次性选出需要的数据即可。jQuery是目前比较流行的一个javascript框架,以前也是久闻其名,但一直没有用过。Google了一把,发现其用法还是非常简单的,短短几行代码,就可以实现我所想要的效果。jQuery功能强大,但其实就是一个120K左右的js文件,并且还支持插件,分页功能就是通过一个叫tablesorter的插件实现的。

使用jQuery+Tablesorter实现客户端分页与排序,只需要10几行代码足矣。唯一的要求,就是html的table标签内要包含thead和tbody部分,这可以调用HTML_Table::getHeader()生成thead,调用HTML_Table::getBody()生成tbody部分。然后在需要展示数据的页面引入jQuery和Tablesorter的js库文件,再加上几行代码即可实现客户端javascript对数据table的分页与排序,并且还支持动态修改每页数据行数,支持多列排序等。具体的例子和代码,都可以在本文的链接中找到,就不在这里多说了。

Web开发我是外行,几年前学了点php的皮毛,知识已经多年没有更新过了。Ajax和web2.0的年代,javascript确实重新焕发了青春,像jQuery这样的框架,真的是不可多得的好东西,对于像我这样的初学者,也能很快上手做出相当不错的页面效果,这才是技术的生产力啊。

当然,在客户端做分页和排序有利也有弊。因为所有数据是一开始就全部从数据库中选取并返回客户端的,如果数据量比较大,那么第一次加载页面的时间就会比较长,并且可能占用客户端过多的资源。所以必须仔细权衡,在合适的场景用合适的技术。