目录
Zabbix server: More than 75% used in the history cache
监控什么
prometheus 监控可见:prometheus 从入门到精通(史上最全)-CSDN博客
服务器
cpu利用率、mem、网卡输入、网卡输出(是否有猛增的流量,正常情况下流量不会超过某个值,进口增大—》可能遭到攻击,出口增大—》可能中了木马变成肉鸡)
应用程序
python、java、php
服务
nginx、tomcat、httpd
开源监控
zabbix
普罗米修斯(使用go语言 时序监控)——对容器、微服务的监控
Open-fa
一、安装部署
lcon (小米的)
服务端
服务端安装
# 安装zabbix仓库 rpm -Uvh https://repo.zabbix.com/zabbix/5.0/rhel/7/x86_64/zabbix-release-5.0-1.el7.noarch.rpm # 安装zabbix server 和agent yum -y install zabbix-server-mysql zabbix-agent # 安装 Red Hat 软件集合(仓库) yum -y install centos-release-scl # 编辑仓库配置文件 /etc/yum.repos.d/zabbix.repo 并开启 zabbix-frontend repository [zabbix-frontend] ... enabled=1 ... # 安装 Zabbix 前端 软件包 yum -y install zabbix-web-mysql-scl zabbix-nginx-conf-scl # 进入数据库 # 创建 zabbix数据库 create database zabbix character set utf8 collate utf8_bin; # 创建 zabbix用户 create user zabbix@localhost identified by '密码'; # 授权 grant all privileges on zabbix.* to zabbix@localhost; # 导入初始架构和数据,系统将提示您输入新创建的密码 zcat /usr/share/doc/zabbix-server-mysql*/create.sql.gz | mysql -uzabbix -p密码 zabbix # 配置数据库 vim /etc/zabbix/zabbix_server.conf DBPassword=密码 # 配置rh-nginx vim /etc/opt/rh/rh-nginx116/nginx/nginx.conf 删除 server 内容 # 配置nginx子配置文件 vim /etc/opt/rh/rh-nginx116/nginx/conf.d/zabbix.conf 取消 listen 和 server_name 的注释并设置它们。 # 配置php vim /etc/opt/rh/rh-php72/php-fpm.d/zabbix.conf # 添加 nginx 到 listen.acl_users 指令的值中 listen.acl_users = apache,nginx # 取消下面的注释并设置正确的时区 php_value[date.timezone] = Asia/Shanghai # 启动zabbix服务 systemctl restart zabbix-server zabbix-agent rh-nginx116-nginx rh-php72-php-fpm
如果 mysql 用的是8.x版本的,zabbix-server 就会无法正常启动,这是因为 mysql 8.x 版本的密码加密方式与之前的不同,可进入数据库更改 zabbix 用户的密码加密方式。
# 具体报错为 ERROR 2059 (HY000): Authentication plugin 'caching_sha2_password' cannot be loaded: /usr/lib64/mysql/plugin/caching_sha2_password.so: cannot open shared object file: No such file or directory # 更改步骤,1.先查看当前规则 select host,user,plugin from mysql.user; +-----------+------------------+-----------------------+ | host | user | plugin | +-----------+------------------+-----------------------+ | localhost | mysql.infoschema | caching_sha2_password | | localhost | mysql.session | caching_sha2_password | | localhost | mysql.sys | caching_sha2_password | | localhost | root | caching_sha2_password | | localhost | zabbix | caching_sha2_password | +-----------+------------------+-----------------------+ 5 rows in set (0.00 sec) # plugin 就是密码的加密规则,我们可以看到 zabbix 用户的加密规则是 caching_sha2_password ,而之前版本所用的加密规则是 mysql_native_password,所以我们现在要将加密规则改回来 # 第二步,更改加密规则 alter user 'zabbix'@'localhost' identified by '[email protected]' password expire never; alter user 'zabbix'@'localhost' identified with mysql_native_password by '[email protected]; # 再次查看 +-----------+------------------+-----------------------+ | host | user | plugin | +-----------+------------------+-----------------------+ | localhost | mysql.infoschema | caching_sha2_password | | localhost | mysql.session | caching_sha2_password | | localhost | mysql.sys | caching_sha2_password | | localhost | root | caching_sha2_password | | localhost | zabbix | mysql_native_password | +-----------+------------------+-----------------------+ 5 rows in set (0.00 sec) # 现在重新启动 zabbix-server 就可以发现 他可以正常启动了
服务端页面配置
访问并配置zabbix,直接在网页输入自己的IP加端口即可
填写 Zabbix 服务器的主机名或主机IP地址和端口号,以及安装的名称(可选)。最后的
Name
的值是可选的,这个表示安装的这个 zabbix server 是什么角色。因为, Zabbix 是可以做分布式的监控系统,可以有一个服务器角色和多个代理角色。这里还有一步信息确认忘了截图,不过无关紧要,确认无误后下一步即可
至此,zabbix 的安装就完成了
默认的登录用户名为:Admin ,密码为:zabbix
成功后,进入仪表盘
中文配置
图形中文乱码
图形中文乱码
首先在 windows 中找一个自己喜欢的字体文件,具体路径在 C:\Windows\Fonts
,找一个 ttf 类型的文件(可以选中文件然后右击属性查看)
找到对眼的以后,上传至服务器,将文件放在 /usr/share/zabbix/assets/fonts
目录下,将文件的后缀改为小写 ttf
然后更改配置文件 /usr/share/zabbix/include/defines.inc.php
中的 define('ZBX_GRAPH_FONT_NAME', 'graphfont'); // font file name
将 graphfont 改为字体文件的名字(不加后缀)即可,无需重启服务,直接刷新zabbix 页面即可生效
agent 端
使用yum安装
# 安装zabbix仓库
rpm -Uvh https://repo.zabbix.com/zabbix/5.0/rhel/7/x86_64/zabbix-release-5.0-1.el7.noarch.rpm
# 安装 zabbix-agent
yum -y install zabbix-agent
# 修改配置文件,添加server端的IP,具体看下面配置文件的介绍
vim /etc/zabbix/zabbix_agentd.conf
# 启动
systemctl restart zabbix-agent
二进制安装
# 下载二进制包
wget https://cdn.zabbix.com/zabbix/binaries/stable/5.0/5.0.7/zabbix_agent-5.0.7-linux-3.0-amd64-static.tar.gz
# 解压
mkdir /usr/local/zabbix-agent
tar -xf zabbix_agent-5.0.7-linux-3.0-amd64-static.tar.gz -C /usr/local/zabbix-agent
# 添加zabbix用户
useradd zabbix
# 注意:默认情况下,即使使用 `root` 用户启动此程序,程序最终也会用 `zabbix` 用户启动,此时只要保证系统中有 `zabbix` 用户即可。
# 指定配置文件启动
/usr/local/zabbix_agent/sbin/zabbix_agentd -c /usr/local/zabbix_agent/conf/zabbix_agentd.conf
agent 配置文件介绍
############ GENERAL PARAMETERS #################
##### Passive checks related 被动模式
### Option: Server
Server=127.0.0.1 # 被动模式下 zabbix server 的地址,也就是允许哪些主机给我发指令
# 换成服务端IP
### Option: ListenPort
# ListenPort=10050 # Agent 自己的监听端口
### Option: ListenIP
# ListenIP=0.0.0.0 # Agent 自己的监听地址
##### Active checks related 主动模式
### Option: ServerActive
ServerActive=127.0.0.1 # 主动模式下,向这些服务器主动汇报监控数据 换成服务端IP
### Option: Hostname
# Hostname=
Hostname=Zabbix server # agent端在 Server 端的识别码,可以不更改
自动发现并安装
实现自动发现,自动安装agent,自动添加模板,自动添加监控项,自动添加触发器,自动添加动作
即从发现到监控,一气呵成!
step 1 创建自动发现规则
设置好你要发现的 IP 段
step 2 创建发现动作
注意这个路径,一定要在左上角选择 Discovery actions
,然后点击创建动作
新建的动作要添加两个条件
-
第一个为第一步创建的发现规则,即去ping
-
第二个是必须能 ping 通。
这两个条件必须为 和 (同时满足)
条件添加完毕后,再添加操作,即当满足上述条件后进行的动作
-
执行远程命令 因为 angent 不会自己安装自己,所以我们需要搞个脚本来进行这步操作
-
当安装、配置完agent后,添加上该主机
-
添加主机群
-
添加模板
至此,一台机器就从无到有,自动监控上了
啥,还缺东西
那可不,脚本光看了功能和名字,还不知道内容呢
这里用到了使用 nginx 来进行获取脚本并执行,由脚本自动安装配置agent
nginx 没啥特殊的,只要搭建一个普通的nginx即可,然后将脚本放在它的 root 目录下,就可以使用 curl 来进行获取
# 如果要使用,请仔细看这个脚本后,然后修改 IP
create_yum(){
echo -e """[yumop]
name=centos7.6
baseurl=http://128.1.70.1/centos
enabled=1
gpgcheck=0
[yumop2]
name=centos7.7
baseurl=http://128.2.42.165:8090
enabled=1
gpgcheck=0 """ >/etc/yum.repos.d/1.repo
yum clean all
yum makecache
}
# 检查是否已有agent
rpm -qa|grep zabbix-agent
if [[ $? -eq 0 ]];then
exit 0
fi
# 查看yum源是否ok
if [[ -e /etc/yum.repos.d/1.repo ]];then
grep "baseurl=http://128.1.70.1/centos" /etc/yum.repos.d/1.repo >/dev/null && grep "baseurl=http://128.2.42.165:8090" /etc/yum.repos.d/1.repo >/dev/null
if [[ $? -ne 0 ]];then
create_yum
fi
else
mkdir /etc/yum.repos.d/bak && mv /etc/yum.repos.d/*.repo /etc/yum.repos.d/bak
if [[ $? -eq 0 ]];then
create_yum
else
exit 99
fi
fi
# 下载agent
yum -y install zabbix-agent >/dev/null
if [[ $? -eq 0 ]];then
sed -i '/^Server=/cServer=128.2.64.153' /etc/zabbix/zabbix_agentd.conf && \
sed -i '/^ServerActive==/cServerActive==128.2.64.153' /etc/zabbix/zabbix_agentd.conf && \
systemctl restart zabbix-agent.service
fi
二、添加监控
1、添加被监控的主机
实际生产中,被监控的主机中总是会有一部分主机需要被监控同样的内容,比如对于一个Nginx 集群,集群内的主机都需要监控他们的 nginx 进程。这样的话,我们应该建立一个主机组,之后把它们添加到这个主机组中。然后对这个主机组来设置相关的监控项。
添加主机组
添加主机
被添加的主机必须在配置文件中设置好监控的方式及server端的IP
在没有添加监控项之前,监控方式(可用性)的灯是不会亮起来的
2、添加监控项
初始可选的监控项有以下这些
注意监控项中的键值 net.dns[<ip>,name,<type>,<timeout>,<count>,<protocol>] 中括号中,有< > 的是选填,不加的是必填,具体参数可以看这里
因为我设置的时候忘记截图了,又点进去查看,所以下面是更新
配置好后,就可以查看被监控主机的状态了
关于监控项单位的种种
注意:只要是初始值是大于等于 1000
的,Zabbix 都会对数据进行处理,处理的方式是除以 1000
或者除以 1024
,得到的结果如果仍然大于等于 1000, 就会继续除以 1000
或者除以 1024
,直到得到的结果小于 1000
为止
3、触发器
触发值选择
设置触发器
last(1) 表示最后一秒
last(#1) 表示最后一次
4、报警媒介
集中发送通知的方式,在 Zabbix 中都称为 报警媒介类型,报警媒介类型默认就会有很多。
电子邮件类
# 报警模板
事件: {EVENT.NAME}
事件主机: {HOST.NAME}
事件时间: {EVENT.DATE} {EVENT.TIME}
事件等级: {TRIGGER.SEVERITY}
事件信息: {TRIGGER.NAME}
事件项目: {TRIGGER.KEY1}
事件详情: {ITEM.NAME} : {ITEM.VALUE}
当前状态: {TRIGGER.STATUS} : {ITEM.VALUE1}
事件ID: {EVENT.ID}
操作数据: {EVENT.OPDATA}
{TRIGGER.URL}
测试
Mattermost
俺们公司是内网环境,通信靠 Mattermost 来进行交流,所以报警就靠 Mattermost 来报警了,zabbix中是有默认报警模板,只要稍加修改就可以使用
trigger_description 告警描述
// 默认的脚本也可以改改,这样可以控制显示的格式,以下是脚本全文,可以直接使用,我会在其中使用注释 标注哪里可以更改
var SEVERITY_COLORS = [
'#97AAB3', '#7499FF', '#FFC859',
'#FFA059', '#E97659', '#E45959'
];
var RESOLVE_COLOR = '#009900';
var SEND_MODE_HANDLERS = {
alarm: handlerAlarm,
event: handlerEvent
};
if (!String.prototype.format) {
String.prototype.format = function() {
var args = arguments;
return this.replace(/{(\d+)}/g, function(match, number) {
return number in args
? args[number]
: match
;
});
};
}
function isEventProblem(params) {
return params.event_value == 1
&& params.event_update_status == 0
;
}
function isEventUpdate(params) {
return params.event_value == 1
&& params.event_update_status == 1
;
}
function isEventResolve(params) {
return params.event_value == 0;
}
function getPermalink(mattermost_url, team_name, postid) {
return '{0}/{1}/pl/{2}'.format(
mattermost_url.replace(/\/+$/, ''),
team_name,
postid
);
}
function getChannel(send_to) {
switch (true) {
case /.+\/#.+/.test(send_to):
return getChannelByName(send_to);
case /@.+/.test(send_to):
return getDirectChannel(send_to);
default:
return getChannelByID(send_to);
}
}
function getChannelByName(send_to) {
var team_chan = send_to
.trim()
.split('/#');
var resp = JSON.parse(req.Get(
Mattermost.channel_byname.format(team_chan[0], team_chan[1]),
JSON.stringify(fields)
)
);
if (req.Status() != 200) {
throw '[{0}] {1}'.format(resp.status_code, resp.message);
}
return resp;
}
function getDirectChannel(send_to) {
Zabbix.Log(5, '[ Mattermost Webhook ] Call {0}({1})'.format(
arguments.callee.name,
JSON.stringify(arguments)
));
var teamUser = send_to
.trim()
.split('/@'),
bot = getBotUser(),
user = getUserByName(teamUser[1]);
var resp = JSON.parse(req.Post(
Mattermost.direct_channel,
JSON.stringify([bot.id, user.id])
)
);
Zabbix.Log(5, '[ Mattermost Webhook ] Result {0}: {1}'.format(
arguments.callee.name,
JSON.stringify(resp)
));
if (req.Status() != 201) {
throw '[{0}] {1}'.format(resp.status_code, resp.message);
}
resp.team_name = teamUser[0];
return resp;
}
function getChannelByID(channelID) {
Zabbix.Log(5, '[ Mattermost Webhook ] Call {0}({1})'.format(
arguments.callee.name,
JSON.stringify(arguments)
));
var resp = JSON.parse(req.Get(
Mattermost.get_channel.format(channelID),
JSON.stringify(fields)
)
);
Zabbix.Log(5, '[ Mattermost Webhook ] Result {0}: {1}'.format(
arguments.callee.name,
JSON.stringify(resp)
));
if (req.Status() != 200) {
throw '[{0}] {1}'.format(resp.status_code, resp.message);
}
return resp;
}
function getBotUser() {
Zabbix.Log(5, '[ Mattermost Webhook ] Call {0}({1})'.format(
arguments.callee.name,
JSON.stringify(arguments)
));
var resp = JSON.parse(req.Get(
Mattermost.bot_user,
JSON.stringify(fields)
)
);
Zabbix.Log(5, '[ Mattermost Webhook ] Result {0}: {1}'.format(
arguments.callee.name,
JSON.stringify(resp)
));
if (req.Status() != 200) {
throw '[{0}] {1}'.format(resp.status_code, resp.message);
}
return resp;
}
function getUserByName(userName) {
Zabbix.Log(5, '[ Mattermost Webhook ] Call {0}({1})'.format(
arguments.callee.name,
JSON.stringify(arguments)
));
var resp = JSON.parse(req.Get(
Mattermost.user_byname.format(userName),
JSON.stringify(fields)
)
);
Zabbix.Log(5, '[ Mattermost Webhook ] Result {0}: {1}'.format(
arguments.callee.name,
JSON.stringify(resp)
));
if (req.Status() != 200) {
throw '[{0}] {1}'.format(resp.status_code, resp.message);
}
return resp;
}
function getTeamByID(teamID) {
Zabbix.Log(5, '[ Mattermost Webhook ] Call {0}({1})'.format(
arguments.callee.name,
JSON.stringify(arguments)
));
var resp = JSON.parse(req.Get(
Mattermost.get_team.format(teamID),
JSON.stringify(fields)
)
);
Zabbix.Log(5, '[ Mattermost Webhook ] Result {0}: {1}'.format(
arguments.callee.name,
JSON.stringify(resp)
));
if (req.Status() != 200) {
throw '[{0}] {1}'.format(resp.status_code, resp.message);
}
return resp;
}
function createProblemURL(zabbix_url, triggerid, eventid, event_source) {
var problem_url = '';
if (event_source === '0') {
problem_url = '{0}/tr_events.php?triggerid={1}&eventid={2}'
.format(
zabbix_url,
triggerid,
eventid
);
}
else {
problem_url = zabbix_url;
}
return problem_url;
}
function getTagValue(event_tags, key) {
var pattern = new RegExp('(' + key + ':.+)');
var tagValue = event_tags
.split(',')
.filter(function (v) {
return v.match(pattern);
})
.map(function (v) {
return v.split(':')[1];
})[0]
|| 0;
return tagValue;
}
function handlerAlarm(req, params) {
var channel = getChannel(params.send_to);
var fields = {
channel_id: channel.id,
props: {}
};
if (isEventProblem(params)) {
var team_name = channel.team_name
? channel.team_name
: getTeamByID(channel.team_id).name;
fields.props.attachments = [
createMessage(
SEVERITY_COLORS[params.event_nseverity] || 0,
params.event_date,
params.event_time,
createProblemURL(params.zabbix_url, params.trigger_id, params.event_id, params.event_source)
)
];
var resp = JSON.parse(req.Post(
Mattermost.post_message,
JSON.stringify(fields)
)
);
if (req.Status() != 201) {
throw '[{0}] {1}'.format(resp.status_code, resp.message);
}
result.tags.__mattermost_post_id = resp.id;
result.tags.__mattermost_channel_id = channel.id;
result.tags.__mattermost_channel_name = channel.name;
result.tags.__mattermost_message_link = getPermalink(
params.mattermost_url,
team_name,
resp.id
);
}
else if (isEventUpdate(params)) {
fields.root_id = getTagValue(params.event_tags, 'mattermost_post_id');
if (params.event_source === '0') {}
fields.props.attachments = [
createMessage(
SEVERITY_COLORS[params.event_nseverity] || 0,
params.event_update_date,
params.event_update_time,
createProblemURL(params.zabbix_url, params.trigger_id, params.event_id, params.event_source),
true
)
];
resp = JSON.parse(req.Post(
Mattermost.post_message, JSON.stringify(fields)
)
);
if (req.Status() != 201) {
throw '[{0}] {1}'.format(resp.status_code, resp.message);
}
}
else if (isEventResolve(params)) {
fields.channel_id = getTagValue(params.event_tags, 'mattermost_channel_id');
fields.id = getTagValue(params.event_tags, 'mattermost_post_id');
fields.props.attachments = [
createMessage2(
RESOLVE_COLOR,
params.event_date,
params.event_time,
createProblemURL(params.zabbix_url, params.trigger_id, params.event_id, params.event_source)
)
];
var post_id = getTagValue(params.event_tags, 'mattermost_post_id');
resp = JSON.parse(req.Put(
Mattermost.chat_update.format(post_id),
JSON.stringify(fields)
)
);
if (req.Status() != 200) {
throw '[{0}] {1}'.format(resp.status_code, resp.message);
}
}
}
function handlerEvent(req, params) {
var channel = getChannel(params.send_to);
var fields = {
channel_id: channel.id,
props: {}
};
if (isEventProblem(params)) {
var team_name = channel.team_name
? channel.team_name
: getTeamByID(channel.team_id).name;
fields.props.attachments = [
createMessage(
SEVERITY_COLORS[params.event_nseverity] || 0,
params.event_date,
params.event_time,
createProblemURL(params.zabbix_url, params.trigger_id, params.event_id, params.event_source)
)
];
var resp = JSON.parse(req.Post(Mattermost.post_message, JSON.stringify(fields)));
if (req.Status() != 201) {
throw '[{0}] {1}'.format(resp.status_code, resp.message);
}
result.tags.__mattermost_channel_name = channel.name;
result.tags.__mattermost_message_link = getPermalink(
params.mattermost_url,
team_name,
resp.id
);
}
else if (isEventUpdate(params)) {
fields.props.attachments = [
createMessage(
SEVERITY_COLORS[params.event_nseverity] || 0,
params.event_update_date,
params.event_update_time,
createProblemURL(params.zabbix_url, params.trigger_id, params.event_id, params.event_source),
false
)
];
resp = JSON.parse(req.Post(Mattermost.post_message, JSON.stringify(fields)));
if (req.Status() != 201) {
throw '[{0}] {1}'.format(resp.status_code, resp.message);
}
}
else if (isEventResolve(params)) {
fields.props.attachments = [
createMessage2(
RESOLVE_COLOR,
params.event_recovery_date,
params.event_recovery_time,
createProblemURL(params.zabbix_url, params.trigger_id, params.event_id, params.event_source)
)
];
resp = JSON.parse(req.Post(Mattermost.post_message2, JSON.stringify(fields)));
if (req.Status() != 201) {
throw '[{0}] {1}'.format(resp.status_code, resp.message2);
}
}
}
// 从这里开始就是设置 恢复状态 信息格式的地方
function createMessage2(
event_severity_color,
event_date,
event_time,
problem_url,
isShort
) {
var message2 = {
fallbac: params.alert_subject,
title: params.alert_subject,
color: event_severity_color,
footer: "最终解释权归运维所有", // 这里是信息下标,
fields: [
{
title: 'IP:',
value: '{0}'.format(params.host_ip),
short: true
},
{
title: '解决时间:',
value: '{0} {1}'.format(event_date, event_time),
short: true
}
],
};
if (params.event_source === '0') {
message2.fields.push(
{
title: '严重程度',
value: params.event_severity,
short: true
}
);
}
if (!isShort && params.event_source === '0') {
message2.fields.push(
{
title: '状态',
value: '已解决',
short: true
}
);
}
if (params.event_source !== '0' || params.event_update_status === '1') {
message2.fields.push(
{
title: 'Details',
value: params.alert_message,
short: false
}
);
}
return message2;
}
// 这里是设置 报警状态 信息格式的位置
function createMessage(
event_severity_color,
event_date,
event_time,
problem_url,
isShort
) {
var message = {
fallbac: params.alert_subject,
title: params.alert_subject,
color: event_severity_color,
footer: "最终解释权归运维所有",
fields: [
{
title: 'IP:',
value: '{0}'.format(params.host_ip),
short: true
},
{
title: '发生时间:',
value: '{0} {1}'.format(event_date, event_time),
short: true
}
],
};
if (params.event_source === '0') {
message.fields.push(
{
title: '严重程度',
value: params.event_severity,
short: true
}
);
}
if (!isShort && params.event_source === '0') {
message.fields.push(
{
title: '告警描述',
value: params.trigger_description,
short: true
}
);
}
if (params.event_source !== '0' || params.event_update_status === '1') {
message.fields.push(
{
title: 'Details',
value: params.alert_message,
short: false
}
);
}
return message;
}
function validateParams(params) {
if (typeof params.bot_token !== 'string' || params.bot_token.trim() === '') {
throw 'Field "bot_token" cannot be empty';
}
if (isNaN(params.event_id)) {
throw 'Field "event_id" is not a number';
}
if ([0, 1, 2, 3].indexOf(parseInt(params.event_source)) === -1) {
throw 'Incorrect "event_source" parameter given: "' + params.event_source + '".\nMust be 0-3.';
}
if (params.event_source !== '0') {
params.event_nseverity = '0';
params.event_severity = 'Not classified';
params.event_update_status = '0';
params.send_mode = 'event';
}
if (params.event_source === '1' || params.event_source === '2') {
params.event_value = '1';
}
if (params.event_source === '1') {
params.host_name = params.discovery_host_dns;
params.host_ip = params.discovery_host_ip;
}
if ([0, 1, 2, 3, 4, 5].indexOf(parseInt(params.event_nseverity)) === -1) {
throw 'Incorrect "event_nseverity" parameter given: ' + params.event_nseverity + '\nMust be 0-5.';
}
if (typeof params.event_severity !== 'string' || params.event_severity.trim() === '') {
throw 'Field "event_severity" cannot be empty';
}
if (params.event_update_status !== '0' && params.event_update_status !== '1') {
throw 'Incorrect "event_update_status" parameter given: ' + params.event_update_status + '\nMust be 0 or 1.';
}
if (params.event_value !== '0' && params.event_value !== '1') {
throw 'Incorrect "event_value" parameter given: ' + params.event_value + '\nMust be 0 or 1.';
}
if (typeof params.host_ip !== 'string' || params.host_ip.trim() === '') {
throw 'Field "host_ip" cannot be empty';
}
if (typeof params.host_name !== 'string' || params.host_name.trim() === '') {
throw 'Field "host_name" cannot be empty';
}
if (typeof params.mattermost_url !== 'string' || params.mattermost_url.trim() === '') {
throw 'Field "mattermost_url" cannot be empty';
}
if (!/^(http|https):\/\/.+/.test(params.mattermost_url)) {
throw 'Field "mattermost_url" must contain a schema';
}
if (['alarm', 'event'].indexOf(params.send_mode) === -1) {
throw 'Incorrect "send_mode" parameter given: ' + params.send_mode + '\nMust be "alarm" or "event".';
}
if (typeof params.send_to !== 'string' || params.send_to.trim() === '') {
throw 'Field "send_to" cannot be empty';
}
if (isNaN(params.trigger_id) && params.event_source === '0') {
throw 'field "trigger_id" is not a number';
}
if (typeof params.zabbix_url !== 'string' || params.zabbix_url.trim() === '') {
throw 'Field "zabbix_url" cannot be empty';
}
if (!/^(http|https):\/\/.+/.test(params.zabbix_url)) {
throw 'Field "zabbix_url" must contain a schema';
}
}
try {
var params = JSON.parse(value);
validateParams(params);
var req = new CurlHttpRequest(),
fields = {},
result = {tags: {}};
if (typeof params.HTTPProxy === 'string' && params.HTTPProxy.trim() !== '') {
req.SetProxy(params.HTTPProxy);
}
req.AddHeader('Content-Type: application/json; charset=utf-8');
req.AddHeader('Authorization: Bearer ' + params.bot_token);
params.mattermost_url = params.mattermost_url.replace(/\/+$/, '');
params.zabbix_url = params.zabbix_url.replace(/\/+$/, '');
var APIEndpoint = params.mattermost_url + '/api/v4/';
var Mattermost = {
post_message: APIEndpoint + 'posts',
get_channel: APIEndpoint + 'channels/{0}',
get_team: APIEndpoint + 'teams/{0}',
chat_update: APIEndpoint + 'posts/{0}',
direct_channel: APIEndpoint + 'channels/direct',
channel_byname: APIEndpoint + 'teams/name/{0}/channels/name/{1}',
user_byname: APIEndpoint + 'users/username/{0}',
bot_user: APIEndpoint + 'users/me'
};
params.send_mode = params.send_mode.toLowerCase();
params.send_mode = params.send_mode in SEND_MODE_HANDLERS
? params.send_mode
: 'alarm';
SEND_MODE_HANDLERS[params.send_mode](req, params);
if (params.event_source === '0') {
return JSON.stringify(result);
}
else {
return 'OK';
}
}
catch (error) {
Zabbix.Log(4, '[ Mattermost Webhook ] Mattermost notification failed: ' + error);
throw 'Mattermost notification failed: ' + error;
}
5、添加用户
用户的类型有管理员和超级管理员
添加用户
为用户添加报警媒介
如果用户没有添加报警媒介则无法使用该媒介进行报警2
为用户添加主机权限
刚添加的用户是无法看到已经监控的任何一台服务器的,原因是没有赋予用户权限
此时再将用户添加至这个用户组中,再进行登录,就可以看到那些服务器了
6、添加动作
Zabbix 的动作,主要作用是当触发器被触发后,执行相关操作的。
要创建动作需要有两个必须的元素:
-
条件 规定什么情况下执行此动作
-
操作 动作具体操作什么
操作可以是:
发送通知 执行系统的内部命令 操作可以是多个步骤,是按照设置好的顺序依次执行的。
发送通知 和 执行内部命令 可以单独使用他们,也可以让两者一起配合使用。 比如可以在服务器意外停止的时候,先执行 一个内部命令,假如执行命令后,服务仍然没有恢复为 正常状态。则可以再发送一个通知。
添加动作
关于步骤就是起始步骤到下一个步骤,假如执行的步骤只有一步,这里可以选择
1 - 1
步骤持续时间 是此步骤执行完毕需要多长时间,比如发送一封电子邮件可能需要 1 秒,删除一些没有的文件需要 1 分钟,重启一个 Java 的应用程序需要 5 分钟等。 但是这里的取值只能是 0 或者 60-604800(单位是秒) 其中的一个。 这里设置的时间会覆盖之前的 默认操作步骤持续时间,假设这里使用 0, 就会使用之前的 默认操作步骤持续时间 的值(默认是 1h)
发送消息可以是一个或多个组,也可以是一个或多个具体的用户。 这里我仅仅选择一个我之前创建的用户
shark
仅送到
仅送到
这里就是选择以那种 报警媒介 发送通知消息
一个用户是可以有多个 报警媒介 的,比如电子邮件,企业微信、钉钉等。
可以选择所有的,也可以i选择某一个。
这里我选择的是之前创建的报警媒介。如下图:
Custom message 是否在这里自定义消息,假如这里设置了,就会覆盖在 报警媒介类型中设置的消息模板。这里我们不做进一步的操作。
条件 这个需要为此此操作步骤设置一个触发条件 此步骤不是必须的
验证动作是否触发
注意:假如你设置了这个动作之前,触发器已经被触发了,并且当前获取的数据之一处于触发器指标的外部,则触发器不会重复产生事件,只能等触发器再次被触发产生新的问题才行。如下图就是这种情况:
7、可视化
zabbix 提供了众多的可视化工具直观展示,如 graph、screen 及 map 等。前面也看到过一些简单的图形展示。如果想要把多个相关的数据定义在同一张图上去查看,就需要去自定义图形
自定义图形中可以集中展示多个时间序列的数据流。支持四种不同形式的图形
线状图(normal)
堆叠面积图(stacked)、
饼图(pie)”
分离型饼图(exploded)
添加自定义图形
设置过程如下:进入 配置 ---> 主机 ---> node1 ---> 图形,选择右上角创建图形:
聚合图形
幻灯片
拓扑图
在拓扑图中,可以定义成一个复杂的网络连接图,可以使用一台主机来连接另一台主机,这样的话,就可以查看出到底是哪个链接出了问题
8、自定义模板
每一个主机的监控项都很多,一个一个的添加实在是太头疼了,更何况,可能不止一个主机。可以把一个 redis 的监控项添加进一个模板里,这样更方便于我们以后的添加。
创建模板
模板中的监控项、触发器等的添加和上面的步骤一样
使用自定义模板
也可以在创建主机时直接使用已有模板
9、宏
宏是一种抽象(Abstraction),它根据一系列预定义的规则替换一定的文本模式,而解释器或编译器在遇到宏时会自动进行这一模式替换。类似地,zabbix基于宏保存预设文本模式,并且在调用时将其替换为其中的文本。
zabbix有许多内置的宏,如{HOST.NAME}、{HOST.IP}、{TRIGGER.DESCRIPTION}、{TRIGGER.NAME}、{TRIGGER.EVENTS.ACK}等。
详细信息请参考官方文档
就是定义一个变量 起一个值
宏一共有三种级别,分别是全局宏、模板宏、主机宏。不同级别的宏的适用范围也不一样。
全局宏也可以作用于所有的模板宏和主机宏,优先级最低。
模板宏则可以作用于所有使用该模板的主机,优先级排在中间。
主机宏则只对单个主机有效,优先级最高。
宏的类型
宏的类型分为系统内建的宏和用户自定义的宏。
为了更强的灵活性,zabbix还支持在全局、模板或主机级别使用用户自定义宏(user macro)。
系统内建的宏在使用的时候需要
{MACRO}
的语法格式,用户自定义宏要使用{$MACRO}
这种特殊的语法格式。宏可以应用在item keys和descriptions、trigger名称和表达式、主机接口IP/DNS及端口、discovery机制的SNMP协议的相关信息中……
宏的名称只能使用大写字母、数字及下划线。
进一步信息请参考官方文档。
定义宏
全局宏
模板宏和主机宏和上述方法类似,一个在模板里面找,一个在主机里面找
使用宏
可以在任何地方使用
使用效果
10、监控项自动发现(LLD)
自动发现(LLD)提供了一种为受监控节点的不同监控指标自动创建监控项,触发器和图形的分发;此外还可以配置 Zabbix 根据定期执行发现后得到的实际结果,来移除不需要的监控。
暂时只用到了系统自带的一些监控,并没有自己创建的需求,所以暂不做,如有想法可以百度。
三、用户参数(自定义key)
自定义用户参数,也就是自定义key,有时可能想要运行一个代理检查,而不是 Zabbix 的预定义,就可以编写一个命令来检索需要的数据,并将其包含在代理配置文件("UserParameter"配置参数)的用户参数中
1、格式
UserParameter=<key>,<command>
# 等号右边固定,key就类似于net.tcp.listen,command就是linux中的命令
# 配置完成后需要重新启动agent端
、用法展示
选择一个命令,例如free | awk '/^Mem/{print $3}'
添加用户参数
cd /etc/zabbix/zabbix_agentd.d/
vim memory_usage.conf
UserParameter=memory.used,free | awk '/^Mem/{print $3}'
# 重启服务
systemctl restart zabbix-agent.service
# 在server端查询
zabbix_get -s agent端的IP -p 10050 -k "memory.used"
# 这个命令在agent源码包解压后的bin目录中
在监控项中使用该参数
3、升级版用法(带参数的监控项)
添加一个带参数的key
先找到一个命令,例如
cat /proc/meminfo
添加用户参数
cd /etc/zabbix/zabbix_agentd.d/
vim memory_usage.conf
UserParameter=memory.stats[*],cat /proc/meminfo | awk '/^$1/{print $$2}'
# $$2:表示不是调前边位置参数的$2 ,而是 awk 的参数 $2
# $1是调用前边的[*],位置参数,第一个参数
# 重启服务
systemctl restart zabbix-agent.service
# 在server端查询
./zabbix_get -s 10.9.29.117 -p 10050 -k "memory.stats[MemTotal]"
> 1863252
./zabbix_get -s 10.9.29.117 -p 10050 -k "memory.stats[Cache]"
> 133400
四、网络发现
设置自动发现规则
五、agent端各种监控方式
主动与被动都是对于agent端而言的
被动检测:server向agent请求获取配置的各监控项相关的数据,agent接收请求、获取数据并响应给server;
主动检测:agent向server请求与自己相关监控项配置,主动地将server配置的监控项相关的数据发送给server;
前面介绍的都是被动模式
1、主动监控
配置
# 配置文件中
vim /etc/zabbix/zabbix_agentd.conf
# 给哪个监控server 发送数据
ServerActive=serverIP
Hostname=node1.qfedu.com # 自己的主机名,假设主机定死了,不设置下一项
#HostnameItem= # 如果自己的主机名易变动,这一项相当于key一样去匹配
# 若后两项同时启用,下边一个选择生效
设置一个主动监控
主动模式下,右侧ZBX不会亮起
使用sender手动发送数据
首先需要配置一个采集器
zabbix_sender
-z zabbix_server_ip
-p zabbix_server_port
-s zabbix_agent_hostname
-k key
-o value 值
zabbix_sender -z 10.9.29.116 -p 10050 -s song1 -k system.cpu.switches -o 9999
2、snmp方式
SNMP:简单网络管理协议;(非常古老的协议)
三种通信方式:读(get, getnext)、写(set)、trap(陷阱);
端口:161/udp 162/udp
为无法安装agent服务的设备使用,例如交换机,路由器
linux启用snmp
# 安装
yum install net-snmp net-snmp-utils
# 配置文件:定义ACL(访问控制列表)
vim /etc/snmp/snmpd.conf
# 可用的视图 OID
# 示例:.1.3.6.1.2.1.1.1.0 系统描述信息
.1.3.6.1.2.1.
1.1.0:系统描述信息,SysDesc
1.3.0:监控时间, SysUptime
1.5.0:主机名,SysName
1.7.0:主机提供的服务,SysService
.1.3.6.1.2.2.
2.1.0:网络接口数目
2.2.1.2:网络接口的描述信息
2.2.1.3:网络接口类型
# 启动
# 被监控端开启的服务
systemctl start snmpd
# 监控端开启的服务(如果允许被监控端启动主动监控时启用)
systemctl start snmptrapd
# 测试
snmpget -v 2c -c public 被测试主机的IP OID
snmpwalk -v 2c -c public HOST OID # 通过这个端口查询到的数据,全列出了
# 例子
snmpget -v 2c -c public 10.9.29.117 .1.3.6.1.2.1.1.1.0
> SNMPv2-MIB::sysDescr.0 = STRING: Linux tomcat2 3.10.0-957.el7.x86_64 #1 SMP Thu Nov 8 23:39:32 UTC 2018 x86_64
snmpwalk -v 2c -c public 10.9.29.117 .1.3.6.1.2.1.1.1.0
> SNMPv2-MIB::sysDescr.0 = STRING: Linux tomcat2 3.10.0-957.el7.x86_64 #1 SMP Thu Nov 8 23:39:32 UTC 2018 x86_64
snmpwalk -v 2c -c public 10.9.29.117 .1.3.6.1.2.1.1.1.1
> SNMPv2-MIB::sysDescr.1 = No Such Instance currently exists at this OID
配置snmp监控
# 添加视图
vim /etc/snmp/snmpd.conf
view systemview included .1.3.6.1.2.1.1
view systemview included .1.3.6.1.2.1.2 # 网络接口的相关数据
view systemview included .1.3.6.1.4.1.2021 # 系统资源负载,memory, disk io, cpu load
view systemview included .1.3.6.1.2.1.25
可以添加以下模板,方便观察
设置入站出站packets 的SNMP监控
监控网络设备:交换机、路由器的步骤:
把交换机、路由器的SNMP 把对应的OID的分支启用起来
了解这些分支下有哪些OID,他们分别表示什么意义
我们要监控的某一数据:如交换机的某一个接口流量、报文,发送、传入传出的报文数有多少个;传入传出的字节数有多少个,把OID取出来,保存
# 入站
interface traffic packets(in)
# 出站
interface traffic packets(out)
六、分布式监控
Zabbix代理可以代表Zabbix服务器收集性能和可用性数据。这样,代理可以承担一些收集数据的负担,并减轻Zabbix服务器的负担。
1、添加zabbix-proxy主机—服务器设置
# 安装zabbix-proxy
rpm -Uvh https://repo.zabbix.com/zabbix/5.0/rhel/7/x86_64/zabbix-release-5.0-1.el7.noarch.rpm
yum -y install zabbix-proxy-mysql zabbix-get zabbix-agent zabbix-sender
# 为zabbix-proxy配置数据库,该数据库必须是独立的,不能和server端使用一个
create database zabbix_proxy character set utf8 collate utf8_bin;
create user zabbix@localhost identified by 'password';
grant all privileges on zabbix_proxy.* to zabbix@localhost;
# 导入数据
zcat /usr/share/doc/zabbix-proxy-mysql*/schema.sql.gz | mysql -uzabbix -p密码 zabbix_proxy
# 配置zabbix-proxy
vi /etc/zabbix/zabbix_proxy.conf
# 数据库信息
DBHost=localhost
DBName=zabbix_proxy
DBUser=zabbix
DBPassword=密码
# 配置服务
# 代理模式 0 主动上报给 Zabbix Server, 1 被动,默认 0
ProxyMode=0
Server=Zabbix 服务器的IP
# 唯一的、区分大小写的代理名称。确保服务器知道代理名称!如果未定义,则从HostnameItem获取值。
Hostname=bj-proxy
# 允许日志文件最大多少 MB, 默认是 0,就是不限制大小,也就是不进行日志切割
LogFileSize=2
# 即使数据已经与服务器同步,代理也会在本地保留N个小时。如果第三方应用程序将使用本地数据,则可以使用此参数。默认 0
ProxyLocalBuffer=0
# 如果没有与Zabbix服务器连接,代理将保留数据N小时。旧数据将丢失。默认 1
ProxyOfflineBuffer=1
# 心跳消息的频率(秒)。用于监控服务器端代理的可用性。0-已禁用心跳消息。对于处于被动模式的代理,此参数将被忽略。默认 60
HeartbeatFrequency=60
# 向服务端更新监控配置的间隔时间。为了快速看到实验效果,这里设置5秒,默认3600秒
ConfigFrequency=5
# 向服务端发送监控数据的间隔时间,单位秒
DataSenderFrequency=5
# 启动服务
systemctl start zabbix-proxy.service
# 在被zabbix-proxy监控的agent端将IP设置为zabbix-proxy的IP
vi /etc/zabbix/zabbix_agentd.conf
# Zabbix Proxy 的 IP
Server=192.168.122.100
# 假如开启了 agent 的主动模式,这里也是 Zabbix Proxy 的 IP
ServerActive=192.168.122.100
2、页面设置
3、为proxy添加监控主机
这里嫌麻烦直接修改已有主机,添加新的也很简单,自己摸索
修改完毕后,如果数据正常输出,就表示成功
七、开始监控
1、监控php-fpm服务状态
# 下载php-fpm
yum -y install php-fpm
# 打开php-fpm的状态页面
vim /etc/php-fpm.d/www.conf
user = nginx
group = nginx
pm.status_path = /status # php-fpm 的状态监测页面
ping.path = /ping # ping 接口,存活状态是否ok
ping.response = pong # 响应内容pong
# 开启服务
systemctl start php-fpm
# 设置nginx
vim /etc/nginx/nginx.conf
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location ~* /(status|ping) {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
include fastcgi_params;
allow 127.0.0.1; # 因为这个页面很重要,所有需加访问控制
deny all;
access_log off; # 访问这个页面就不用记录日志了
}
# 复制状态信息页面到网站根目录
cp /usr/share/fpm/status.html /usr/share/nginx/html/
# 开启nginx
systemctl start nginx
# 查看状态
curl 127.0.0.1/status
# 添加用户参数
cd /etc/zabbix/zabbix_agentd.d/
vim php_status.conf
UserParameter=php-fpm.stats[*],curl -s http://127.0.0.1/status | awk '/^$1/{print $$NF}'
# 设置用户参数为php-fpm.stats[*],$1为第一个参数;$$NF为awk中的参数,倒数第一列
# 重启服务
systemctl restart zabbix-agent
# 在server端检查
./zabbix_get -s 10.9.29.117 -p 10050 -k "php-fpm.stats[idle]"
./zabbix_get -s 10.9.29.117 -p 10050 -k "php-fpm.stats[active]"
./zabbix_get -s 10.9.29.117 -p 10050 -k "php-fpm.stats[max active]"
# 后续添加监控项自行解决
2、web服务器监控
例如nginx,httpd,监测流量,上传速度,下载速度,并发数
创建web监控
查看web监控
3、监控tomcat
Java虚拟机(JVM)具有内置的插件,使您能够使用JMX监视和管理它。您还可以使用JMX监视工具化的应用程序。
# server端
# 安装 zabbix-java-gateway程序包
yum -y install zabbix-java-gateway
# 配置javagateway
vim /etc/zabbix/zabbix_java_gateway.conf # 安装完后,会生成一个java_gateway 的配置文件
LISTEN_IP="0.0.0.0" #监听服务器地址
LISTEN_PORT=10052 #监听zabbix_java进程的端口,默认是10052
PID_FILE="/tmp/zabbix_java.pid" #zabbix_java的pid路径
START_POLLERS=5 #zabbix_java的进程数
TIMEOUT=10 #zabbix_java的超时时间
# 可不用修改,直接开启服务
systemctl start zabbix-java-gateway.service
# 设置server端
vim /etc/zabbix/zabbix_server.conf
JavaGateway=172.16.0.70 #即 zabbix server IP地址
JavaGatewayPort=10052
StartJavaPollers=5 #监控项
# 重启服务
systemctl restart zabbix-server
# agent端
# 在agent端安装tomcat
yum -y install java-1.8.0-openjdk-devel tomcat-admin-webapps tomcat-docs-webapp
# 配置tomcat
vim /etc/sysconfig/tomcat
CATALINA_OPTS="-Djava.rmi.server.hostname=本机IP -Djavax.management.builder.initial= -Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.port=12345 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false"
# 启动服务
systemctl start tomcat
页面设置
然后稍候片刻,如果配置没错就可以看到JMX变绿,且可以查看到最新数据
4、监控mysql
需求一:监控MySQL的状态,当状态发生异常,发出报警;
需求二:监控MySQL的操作,并用图表展现;
存活监测
# 创建一个普通用户,并授权
grant usage on *.* to [email protected] identified by 'QFedu@123';
# 创建一个包含用户名和密码的文件
mkdir /var/lib/zabbix/
vim /var/lib/zabbix/.my.cnf
[mysqladmin]
user=zabbix
host=127.0.0.1
password='QFedu@123'
# 使用这个命令监测
HOME=/var/lib/zabbix/ mysqladmin ping |grep -c alive
# 存活输出1 不存活输出2
# 添加自定义key
vim /etc/zabbix/zabbix_agentd.d/userparameter_mysql.conf
UserParameter=mysql.ping,HOME=/var/lib/zabbix mysqladmin ping | grep -c alive
# 检查命令是否正常
/usr/sbin/zabbix_agentd -t mysql.ping
> mysql.ping [t|1]
# 重启服务
systemctl restart zabbix-agent.service
# 在server端检查
./zabbix_get -s 10.9.29.117 -p 10050 -k "mysql.ping"
其他性能监测
使用一个自定义的shell脚本来进行监测
# 添加一个自定义的key
vim /etc/zabbix/zabbix_agentd.d/userparameter_mysql.conf
# 监控mysql性能的脚本
UserParameter=mysql.status[*],/etc/zabbix/zabbix_agentd.d/check_mysql.sh $1
# 查看版本
UserParameter=mysql.version,mysql -V
# 脚本内容
vim /etc/zabbix/zabbix_agentd.d/check_mysql.sh
#!/bin/bash
# -------------------------------------------------------------------------------
# FileName: check_mysql.sh
# Revision: 1.0
# -------------------------------------------------------------------------------
# Copyright:
# License: GPL
# 用户名
MYSQL_USER='zabbix'
# 密码
MYSQL_PWD='QFedu@123'
# 主机地址/IP
MYSQL_HOST='127.0.0.1'
# 端口
MYSQL_PORT='3306'
# 数据连接
MYSQL_CONN="/usr/bin/mysqladmin -u${MYSQL_USER} -p${MYSQL_PWD} -h${MYSQL_HOST} -P${MYSQL_PORT}"
# 参数是否正确
if [ $# -ne "1" ];then
echo "arg error!"
fi
# 获取数据
case $1 in
Uptime)
result=`${MYSQL_CONN} status 2>/dev/null |cut -f2 -d":"|cut -f1 -d"T"`
echo $result
;;
Com_update)
result=`${MYSQL_CONN} extended-status 2>/dev/null |grep -w "Com_update"|cut -d"|" -f3`
echo $result
;;
Slow_queries)
result=`${MYSQL_CONN} status 2>/dev/null |cut -f5 -d":"|cut -f1 -d"O"`
echo $result
;;
Com_select)
result=`${MYSQL_CONN} extended-status 2>/dev/null |grep -w "Com_select"|cut -d"|" -f3`
echo $result
;;
Com_rollback)
result=`${MYSQL_CONN} extended-status 2>/dev/null |grep -w "Com_rollback"|cut -d"|" -f3`
echo $result
;;
Questions)
result=`${MYSQL_CONN} status 2>/dev/null |cut -f4 -d":"|cut -f1 -d"S"`
echo $result
;;
Com_insert)
result=`${MYSQL_CONN} extended-status 2>/dev/null |grep -w "Com_insert"|cut -d"|" -f3`
echo $result
;;
Com_delete)
result=`${MYSQL_CONN} extended-status 2>/dev/null |grep -w "Com_delete"|cut -d"|" -f3`
echo $result
;;
Com_commit)
result=`${MYSQL_CONN} extended-status 2>/dev/null |grep -w "Com_commit"|cut -d"|" -f3`
echo $result
;;
Bytes_sent)
result=`${MYSQL_CONN} extended-status 2>/dev/null |grep -w "Bytes_sent" |cut -d"|" -f3`
echo $result
;;
Bytes_received)
result=`${MYSQL_CONN} extended-status 2>/dev/null |grep -w "Bytes_received" |cut -d"|" -f3`
echo $result
;;
Com_begin)
result=`${MYSQL_CONN} extended-status 2>/dev/null |grep -w "Com_begin"|cut -d"|" -f3`
echo $result
;;
*)
echo "Usage:$0(Uptime|Com_update|Slow_queries|Com_select|Com_rollback|Questions|Com_insert|Com_delete|Com_commit|Bytes_sent|Bytes_received|Com_begin)"
;;
esac
# 授权
chmod +x /etc/zabbix/zabbix_agentd.d/check_mysql.sh
chown zabbix.zabbix /etc/zabbix/zabbix_agentd.d/check_mysql.sh
# 在server端检查
./zabbix_get -s 10.9.29.117 -p 10050 -k "mysql.status[Com_update]"
./zabbix_get -s 10.9.29.117 -p 10050 -k "mysql.status[Uptime]"
5.0版本新方法
上面的只是给你提示可以这么做,在新版本中,操作更为便利
然后,下载模板文件,或者直接复制
# 创建一个包含用户名和密码的文件
mkdir /var/lib/zabbix/
vim /var/lib/zabbix/.my.cnf
[mysqladmin]
user=zabbix
host=127.0.0.1
password='QFedu@123'
# 或者你懒得去看,直接复制这个
vim /etc/zabbix/zabbix_agentd.d/Template_DB_MySQL.conf
#template_db_mysql.conf created by Zabbix for "Template DB MySQL" and Zabbix 4.2
#For OS Linux: You need create .my.cnf in zabbix-agent home directory (/var/lib/zabbix by default)
#For OS Windows: You need add PATH to mysql and mysqladmin and create my.cnf in %WINDIR%\my.cnf,C:\my.cnf,BASEDIR\my.cnf https://dev.mysql.com/doc/refman/5.7/en/option-files.html
#The file must have three strings:
#[client]
#user='zbx_monitor'
#password='<password>'
#
UserParameter=mysql.ping[*], mysqladmin -h"$1" -P"$2" ping
UserParameter=mysql.get_status_variables[*], mysql -h"$1" -P"$2" -sNX -e "show global status"
UserParameter=mysql.version[*], mysqladmin -s -h"$1" -P"$2" version
UserParameter=mysql.db.discovery[*], mysql -h"$1" -P"$2" -sN -e "show databases"
UserParameter=mysql.dbsize[*], mysql -h"$1" -P"$2" -sN -e "SELECT COALESCE(SUM(DATA_LENGTH + INDEX_LENGTH),0) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='$3'"
UserParameter=mysql.replication.discovery[*], mysql -h"$1" -P"$2" -sNX -e "show slave status"
UserParameter=mysql.slave_status[*], mysql -h"$1" -P"$2" -sNX -e "show slave status"
# 重启服务
systemctl restart zabbix-agent.service
八、常用自定义监控项
1、mysql
version:数据库版本
key_buffer_size:myisam的索引buffer大小
sort_buffer_size:会话的排序空间(每个线程会申请一个)
join_buffer_size:这是为链接操作分配的最小缓存大小,这些连接使用普通索引扫描、范围扫描、或者连接不适用索引
max_connections:最大允许同时连接的数量
max_connect_errors:允许一个主机最多的错误链接次数,如果超过了就会拒绝之后链接(默认100)。可以使用flush hosts命令去解除拒绝
open_files_limits:操作系统允许mysql打开的文件数量,可以通过opened_tables状态确定是否需要增大table_open_cache,如果opened_tables比较大且一直还在增大说明需要增大table_open_cache
max-heap_tables_size:建立的内存表的最大大小(默认16M)这个参数和tmp_table_size一起限制内部临时表的最大值(取这两个参数的小的一个),如果超过限制,则表会变为innodb或myisam引擎,(5.7.5之前是默认是myisam,5.7.6开始是innodb,可以通过internal_tmp_disk_storage_engine参数调整)。
max_allowed_packet:一个包的最大大小
##########GET INNODB INFO
#INNODB variables
innodb_version:
innodb_buffer_pool_instances:将innodb缓冲池分为指定的多个(默认为1)
innodb_buffer_pool_size:innodb缓冲池大小、5.7.5引入了innodb_buffer_pool_chunk_size,
innodb_doublewrite:是否开启doublewrite(默认开启)
innodb_read_io_threads:IO读线程的数量
innodb_write_io_threads:IO写线程的数量
########innodb status
innodb_buffer_pool_pages_total:innodb缓冲池页的数量、大小等于innodb_buffer_pool_size/(16*1024)
innodb_buffer_pool_pages_data:innodb缓冲池中包含数据的页的数量
########## GET MYSQL HITRATE
1、查询缓存命中率
如果Qcache_hits+Com_select<>0则为 Qcache_hits/(Qcache_hits+Com_select),否则为0
2、线程缓存命中率
如果Connections<>0,则为1-Threads_created/Connections,否则为0
3、myisam键缓存命中率
如果Key_read_requests<>0,则为1-Key_reads/Key_read_requests,否则为0
4、myisam键缓存写命中率
如果Key_write_requests<>0,则为1-Key_writes/Key_write_requests,否则为0
5、键块使用率
如果Key_blocks_used+Key_blocks_unused<>0,则Key_blocks_used/(Key_blocks_used+Key_blocks_unused),否则为0
6、创建磁盘存储的临时表比率
如果Created_tmp_disk_tables+Created_tmp_tables<>0,则Created_tmp_disk_tables/(Created_tmp_disk_tables+Created_tmp_tables),否则为0
7、连接使用率
如果max_connections<>0,则threads_connected/max_connections,否则为0
8、打开文件比率
如果open_files_limit<>0,则open_files/open_files_limit,否则为0
9、表缓存使用率
如果table_open_cache<>0,则open_tables/table_open_cache,否则为0
2、redis
vim /usr/local/zabbix/etc/zabbix_agentd.conf.d/redis.conf
UserParameter=Redis.Status,/usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 6379 ping |grep -c PONG
UserParameter=Redis_conn[*],/usr/local/redis/bin/redis-cli -h $1 -p $2 info | grep -w "connected_clients" | awk -F':' '{print $2}'
UserParameter=Redis_rss_mem[*],/usr/local/redis/bin/redis-cli -h $1 -p $2 info | grep -w "used_memory_rss" | awk -F':' '{print $2}'
UserParameter=Redis_lua_mem[*],/usr/local/redis/bin/redis-cli -h $1 -p $2 info | grep -w "used_memory_lua" | awk -F':' '{print $2}'
UserParameter=Redis_cpu_sys[*],/usr/local/redis/bin/redis-cli -h $1 -p $2 info | grep -w "used_cpu_sys" | awk -F':' '{print $2}'
UserParameter=Redis_cpu_user[*],/usr/local/redis/bin/redis-cli -h $1 -p $2 info | grep -w "used_cpu_user" | awk -F':' '{print $2}'
UserParameter=Redis_cpu_sys_cline[*],/usr/local/redis/bin/redis-cli -h $1 -p $2 info | grep -w "used_cpu_sys_children" | awk -F':' '{print $2}'
UserParameter=Redis_cpu_user_cline[*],/usr/local/redis/bin/redis-cli -h $1 -p $2 info | grep -w "used_cpu_user_children" | awk -F':' '{print $2}'
UserParameter=Redis_keys_num[*],/usr/local/redis/bin/redis-cli -h $1 -p $2 info | grep -w "$$1" | grep -w "keys" | grep db$3 | awk -F'=' '{print $2}' | awk -F',' '{print $1}'
UserParameter=Redis_loading[*],/usr/local/redis/bin/redis-cli -h $1 -p $2 info | grep loading | awk -F':' '{print $$2}'
Redis.Status --检测Redis运行状态, 返回整数
Redis_conn --检测Redis成功连接数,返回整数
Redis_rss_mem --检测Redis系统分配内存,返回整数
Redis_lua_mem --检测Redis引擎消耗内存,返回整数
Redis_cpu_sys --检测Redis主程序核心CPU消耗率,返回整数
Redis_cpu_user --检测Redis主程序用户CPU消耗率,返回整数
Redis_cpu_sys_cline --检测Redis后台核心CPU消耗率,返回整数
Redis_cpu_user_cline --检测Redis后台用户CPU消耗率,返回整数
Redis_keys_num --检测库键值数,返回整数
Redis_loding --检测Redis持久化文件状态,返回整数
3、nginx
vim /etc/nginx/conf.d/default.conf
location /nginx-status
{
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
vim /usr/local/zabbix/etc/zabbix_agentd.conf.d/nginx.conf
UserParameter=Nginx.active,/usr/bin/curl -s "http://127.0.0.1:80/nginx-status" | awk '/Active/ {print $NF}'
UserParameter=Nginx.read,/usr/bin/curl -s "http://127.0.0.1:80/nginx-status" | grep 'Reading' | cut -d" " -f2
UserParameter=Nginx.wrie,/usr/bin/curl -s "http://127.0.0.1:80/nginx-status" | grep 'Writing' | cut -d" " -f4
UserParameter=Nginx.wait,/usr/bin/curl -s "http://127.0.0.1:80/nginx-status" | grep 'Waiting' | cut -d" " -f6
UserParameter=Nginx.accepted,/usr/bin/curl -s "http://127.0.0.1:80/nginx-status" | awk '/^[ \t]+[0-9]+[ \t]+[0-9]+[ \t]+[0-9]+/ {print $1}'
UserParameter=Nginx.handled,/usr/bin/curl -s "http://127.0.0.1:80/nginx-status" | awk '/^[ \t]+[0-9]+[ \t]+[0-9]+[ \t]+[0-9]+/ {print $2}'
UserParameter=Nginx.requests,/usr/bin/curl -s "http://127.0.0.1:80/nginx-status" | awk '/^[ \t]+[0-9]+[ \t]+[0-9]+[ \t]+[0-9]+/ {print $3}'
4、TCP相关
vim /usr/local/zabbix/share/zabbix/alertscripts/tcp_connection.sh
#!/bin/bash
function ESTAB {
/usr/sbin/ss -ant |awk '{++s[$1]} END {for(k in s) print k,s[k]}' | grep 'ESTAB' | awk '{print $2}'
}
function TIMEWAIT {
/usr/sbin/ss -ant | awk '{++s[$1]} END {for(k in s) print k,s[k]}' | grep 'TIME-WAIT' | awk '{print $2}'
}
function LISTEN {
/usr/sbin/ss -ant | awk '{++s[$1]} END {for(k in s) print k,s[k]}' | grep 'LISTEN' | awk '{print $2}'
}
$1
vim /usr/local/zabbix/etc/zabbix_agentd.conf.d/cattcp.conf
UserParameter=tcp[*],/usr/local/zabbix/share/zabbix/alertscripts/tcp_connection.sh $1
tcp[TIMEWAIT] --检测TCP的驻留数,返回整数
tcp[ESTAB] --检测tcp的连接数、返回整数
tcp[LISTEN] --检测TCP的监听数,返回整数
5、系统常用自带监控项
agent.ping 检测客户端可达性、返回nothing表示不可达。1表示可达
system.cpu.load --检测cpu负载。返回浮点数
system.cpu.util -- 检测cpu使用率。返回浮点数
vfs.dev.read -- 检测硬盘读取数据,返回是sps.ops.bps浮点类型,需要定义1024倍
vfs.dev.write -- 检测硬盘写入数据。返回是sps.ops.bps浮点类型,需要定义1024倍
net.if.out[br0] --检测网卡流速、流出方向,时间间隔为60S
net-if-in[br0] --检测网卡流速,流入方向(单位:字节) 时间间隔60S
proc.num[] 目前系统中的进程总数,时间间隔60s
proc.num[,,run] 目前正在运行的进程总数,时间间隔60S
###处理器信息
通过zabbix_get 获取负载值
合理的控制用户态、系统态、IO等待时间剋保证进程高效率的运行
系统态运行时间较高说明进程进行系统调用的次数比较多,一般的程序如果系统态运行时间占用过高就需要优化程序,减少系统调用
io等待时间过高则表明硬盘的io性能差,如果是读写文件比较频繁、读写效率要求比较高,可以考虑更换硬盘,或者使用多磁盘做raid的方案
system.cpu.swtiches --cpu的进程上下文切换,单位sps,表示每秒采样次数,api中参数history需指定为3
system.cpu.intr --cpu中断数量、api中参数history需指定为3
system.cpu.load[percpu,avg1] --cpu每分钟的负载值,按照核数做平均值(Processor load (1 min average per core)),api中参数history需指定为0
system.cpu.load[percpu,avg5] --cpu每5分钟的负载值,按照核数做平均值(Processor load (5 min average per core)),api中参数history需指定为0
system.cpu.load[percpu,avg15] --cpu每5分钟的负载值,按照核数做平均值(Processor load (15 min average per core)),api中参数history需指定为0
6、系统常用自定义监控项
####内存相关
vim /usr/local/zabbix/etc/zabbix_agentd.conf.d/catcarm.conf
UserParameter=ram.info[*],/bin/cat /proc/meminfo |awk '/^$1:{print $2}'
ram.info[Cached] --检测内存的缓存使用量、返回整数,需要定义1024倍
ram.info[MemFree] --检测内存的空余量,返回整数,需要定义1024倍
ram.info[Buffers] --检测内存的使用量,返回整数,需要定义1024倍
####TCP相关的自定义项
vim /usr/local/zabbix/share/zabbix/alertscripts/tcp_connection.sh
#!/bin/bash
function ESTAB {
/usr/sbin/ss -ant |awk '{++s[$1]} END {for(k in s) print k,s[k]}' | grep 'ESTAB' | awk '{print $2}'
}
function TIMEWAIT {
/usr/sbin/ss -ant | awk '{++s[$1]} END {for(k in s) print k,s[k]}' | grep 'TIME-WAIT' | awk '{print $2}'
}
function LISTEN {
/usr/sbin/ss -ant | awk '{++s[$1]} END {for(k in s) print k,s[k]}' | grep 'LISTEN' | awk '{print $2}'
}
$1
vim /usr/local/zabbix/etc/zabbix_agentd.conf.d/cattcp.conf
UserParameter=tcp[*],/usr/local/zabbix/share/zabbix/alertscripts/tcp_connection.sh $1
tcp[TIMEWAIT] --检测TCP的驻留数,返回整数
tcp[ESTAB] --检测tcp的连接数、返回整数
tcp[LISTEN] --检测TCP的监听数,返回整数
九、zabbix优化
1、数据库
引擎
对于数据库而言,Zabbix 属于写多读少的操作,应该使用 Innodb 数据库引擎或者性能更好的 Tokudb,不应该使用 MyISAM
-
MyISAM 是不支持外键的,而 Zabbix创表的时候是有外键的。
-
MyISAM 只支持表级锁,就是说没插入/更新一条数据,整个表都要锁住,而 Zabbix 是写数据库比较多的,这样的话就会导致写如的速度很慢。
TokuDB一直被传说有着较高压缩比、较高insert性能、以及在线添加索引和字段速度较快等等优点,
关于 Tokudb 和 InnoDB 的性能对比参考如下博客
数据库
-
历史数据不要保存太长时长;
-
尽量让数据缓存在数据库服务器的内存中;
2、优化监控项
-
触发器的表达式
-
减少使用聚合函数min(), max(), avg();尽量使用last(),nodata(),因为聚合函数,要运算
-
数据收集:polling较慢(减少使用SNMP/agentless/agent);尽量使用trapping(agent(active)主动监控);
-
-
数据类型:文本型数据处理速度较慢;尽量少收集类型为文本 text或string类型的数据;多使用类型为numeric 数值型数据 的;
-
删除无用的监控项
-
增加数据收集间隔时间
-
减少历史数据的保留时长
3、Agent 工作模式改为主动或者使用分布式:Proxy
4、优化相关进程数
设置自动发现
制造让其快速繁忙的最有效的办法就是设置一个网段进行自动发现的扫描
保证自动发现规则是
已启用
状态
查看图,尝试在
名称
搜索框中搜索Utilization of discoverer data collector processes
现在,调整 /etc/zabbix/zabbix_server.conf
文件中的自动发现进程数量
# 默认值为1
# StartDiscoverers=1
# 修改为
StartDiscoverers=10
# 重启服务后查看进程数
ps -ef |grep discovere[r]
缓存设置
对应的配置文件中的选项
十、使用时遇到的问题
1、监控的服务器太多,把根占满了
因为创建数据库时没有特指数据存储的目录,导致数据存在了根下,而根的容量又不大,很快就满了
# 第一步,停服务,先将 zabbix-server 和 mysqld 停掉
[root@song-zabbix-server lib]# systemctl stop mysqld
[root@song-zabbix-server lib]# systemctl stop zabbix-server
# 第二步,迁移数据,将 mysql 的数据文件目录迁移到一个大空间的盘下
[root@song-zabbix-server lib]# mv /var/lib/mysql /data/mysql-data
# 第三步,做链接,将迁移后的目录链接到原地方,这样就不用更改配置文件了
[root@song-zabbix-server lib]# ln -s /data/mysql-data/ /var/lib/mysql
# 第四步,启动服务,然后就ok了
[root@song-zabbix-server lib]# systemctl start mysqld
[root@song-zabbix-server lib]# systemctl start zabbix-server
迁移zabbix使用的mysql
因华为虚拟机性能较低下,导致MySQL读写到瓶颈(表现:iowait 极高),故迁移MySQL至华为发放的MySQL中去
过程:大约80G的数据,dump时间大约1H,sql 文件 20G,导入耗时4小时
有丢失几个G 的数据,不清楚是重新启动mysql后又写入的,还是就是给丢了的,不过都是历史记录,所以问题不太大
# 1.停服务
# 2.dunp mysql
# 3.导入 新库
# 4.修改zabbix配置文件
# 5.重启验证
十一、报警处理
Zabbix server: More than 75% used in the history cache
在 zabbix-server 端,修改 server 的配置文件,将 HistoryCacheSize
值调大