关于linux:技术分享-Linux-环境下针对进程维度的监控实现

28次阅读

共计 16364 个字符,预计需要花费 41 分钟才能阅读完成。

作者:莫善

某互联网公司高级 DBA。

本文起源:原创投稿

* 爱可生开源社区出品,原创内容未经受权不得随便应用,转载请分割小编并注明起源。


一、背景介绍

运维工作中可能会遇到这么一个痛点,因线上机器根本都是单机多实例,有时候会呈现因为某个实例而影响了整个机器的性能。因短少过程级别的监控,预先想剖析是哪个实例跑满了系统资源往往比拟艰难。为了解决这一痛点,迫切希望实现过程级别的监控。

过程级别的资源监控,包含然而不限于 CPU,内存,磁盘 IO,网络流量。

二、后期筹备

经理解,有一个 process_exporter 能够实现过程监控,然而在理论调研及测试发现,该工具有些有余:

process_exporter https://github.com/ncabatoff/…

  • 监控的对象必须事后配置

咱们线上单台机器可能部署有 20 个实例,要么是将 20 个实例的配置放在一个 process_export,要么是单个实例一个 process_export,不论哪种形式部署 process_export 可能都有些麻烦,另外新加一个想监控的对象也须要从新保护一下 process_exporter。

我心愿是增加待监控机器后能主动发现所有沉闷的过程。

  • 不能监控过程的网络状况

测试 process_exporter 发现只有 io、内存、cpu 等应用状况,没找到网络监控的指标。

咱们线上机器很多还是千兆网卡,监控网络应用状况的需要更大。

  • 额定的需要

咱们的环境可能会有一些长期过程(不是常驻过程)。

三、需要实现

1、监控采集

最开始的思路很简略,就想着应用一些零碎工具间接读后果进行解析。然而领导感觉读取它们的采集后果可能略微重了一点,可能效率不高,达不到小粒度采集,所以想让我钻研一下间接抓取【/proc/pid/】上面运行态的数据,这种形式效率应该是最高的。然而在理论测试过程中发现,想要通过【/proc/pid/】来实现过程监控的计划真是困难重重,以至于起初临时放弃该计划了,不过还是想简略聊一下这个的测试历程。

[root process-exporter]# ls /proc/1
attr       auxv    clear_refs  comm             cpuset  environ  fd      gid_map  limits    map_files  mem        mounts      net  numa_maps  oom_score      pagemap      personality  root   schedstat  setgroups  stack  statm   syscall  timers   wchan
autogroup  cgroup  cmdline     coredump_filter  cwd     exe      fdinfo  io       loginuid  maps       mountinfo  mountstats  ns   oom_adj    oom_score_adj  patch_state  projid_map   sched  sessionid  smaps      stat   status  task     uid_map
[root process-exporter]# 

这个连贯比拟具体的介绍了【/proc/pid】上面的文件 / 目录 https://github.com/NanXiao/gn…

(1)CPU 状态抓取

间接翻车,在【/proc/pid/】上面没找到 CPU 相干的状态数据。

有晓得的大佬请领导一下。

(2)MEM 状态抓取

内存能够通过【/proc/pid/status】文件进行抓取。

$ grep "VmRSS:" /proc/3948/status 
VmRSS:    19797780 kB
$

(3)io 状态抓取

同理,io 也能够通过【/proc/pid/io】文件进行抓取。

$ grep "bytes" /proc/3948/io
read_bytes: 7808071458816
write_bytes: 8270093250560

(4)网络状态抓取

这个也间接翻车,在【/proc/pid/】上面倒是找到了跟网络相干的信息,比方【/proc/pid/net/dev】,还有【/proc/pid/netstat】。

起初认为 dev 这个文件是保留了过程级网络传输数据,然而发现这个文件记录的网络流量是整个网卡的,就是说【/proc/pid/net/dev】和【/proc/net/dev】这两个文件记录的网络流量字节数根本一样大。具体测试如下:

首先模仿两个网络传输的过程,因为我测试的机器是有 NFS,所以间接从 NFS 拷贝到本地,就模仿了网络传输。

$  ps -ef|grep -- "cp -i -r"|grep -v grep
root      66218 111973 12 17:14 pts/1    00:00:11 cp -i -r Backup_For_TiDB/15101/2022-06-20 /work
root      67099 122467 10 17:14 pts/2    00:00:09 cp -i -r Backup_For_TiDB/15001/2022-06-20 /work

过程号别离是 66218 67099

而后通过同时打印两个 pid 对应的【/proc/pid/net/dev】文件及零碎的【/proc/net/dev】文件做比照

$  cat /proc/66218/net/dev /proc/67099/net/dev /proc/net/dev |grep eth0 && sleep 1 && echo "------------------------" && cat /proc/66218/net/dev /proc/67099/net/dev /proc/net/dev|grep eth0
  eth0: 364616462197417 249383778845    0    0    0     0          0         0 77471452119287 170038153309    0    0    0     0       0          0
  eth0: 364616462197417 249383778845    0    0    0     0          0         0 77471452119287 170038153309    0    0    0     0       0          0
  eth0: 364616462197417 249383778845    0    0    0     0          0         0 77471452119287 170038153309    0    0    0     0       0          0
------------------------
  eth0: 364616675318586 249383924598    0    0    0     0          0         0 77471456448161 170038229547    0    0    0     0       0          0
  eth0: 364616675318586 249383924598    0    0    0     0          0         0 77471456449457 170038229571    0    0    0     0       0          0
  eth0: 364616675318586 249383924598    0    0    0     0          0         0 77471456449835 170038229578    0    0    0     0       0          0
$  

能够看到,这三个【/proc/66218/net/dev】【/proc/67099/net/dev】【/proc/net/dev】的 eth0 网卡的流量是一样的,就是说【/proc/pid/net/dev】理论也是零碎的流量开销,而不是单个过程对应的流量开销。

【/proc/pid/net/dev】这个不行就狐疑【/proc/pid/net/netstat】这个文件是我须要的,然而很好受,简直看不懂外面的信息,找了很多材料才大抵弄清楚外面的数据,最终发现也不是须要的数据。

/proc/pid/net/netstat 的详情能够参考这里 https://github.com/moooofly/M…

最终还是斗争了,老老实实应用现成的工具进行采集吧。

top free ps iotop iftop 等工具

2、数据分析

确定了采集形式后就是数据的剖析了,上面筹备挨个剖析一下。

(1)CPU

上面这几个是整机的状况

$ lscpu|grep 'NUMA node0 CPU(s)'|awk '{print $NF}'|awk -F'-' '{print $2+1}'  #机器 CPU 外围数
$ uptime|awk -F'average:' '{print $2}'|awk -F, '{print int($1)}'            #机器以后负载状况
$ top -b -n 1|grep '%Cpu(s):' |awk '{print int($8)}'  #idle
$ top -b -n 1|grep '%Cpu(s):' |awk '{print int($10)}' # iowait

这部分比较简单,间接记录即可。

上面是针对过程抓取 CPU 应用状况

$ top -b -n 1|grep -P "^[0-9]*"|awk 'NF==12 {if($9 > 200 || $10 > 10) {for (i=1;i<=NF;i++)
            printf $i"@@@";
        print "";
    }
}'  #过程应用 CPU 百分比,内存百分比,仅记录应用到 cpu 和内存的过程 

这部分略微有点简单,后果会保留到 top_dic 字典。

这个操作的目标是想着记录过程的 cpu 内存应用状况,然而会发现 top 的详情外面并没有过程信息,所以还须要联合 ps 辅助一下,具体如下:

ps -ef|awk '{printf $2"@@@";for(i=8;i<=NF;i++) {printf $i" "}print""}'

这部分后果会保留到 ps_dic 字典。只须要记录 pid 和过程详情即可,所以对 ps 做了剖析后最初的后果就是【pid@@@process_info】,最终 top_dic 和 ps_dic 通过 pid 关联

(2)MEM

上面是整机的状况

$ free |grep '^Mem:'|awk '{print int($2/1024/1024),int($3/1024/1024),int(($2-$3)/1024/1024)}'

上面是针对过程抓取 MEM 应用状况

# 过程应用 MEM 百分比在 cpu 局部就曾经采集 

内存这块是为了不便并没有应用 proc 上面的运行态数据,如果从 proc 上面采集须要遍历所有 pid,感觉比拟麻烦,还不如间接通过 top 采集一次来的不便(还是顺便采集)。然而也有一个弊病,最终计算过程应用内存大小会多一个操作,即须要依据 MEM 百分比对其进行计算换成具体字节数。

(3)磁盘

上面是整机的磁盘应用状况

$ df|grep '" + part +"'|awk '$2 > 1024 * 1024 * 50 && /^\//{print $1,int($2/1024/1024),int($3/1024/1024),int($4/1024/1024)}'  #磁盘应用状况 

须要数据盘的挂载点,如果没有配置挂载点会记录整个机器的所有挂载点(大于 50GB 的挂载点)的应用状况。

上面是针对过程抓取 io 应用状况

$ iotop -d 1 -k -o -t -P -qq -b -n 1|awk -F'%' '
    NR>2{
        OFS="@@@";
        split($1,a," ");
        if(a[5] > 10240 || a[7] > 10240 ) {print a[1],a[2],a[5]a[6],a[7]a[8],$NF;
        }
    }
    NR<3{print $0;}'|awk'
    {if(NR==1){print $1,$2,$6,$13;} else if(NR==2) {print $1,$2,$5,$11;} else {print $0;}
    }'

这个采集也略微有点简单,后果会保留到 iotop_dic 字典,通过 pid 和 top_dic 和 ps_dic 这两个字典关联。须要留神的是,在理论测试过程中发现,局部过程的详情十分长,所以为了防止数据冗余,过程信息会记录到独自的表【tb_monitor_process_info】,并记录该串的 md5 值且将 md5 作为惟一键,这样能够防止空间的节约。在展现的时候仅须要通过 md5 值作为关联条件即可。

咱们须要对后果做剖析并加工成咱们须要的,我感觉有用的就是【工夫】【pid】【读 io】【写 io】【过程信息】,以及对于 io 访问量少的过程间接过滤掉。

综上,过程级别的 cpu,内存,io 应用状况的采集数据上报给 server 端大略是上面这样:

    {
        "19991":{
            "cpu":"50.0",
            "mem":"12.5",
            "io_r":"145",
            "io_w":"14012",
            "md5":"2932fb739fbfed7175c196b42021877b",
            "remarks":"/opt/soft/mysql57/bin/mysqld --defaults-file=//work/mysql23736/etc/my23736.cnf"
        },
        "58163":{
            "cpu":"38.9",
            "mem":"13.1",
            "io_r":"16510",
            "io_w":"1245",
            "md5":"c9e1804bcf8a9a2f7c4d5ef6a2ff1b62",
            "remarks":"/opt/soft/mysql57/bin/mysqld --defaults-file=//work/mysql23758/etc/my23758.cnf"
        }
    }

(4)网络

网络的监控有点好受,没法基于 pid 做剖析,只能通过 ip:port 剖析来回的流量。

上面是整机的网络应用状况

$ iftop -t -n -B -P -s 1 2>/dev/null|grep Total |awk '
    NR < 3 {
        a = $4;
        if ($4 ~ /MB/) {a = ($4 ~ /MB/) ? 1024 * int($4) "KB" : $4;
        } else if ($4 ~ /GB/) {a = ($4 ~ /GB/) ? 1024 * 1024 * int($4) "KB" : $4;
        }
        a = (a ~ /KB/) ? int(a) : 0
        print $2, a;
    }
    NR == 3 {
        b = $6;
        if ($6 ~ /MB/) {b = ($6 ~ /MB/) ? 1024 * int($6) "KB" : $6;
        } else if ($6 ~ /GB/) {b = ($6 ~ /GB/) ? 1024 * 1024 * int($6) "KB" : $6;
        }
        b = (b ~ /KB/) ? int(b) : 0
        print $1, b;
    }'

上面是过程级别的网络应用状况

$ iftop -t -n -B -P -s 2 -L 200 2>/dev/null|grep -P '(<=|=>)'|sed 'N;s/\\n/,/g'|awk 'NF==13{if($4 ~ /(K|M|G)B/ || $10 ~ /(K|M|G)B/) {if(($4 ~ /KB/ && int($4) > 10240) ||
            ($10 ~ /KB/ && int($10) > 10240) ||
            ($4 ~ /MB/ && int($4) > 10240) ||
            ($10 ~ /MB/ && int($10) > 10240) ||
            ($4 ~ /GB/ || $10 ~ /GB/)) {print $2,$4,$8,$10}
        }
    }'

这部分比拟麻烦的是单位换算及计算。这部分会将后果保留到 iftop_dic。

这个采集也略微有一点简单,须要对后果做剖析并加工成咱们所须要的。我认为有用的就是【出 ip:port】【进口流量】【回 ip:port】【入口流量】。最初过程网络应用状况的采集数据上报给 server 端大略是上面这样子。

{
    "net":{
        "speed":"1000",
        "send":"7168",
        "receive":"8192",
        "Total":"16384",
        "time":"2022-06-29 20:16:20",
        "iftop" : {
            "192.168.168.11:55746":[
                {
                    "remote":"192.168.168.13:18059",
                    "out":"7.94KB",
                    "in":"307KB"
                }
            ],
            "192.168.168.11:60090":[
                {
                    "remote":"192.168.168.13:18053",
                    "out":"6.73KB",
                    "in":"307KB"
                }
            ]
        }
    }
}

至此,所有采集项的监控数据都曾经拿到了,上面就是将数据入库了。

3、数据入库

监控数据分析了当前,就是将其记录下来,本我的项目采纳 MySQL 来保留数据,其中未免波及一些二次剖析,以及注意事项,这里不筹备介绍,放在注意事项局部进行介绍。

4、数据展现

实现了数据分析,数据记录,最初的工作就是将数据展现进去,供运维人员在须要的时候随时查看剖析,本我的项目采纳 grafana 将数据展现进去,这个局部有些注意事项,这里也不筹备介绍,放在注意事项进行介绍。能够先来看个效果图:

四、注意事项

应用 python3 实现代码局部,所有注意事项的解决方案也是仅针对 python3 语法来实现的。

1、ssh 环境

数据的采集是通过 rpc 实现,然而 server 端对 client 的治理都是依赖 ssh,所以必须保障 server 到所有的 client 都能 ssh 免密登录。

2、长连贯

跟 MySQL 的通信,倡议应用长连贯。尤其是须要监控的机器个数比拟多,如果是短连贯会频繁跟 MySQL 进行创立连贯开释连贯,存在肯定的不必要开销。

def f_connect_mysql(): #建设连贯
    """建设连贯"""
    state = 0

    try :

        db = pymysql.connect(monitor_host, monitor_user, monitor_pass, monitor_db, monitor_port, read_timeout = 2, write_timeout = 5) #连贯 mysql

    except Exception as e :

        f_write_log(log_opt = "ERROR", log = "[ 建设连贯失败] [" + str(e) + "]", log_file = log_file)

        db = None
        
    return db

def f_test_connection(db):
    """测试连贯"""
    try:

        db.ping()

    except:

        f_connect_mysql()

    return db

def f_close_connection(db):
    """敞开连贯"""
    try:

        db.close()

    except:

        db = None

    return db

须要留神,如果是多线程的话倡议每个线程保护一个连贯,或者增加互斥锁,这样能够防止局部异样。

3、做减法

因为咱们是基于机器去做的过程监控,难免会呈现很多被监控的对象(一台机器上千个服务也不是不可能),在测试过程中没有发现这个问题影响很大,然而在实际上线后发现,如果不优化这个局部会导致 metrics 太多,grafana 的渲染很慢,所以对于不必要的采集记录,能够在采集的时候就过滤掉,能肯定水平防止 client 到 server 端的网络开销,也能缩小磁盘空间的开销,还晋升 grafana 的出图效率。

优化后,在配置文件提供了配置项,只有当过程应用系统资源满足阈值才会被采集。

4、超时机制

(1)操作 MySQL 的超时

既为了代码的健壮性,也是为了程序的继续、稳定性都倡议加上超时参数,能够防止因为一些极其场景导致读数或者写数卡住。

(2)采集数据的超时

生产环境的复杂性,什么都可能产生,即使是一条简略到不能再简略的命令也可能呈现卡住,所以加上超时机制吧。这里须要留神,在增加超时机制的时候发现有些问题,具体测试如下:

Python 3.7.4 (default, Sep  3 2019, 19:29:53) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-16)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import datetime,subprocess
>>> s_time = datetime.datetime.now()
>>> res = subprocess.run("echo $(sleep 10)|awk'{print $1}'",shell=True,stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE,encoding="utf-8",timeout=2)

省略了很多谬误输入

subprocess.TimeoutExpired: Command 'echo $(sleep 10)|awk'{print $1}'' timed out after 2 seconds
>>> e_time = datetime.datetime.now();
>>> 
>>> print(s_time)
2022-06-23 13:05:37.886864
>>> print(e_time)
2022-06-23 13:05:48.353889
>>> print(res)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'res' is not defined
>>> 

能够看到【subprocess.run】设置了两秒超时,然而两秒后没有抛出异样并完结执行,从执行工夫看 s_time 跟 e_time 相差 11 秒,然而整个执行后果是异样的(res 都没有后果),就是说并没有起到料想的超时成果(料想的成果是到超时阈值后终止执行,返回异样)。

如果操作命令是简略的命令就没事,比方将【echo $(sleep 10)|awk ‘{print $1}’】改成【sleep 10】,这个超时机制就失常。

针对这个超时机制可能会呈现生效的状况,在代码外面间接用系统命令 timeout 代替了。

5、返回值

如果操作命令带管道等简单命令,返回值可能并不可信。具体测试如下

>>> res = subprocess.run("echoa|awk'{print $1}'",shell=True,stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE,encoding="utf-8",timeout=2)
>>> res.returncode
0
>>>

【echoa|awk ‘{print $1}’】管道右边的操作是谬误的,所以整个返回后果应该是非零(预期是这样),然而这里返回了 0。起因是在管道操作的场景,bash 默认状况是仅获取最初一个管道的执行返回状态码,例如【comm1|comm2|comm3】,如果 comm1 执行胜利,comm2 执行失败,然而 comm3 执行胜利,那整个返回状态就是执行胜利。

解决方案如下

>>> res = subprocess.run("set -o pipefail;echoa|awk'{print $1}'",shell=True,stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE,encoding="utf-8",timeout=2)
>>> res.returncode
127
>>> 

执行命令前先加一个 set -o pipefail,对于 set - o 的解释能够参考上面的形容。

-o    If set, the return value of a pipeline is the value of the last (rightmost) command to exit with a non-zero status, or zero if all  com‐mands in the pipeline exit successfully.  This option is disabled by default.

五、工作原理

1、server

  • 线程 1

这个线程会做三个事件:

(1)在 server 重启的时候会去读【tb_monitor_version】表,判断以后版本号跟 MySQL 记录的版本号是否统一,如果不统一就会去更新 MySQL 记录的版本号。而后将【tb_monitor_host_config】表所有 istate= 2 的节点更新为 istate=1。

(2)治理 client 上线下线,每 30s 去读一次【tb_monitor_host_config】表,将须要上线的节点或者须要下线的节点进行保护。istate= 1 示意须要上线,就会去部署监控脚本(降级就更新代码),并更新为 istate=2,istate= 0 示意须要下线,会去下线该 client 节点并更新为 istate=-1。

(3)治理 client 状态,每 30s 去读一次【tb_monitor_host_config,tb_monitor_alert_info,tb_monitor_host_info】表(三表关联),将最近两分钟没有上报的 client 且最近 5min 没有被告警的节点统计进去并告警。

  • 线程 2

这个线程做两个事:

(1)期待 client 上报监控数据,而后进行二次剖析并写到 MySQL 中。

(2)返回以后版本号给 client。

2、client

client 端会做三个事件

(1)六线程并行去采集【机器 cpu】【机器内存】【机器磁盘】【机器网络】【过程网络】【过程 io,过程 cpu,过程内存】。采集结束后,主线程会进行剖析并上报给 server 端。

(2)在上报过程中如果遇到间断三次 server 都是异样状态就会将 server 异样记录(防止多个 client 同时告警)到【tb_monitor_alert_info】表发送告警。

(3)上报实现后会判断本人的版本号跟 server 端返回的版本号是否统一,如果不统一就会退出程序,期待 crontab 拉起,以此实现降级。

server 端实现代码更新,在重启 server 的时候会将新代码同步到各个 client。

3、MySQL

MySQL 的作用是存版本信息,client ip 配置,监控数据,以及告警状态等。

4、grafana

grafana 的作用是从 MySQL 读取监控数据并展现进去。

5、alert

采纳企业微信的机器人作为告警通道。

六、应用限度

1、零碎环境

(1)操作系统版本及内核。

$ uname -a
Linux 3.10.0-693.21.1.el7.x86_64 #1 SMP Wed Mar 7 19:03:37 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
$ cat /etc/redhat-release
CentOS Linux release 7.4.1708 (Core)

其余版本没有测试过,不确定是否能用。

(2)零碎工具

监控数据采集依赖于操作系统工具,次要依赖如下:

awk,grep,sed,tr,md5sum
top,iftop,iotop
df,free,lscpu,uptime
ip,netstat
rsync,python3
cd,ssh,timeout

server 端到 client 要有免密登录。

2、软件环境

软件版本可能存在兼容性问题,所以其余版本不确定是否能用,请各自测试调试。

(1)Python 环境

3.7.4

(2)MySQL 版本

5.7.26

(3)grafana 版本

8.3.1 倡议小版本也要统一。https://dl.grafana.com/enterp…

七、应用介绍

1、部署 server

(1)clone 我的项目
mkdir -p /opt/soft/git
cd /opt/soft/git
git clone https://gitee.com/mo-shan/rpc_for_process_monitor.git

依赖 Python3 环境,倡议 3.7.4,要求 python3 在 PATH 外面,装置过程略。

(2)部署 server
cp -r /opt/soft/git/rpc_for_process_monitor /opt/soft/rpc_for_monitor  #留神这里的目录是有区别的, 次要是心愿开发环境跟理论部署的目录不一样, 防止失误
cd /opt/soft/rpc_for_monitor

$ tree -L 2
.
├── conf
│   └── config.ini                  #配置文件
├── img                             #疏忽
│   ├── all-info.png
│   ├── cpu-info.png
│   ├── disk-info.png
│   ├── grafana-data-source-1.png
│   ├── grafana-data-source-2.png
│   ├── grafana-data-source-3.png
│   ├── grafana-data-source-4.png
│   ├── grafana-data-source-5.png
│   ├── grafana-data-source-6.png
│   ├── grafana-data-source-7.png
│   ├── mem-info.png
│   ├── net-info.png
│   └── process-info.png
├── init                            #初始化文件
│   ├── grafana.json                #grafana 配置模板
│   ├── init.sql                    #mysql 建表语句
│   └── requirements.txt            #python3 依赖的模块
├── lib                             #库文件
│   ├── Config.py                   #解析 config.ini
│   ├── ConnectMySQL.py             #连贯并操作 mysql
│   ├── globalVar.py                #全局变量
│   ├── Public.py                   #公共函数
│   └── __pycache__
├── LICENSE
├── logs                            #日志目录
│   └── info.log                    #日志文件
├── py37env                         #虚拟环境,要求在 /opt/soft/rpc_for_monitor/py37env 下能力应用(activate 等文件的门路写死了)│   ├── bin
│   ├── include
│   ├── lib
│   └── pip-selfcheck.json
├── README.md                       #帮忙文档
├── rpc.py                          #主程序
├── start_server.sh                 #server 端的启动脚本
└── state                           #疏忽
    └── state.log

11 directories, 28 files
(3)配置 server
vim conf/config.ini #依据理论状况进行编辑 

如果须要变更我的项目目录,须要将【lib/Config.py】文件的变量【config_file】也改一下。

[global]
version       = 1.1   #版本号, 通过这个变量管制 server 和 client 的代码,如果 server 发现这个配置跟表里保留的版本不统一就认为代码进行了变更,就会将新代码传到 client,client 如果发现自己的版本和 server 版本不一样会进行重启,以此达到降级成果。interval_time = 30    #监控采集粒度单位是秒,即 30 秒一次,这个不是齐全准确的 30s 一次
retention_day = 30    #监控数据保留天数,即 30 天
log_file = /opt/soft/rpc_for_monitor/logs/info.log #日志文件
script_dir = /opt/soft/rpc_for_monitor             #脚本目录,不倡议变更
mount_part    = /work  #数据盘挂载点, 也能够不配置,置为空,然而不能删除这个配置项
log_size      = 20     #日志文件大小(MB)限度,超过这个值就会删除历史日志

[RULE] 
cpu = 200    #采集的阈值,200 示意某个过程应用 cpu 大于等于 200% 才会被采集
mem = 10     #采集的阈值,10 示意某个过程应用内存大于等于 10GB 才会被采集
io  = 10240  #采集的阈值,10240 示意某个过程应用 io(读写有一个就算)大于等于 10MB 才会被采集
net = 10240  #采集的阈值,10240 示意某个过程应用网络(进出有一个就算)大于等于 10MB 才会被采集

[CLIENT]
path = xxxx  #预约义一下操作系统的 path,因为 client 会保护一个 cront 工作,所以防止因为环境变量问题导致脚本执行报错,须要定义一下 path
python3 = /usr/local/python3 #python3 装置目录
py3env = /opt/soft/rpc_for_monitor/py37env #python3 虚拟环境目录,工程自带了一个虚拟环境,能够间接用(前提是脚本目录没有变更)[MSM]
wx_url  = xxxx   #企业微信报警 url,告警性能须要用户本人批改一下并测试(如果是告警机器人 url+key,能够间接配上就能用,本例就是通过企业微信机器人发送告警)[Monitor]  #寄存监控数据的 MySQL 的配置
mysql_host      = xxxx
mysql_port      = xxxx
mysql_user      = xxxx
mysql_pass      = xxxx
省略局部不倡议变更的配置 

所有目录不倡议批改, 要不然须要变更的中央太多,容易出错。

2、部署 MySQL

装置 MySQL 略,倡议的版本:5.7

(1)新建必要的账户

用 MySQL 管理员用户登录并操作。

create user 'monitor_ro'@'192.%' identified by 'pass1'; #明码请依据理论状况变更

grant select on dbzz_monitor.* to 'monitor_ro'@'192.%';

create user 'monitor_rw'@'192.%' identified by 'pass2';

grant select,insert,update,delete on dbzz_monitor.* to 'monitor_rw'@'192.%';

monitor_ro 用户给 grafana 应用, monitor_rw 用户是给程序写入监控数据的(server 端写数据,client 上报给 server)。所以留神的是,monitor_ro 用户要给 grafana 机器受权,monitor_rw 用户要给所有监控对象受权,这个目标是用来管制当 server 失联了,第一个发现的 client 就会向表里写一条告警记录并告警,防止其余 client 反复操作。

(2)初始化 MySQL

用 MySQL 管理员用户登录并操作。

cd /opt/soft/rpc_for_monitor
mysql < init/init.sql 

所有表放在 dbzz_monitor 库下

(dba:3306)@[dbzz_monitor]>show tables;
+----------------------------+
| Tables_in_dbzz_monitor     |
+----------------------------+
| tb_monitor_alert_info      |   # 告警表, 触发告警就会在外面写入一条记录, 防止同一时间屡次告警。| tb_monitor_disk_info       |   # 磁盘信息表,多个盘会记录多条记录
| tb_monitor_host_config     |   # client 配置表,须要采集监控的机器配置到这外面就行
| tb_monitor_host_info       |   # 零碎层面的监控记录到这外面
| tb_monitor_port_net_info   |   # 端口级别的网络监控会记录到这外面
| tb_monitor_process_info    |   # 这外面是记录了过程信息,全局的
| tb_monitor_process_io_info |   # 这里是记录的过程的 io 监控数据
| tb_monitor_version         |   # 记录版本号,及版本号变更工夫
+----------------------------+
6 rows in set (0.00 sec)

(dba:3306)@[dbzz_monitor]>

所有表都有具体的正文,请看表的建表正文。

3、配置 client

配置客户端很简略,只须要往 MySQL 表外面写入一条记录。

use dbzz_monitor;
insert into tb_monitor_host_config(rshost,istate) select '192.168.168.11',1;  
#多个机器就写多条记录,server 端会有后盾线程定时扫描 tb_monitor_host_config
#如果有待增加的 client 就会进行部署
#如果须要下线监控节点间接将 istate 状态改成 0 即可 

这里有个限度条件,这个 client 端曾经有 python3 环境,否则会报错。

4、部署 grafana

装置略。

grafana 版本:8.3.1,倡议小版本也要统一。https://dl.grafana.com/enterp…

这部分波及到 grafana 的配置,所有的配置都曾经导成 json 文件,用户间接导入即可。

具体的操作如下。

(1)新建 DataSource

新建一个数据源


须要抉择 MySQL 数据源

数据源的名称要求写【dba_process_monitor】,如果跟 grafana 配置不统一可能会有影响。

(2)导入 json 配置
$ ll init/grafana.json 
-rw-r--r-- 1 root root 47875 Jun 23 14:28 init/grafana.json

本配置是在 grafana 8.3.1 版本下生成的。须要留神一下版本,不同版本可能不兼容。如果版本不统一导入会导致出图失败,须要用户本人重新配置 grafana,出图的 sql 能够参考一下 grafana 配置文件的 rawSql 的配置【grep rawSql init/grafana.json】。

  • 倡议 1:【Lagend】的配置都改成【as table】,要不然如果指标太多显示进去的会很乱
  • 倡议 2:抉择单位的时候对于不心愿进行转换的能够选【Custom unit】属性
  • 倡议 3:【Stacking and null value】属性倡议设置为【null as zero】

5、启动 server

将 server 端的启动脚本配置到 crontab 中,能够起到守护过程的作用。

echo "*/1 * * * * bash /opt/soft/rpc_for_monitor/start_server.sh" >> /var/spool/cron/root

client 端不必管,server 启动当前会主动去治理 client。

配置实现后,期待一分钟查看日志【/opt/soft/rpc_for_monitor/logs/info.log】,能够看到相似上面的日志。

[2022-06-30 15:13:01] [INFO] [V1.1 Listening for '0.0.0.0:9300']
[2022-06-30 15:13:04] [INFO] [新加监控节点胜利] [192.168.168.11]
[2022-06-30 15:13:11] [INFO] [监控数据上报胜利] [192.168.168.11] 

端口默认是 9300,能够通过批改【/opt/soft/rpc_for_monitor/start_server.sh】这个文件就行变更监听端口。

6、效果图

(1)主页面

总共有五个 ROW,后面四个是机器级别的监控图,process 是过程的监控图。

(2)CPU 页面

整个机器的 CPU 应用状况。

(3)内存页面

整个机器的内存应用状况。

(4)磁盘页面

整个机器的磁盘应用状况,如果没有定义具体的挂载点,会采集所有的挂载点。

(5)网络页面

整个机器的网络应用状况。

(6)过程页面

会看到具体的过程对系统资源的应用状况。须要留神,因在采集的时候做了过滤,所以监控数据并不一定是间断的,所以倡议配置 grafana 的【null as zero】,这样展现监控图的时候是间断的,而不是很多点。另外某个指标可能为空,这也是失常景象。

八、注意事项

  • server,client 端肯定要有 python3 环境。
  • 如果有多个 server,在启动 server 的时候就要指定多个(用逗号隔开),要不然在部署 client 的时候只会配上单个 server,配置多个的益处就是如果第一个宕机 / 异样,client 会上报给其余的 server。
  • server 在运行过程中能够增加 client,只须要在【tb_monitor_host_config】表增加 istate 为 1 的记录即可。同理,如果下线的话就更新 istate 为 0 即可,运行中的 istate 为 2,下线后的 istate 为 -1。
  • 该工具有告警性能(如果配置),server 挂了(client 间断三次都连不上 server),会由第一个发现的 client 记录到 MySQL 外面,并发送告警,如果 client 挂了,server 会发现并告警(超过两分钟未上报告警数据)。
  • 如果须要降级代码,只须要测试好新代码,确认无误后,更新到 server 的部署脚本目录,而后 kill 掉 server 过程即可,期待 crontab 拉起就行了,client 端的代码不必人为进行更新。须要留神,新代码肯定要记得批改配置文件的版本号,要不然 server 端不会发现版本不统一,也就不会下发相干工作去更新 client 的代码。
  • 如果须要批改部署目录请依据理论状况批改【conf/config.ini】【lib/Config.py】,留神这时候自带的虚拟环境将不能应用了。强烈不倡议变更目录构造或者目录名。
  • 因思考到 MySQL 性能问题及 grafana 渲染性能问题,所以减少了采集阈值性能,所以局部面板的监控数据可能会没有(该时间段的过程没有满足采集阈值的数据)。

九、写在最初

本文所有内容仅供参考,因各自环境不同,在应用文中代码时可能碰上未知的问题。如有线上环境操作需要,请在测试环境充沛测试。

正文完
 0