zabbix自动发现agent上多个tomcat并使用JMX监控

zabbix自动发现agent上多个tomcat并使用JMX监控

最开始准备是在zabbix上直接使用 jmxtomcat 监控的,但是在使用过程中发现添加了 zabbix 自带的模板后并无法正常使用,然后参考西门飞冰博客手动添加,添加完成后发现个问题,不能重复添加监控项,可能是我菜吧,毕竟 zabbix 用的少没什么经验。
为了能够实现监控同一服务器上多个不同的 tomcat 并且在一劳永逸,开始了折腾之路。在查阅了大量资料后说干就干。

准备工作

编写脚本

tomcat自动发现脚本

获取 tomcats 存放路径下多个不同命名的 tomcattomcat JMX 端口,IP这个后面没用到(狗头),输出为 json 格式提供给 zabbix 获取使用。

jmx_tomcat_discovery.py >folded
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#!/usr/bin/env python2.7
# -*- coding: UTF-8 -*-

import os, json, socket, fcntl, struct, re

def get_ip_address(ifname):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
return socket.inet_ntoa(fcntl.ioctl(
s.fileno(),
0x8915,
struct.pack('256s', ifname[:15]))[20:24])

def get_tomcat_info(tomcats_path, key_file, network_card):
tomcats = []
for root, _, files in os.walk(tomcats_path, topdown=False):
for file_name in files:
if key_file == file_name:
tomcat = {}
name = root.split("/")[2]
tomcat['{#TOMCAT_NAME}'] = name
file_path = os.path.join(root, file_name)
pattern = re.compile('[0-9]{1,5}')
with open(file_path, "r") as f:
lines = f.readlines()
for line in lines:
if "Dcom.sun.management.jmxremote.port" in line:
try:
port = pattern.findall(line)[0]
except:
port = 0
tomcat['{#TOMCAT_PORT}'] = port
tomcat['{#SERVER_IP}'] = get_ip_address(network_card)
tomcats.append(tomcat)
return tomcats

if __name__ == "__main__":
# tomcat部署路径
tomcats_path = "/data"
# 查找该文件获取jmx端口
key_file = "setenv.sh"
# 选择指定网卡获取IP
network_card = "eth0"

tomcats = get_tomcat_info(tomcats_path, key_file, network_card)
print(json.dumps({'data':tomcats},indent=4,separators=(',',':')))

脚本编写好后存放于 zabbix_agent 服务器上你认为维护方便的地方
测试脚本,取值正常

shell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# ./jmx_tomcat_discovery.py
{
"data":[
{
"{#SERVER_IP}":"192.168.1.132",
"{#TOMCAT_NAME}":"tomcat_02",
"{#TOMCAT_PORT}":"20020"
},
{
"{#SERVER_IP}":"192.168.1.132",
"{#TOMCAT_NAME}":"tomcat_03",
"{#TOMCAT_PORT}":"20030"
},
{
"{#SERVER_IP}":"192.168.1.132",
"{#TOMCAT_NAME}":"tomcat_01",
"{#TOMCAT_PORT}":"20010"
}
]
}

tomcat_jmx监控数据源脚本

监控模板参考zabbix监控自动发现监控tomcat(V1)修改而来,原模板中有部分监控项无法获取数据。

tomcat_monitor.sh >folded
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
#!/usr/bin/env bash

source /etc/profile

[ $# -ne 3 ] && echo 'The scripts need 3 parameters' && exit 1
# tomcat 文件夹名
TOMCAT_NAME=$1
JMX_PORT=$2
# 监控项目
ITEM=$3

# jmx授权访问账号密码,建议权限为readonly
jmx_user="akiya"
jmx_password="akiya_password"
# 无授权验证状态下为"-"
authenticate="-"
if [ -n "$jmx_user" ] && [ -n "$jmx_password" ]; then
authenticate="$jmx_user:$jmx_password"
fi

#读取server.xml配置文件,获取http端口
xml=/data/$1/conf/server.xml
PORT=$(sed -n '69'p $xml | awk -F '[= " ]+' '{print $4}')
# cmdline-jmxclient位置
cmd=/opt/zabbix/cmdline-jmxclient-0.10.3.jar
# 查询缓存存放文件夹
logdir=/tmp/zabbix_tmp
[ ! -d "$logdir" ] && mkdir -p $logdir && chmod 644 $logdir
cd $logdir

#
function HeapMemoryUsage() {
java -jar $cmd $authenticate 127.0.0.1:$JMX_PORT java.lang:type=Memory HeapMemoryUsage 2>$TOMCAT_NAME.$ITEM.$JMX_PORT
}

function EdenSpaceUsage() {
java -jar $cmd $authenticate 127.0.0.1:$JMX_PORT java.lang:type=MemoryPool,name=PS\ Eden\ Space Usage 2>$TOMCAT_NAME.$ITEM.$JMX_PORT
}

function SurvivorSpaceUsage() {
java -jar $cmd $authenticate 127.0.0.1:$JMX_PORT java.lang:type=MemoryPool,name=PS\ Survivor\ Space Usage 2>$TOMCAT_NAME.$ITEM.$JMX_PORT
}

function TenuredGenUsage() {
java -jar $cmd $authenticate 127.0.0.1:$JMX_PORT java.lang:type=MemoryPool,name=PS\ Old\ Gen Usage 2>$TOMCAT_NAME.$ITEM.$JMX_PORT
}

function NonHeapMemoryUsage() {
java -jar $cmd $authenticate 127.0.0.1:$JMX_PORT java.lang:type=Memory NonHeapMemoryUsage 2>$TOMCAT_NAME.$ITEM.$JMX_PORT
}

function MetaspaceUsage() {
java -jar $cmd $authenticate 127.0.0.1:$JMX_PORT java.lang:type=MemoryPool,name=Metaspace Usage 2>$TOMCAT_NAME.$ITEM.$JMX_PORT
}

function CodeCacheUsage() {
java -jar $cmd $authenticate 127.0.0.1:$JMX_PORT java.lang:type=MemoryPool,name=Code\ Cache Usage 2>$TOMCAT_NAME.$ITEM.$JMX_PORT
}

function CompressedClassSpaceUsage() {
java -jar $cmd $authenticate 127.0.0.1:$JMX_PORT java.lang:type=MemoryPool,name=Compressed\ Class\ Space Usage 2>$TOMCAT_NAME.$ITEM.$JMX_PORT
}

function TotalLoadedClassCount() {
java -jar $cmd $authenticate 127.0.0.1:$JMX_PORT java.lang:type=ClassLoading TotalLoadedClassCount 2>$TOMCAT_NAME.$ITEM.$JMX_PORT
}

function LoadedClassCount() {
java -jar $cmd $authenticate 127.0.0.1:$JMX_PORT java.lang:type=ClassLoading LoadedClassCount 2>$TOMCAT_NAME.$ITEM.$JMX_PORT
}

function UnloadedClassCount() {
java -jar $cmd $authenticate 127.0.0.1:$JMX_PORT java.lang:type=ClassLoading UnloadedClassCount 2>$TOMCAT_NAME.$ITEM.$JMX_PORT
}

function TotalStartedThreadCount() {
java -jar $cmd $authenticate 127.0.0.1:$JMX_PORT java.lang:type=Threading TotalStartedThreadCount 2>$TOMCAT_NAME.$ITEM.$JMX_PORT
}

function ThreadCount() {
java -jar $cmd $authenticate 127.0.0.1:$JMX_PORT java.lang:type=Threading ThreadCount 2>$TOMCAT_NAME.$ITEM.$JMX_PORT
}

function PeakThreadCount() {
java -jar $cmd $authenticate 127.0.0.1:$JMX_PORT java.lang:type=Threading PeakThreadCount 2>$TOMCAT_NAME.$ITEM.$JMX_PORT
}

function maxThreads() {
java -jar $cmd $authenticate 127.0.0.1:$JMX_PORT Catalina:name=\"http-nio-$PORT\",type=ThreadPool maxThreads 2>$TOMCAT_NAME.$ITEM.$JMX_PORT
}

function currentThreadCount() {
java -jar $cmd $authenticate 127.0.0.1:$JMX_PORT Catalina:name=\"http-nio-$PORT\",type=ThreadPool currentThreadCount 2>$TOMCAT_NAME.$ITEM.$JMX_PORT
}

function currentThreadsBusy() {
java -jar $cmd $authenticate 127.0.0.1:$JMX_PORT Catalina:name=\"http-nio-$PORT\",type=ThreadPool currentThreadsBusy 2>$TOMCAT_NAME.$ITEM.$JMX_PORT
}

function GlobalRequestProcessor_bytesReceived() {
java -jar $cmd $authenticate 127.0.0.1:$JMX_PORT Catalina:name=\"http-nio-$PORT\",type=GlobalRequestProcessor bytesReceived 2>$TOMCAT_NAME.$ITEM.$JMX_PORT
}

function GlobalRequestProcessor_bytesSent() {
java -jar $cmd $authenticate 127.0.0.1:$JMX_PORT Catalina:name=\"http-nio-$PORT\",type=GlobalRequestProcessor bytesSent 2>$TOMCAT_NAME.$ITEM.$JMX_PORT
}

function requestCount() {
java -jar $cmd $authenticate 127.0.0.1:$JMX_PORT Catalina:name=\"http-nio-$PORT\",type=GlobalRequestProcessor requestCount 2>$TOMCAT_NAME.$ITEM.$JMX_PORT
}

function errorCount() {
java -jar $cmd $authenticate 127.0.0.1:$JMX_PORT Catalina:name=\"http-nio-$PORT\",type=GlobalRequestProcessor errorCount 2>$TOMCAT_NAME.$ITEM.$JMX_PORT
}

function jvmUptime() {
java -jar $cmd $authenticate 127.0.0.1:$JMX_PORT java.lang:type=Runtime Uptime 2>$TOMCAT_NAME.$ITEM.$JMX_PORT
}

case $ITEM in
#统计堆空间堆
HeapMemoryUsage.max)
HeapMemoryUsage
sed -n '4p' $TOMCAT_NAME.$ITEM.$JMX_PORT | awk '{print $2}'
;;
HeapMemoryUsage.used)
HeapMemoryUsage
sed -n '5p' $TOMCAT_NAME.$ITEM.$JMX_PORT | awk '{print $2}'
;;
HeapMemoryUsage.committed)
HeapMemoryUsage
sed -n '2p' $TOMCAT_NAME.$ITEM.$JMX_PORT | awk '{print $2}'
;;
#统计伊甸元代空间
EdenSpaceUsage.max)
EdenSpaceUsage
sed -n '4p' $TOMCAT_NAME.$ITEM.$JMX_PORT | awk '{print $2}'
;;
EdenSpaceUsage.used)
EdenSpaceUsage
sed -n '5p' $TOMCAT_NAME.$ITEM.$JMX_PORT | awk '{print $2}'
;;
EdenSpaceUsage.committed)
EdenSpaceUsage
sed -n '2p' $TOMCAT_NAME.$ITEM.$JMX_PORT | awk '{print $2}'
;;
#统计内存池survivor space(幸存区空间)
SurvivorSpaceUsage.max)
SurvivorSpaceUsage
sed -n '4p' $TOMCAT_NAME.$ITEM.$JMX_PORT | awk '{print $2}'
;;
SurvivorSpaceUsage.used)
SurvivorSpaceUsage
sed -n '5p' $TOMCAT_NAME.$ITEM.$JMX_PORT | awk '{print $2}'
;;
SurvivorSpaceUsage.committed)
SurvivorSpaceUsage
sed -n '2p' $TOMCAT_NAME.$ITEM.$JMX_PORT | awk '{print $2}'
;;
#统计内存池old gen(Tenured Gen 老年代空间)
TenuredGenUsage.max)
TenuredGenUsage
sed -n '4p' $TOMCAT_NAME.$ITEM.$JMX_PORT | awk '{print $2}'
;;
TenuredGenUsage.used)
TenuredGenUsage
sed -n '5p' $TOMCAT_NAME.$ITEM.$JMX_PORT | awk '{print $2}'
;;
TenuredGenUsage.committed)
TenuredGenUsage
sed -n '2p' $TOMCAT_NAME.$ITEM.$JMX_PORT | awk '{print $2}'
;;
#统计非堆内存
NonHeapMemoryUsage.used)
NonHeapMemoryUsage
sed -n '5p' $TOMCAT_NAME.$ITEM.$JMX_PORT | awk '{print $2}'
;;
NonHeapMemoryUsage.committed)
NonHeapMemoryUsage
sed -n '2p' $TOMCAT_NAME.$ITEM.$JMX_PORT | awk '{print $2}'
;;
#统计内存池meta space(元数据空间)
MetaspaceUsage.used)
MetaspaceUsage
sed -n '5p' $TOMCAT_NAME.$ITEM.$JMX_PORT | awk '{print $2}'
;;
MetaspaceUsage.committed)
MetaspaceUsage
sed -n '2p' $TOMCAT_NAME.$ITEM.$JMX_PORT | awk '{print $2}'
;;
#统计内存池code cache(代码缓存)
CodeCacheUsage.max)
CodeCacheUsage
sed -n '4p' $TOMCAT_NAME.$ITEM.$JMX_PORT | awk '{print $2}'
;;
CodeCacheUsage.used)
CodeCacheUsage
sed -n '5p' $TOMCAT_NAME.$ITEM.$JMX_PORT | awk '{print $2}'
;;
CodeCacheUsage.committed)
CodeCacheUsage
sed -n '2p' $TOMCAT_NAME.$ITEM.$JMX_PORT | awk '{print $2}'
;;
#统计compressed class space(压缩类的空间)
CompressedClassSpaceUsage.max)
CompressedClassSpaceUsage
sed -n '4p' $TOMCAT_NAME.$ITEM.$JMX_PORT | awk '{print $2}'
;;
CompressedClassSpaceUsage.used)
CompressedClassSpaceUsage
sed -n '5p' $TOMCAT_NAME.$ITEM.$JMX_PORT | awk '{print $2}'
;;
CompressedClassSpaceUsage.committed)
CompressedClassSpaceUsage
sed -n '2p' $TOMCAT_NAME.$ITEM.$JMX_PORT | awk '{print $2}'
;;
#统计类加载的个数
ClassLoading.TotalLoadedClassCount)
TotalLoadedClassCount
awk '{print $6}' $TOMCAT_NAME.$ITEM.$JMX_PORT
;;
ClassLoading.LoadedClassCount)
LoadedClassCount
awk '{print $6}' $TOMCAT_NAME.$ITEM.$JMX_PORT
;;
ClassLoading.UnloadedClassCount)
UnloadedClassCount
awk '{print $6}' $TOMCAT_NAME.$ITEM.$JMX_PORT
;;
#统计java线程数
Threading.TotalStartedThreadCount)
TotalStartedThreadCount
awk '{print $6}' $TOMCAT_NAME.$ITEM.$JMX_PORT
;;
ThreadCount)
ThreadCount
awk '{print $6}' $TOMCAT_NAME.$ITEM.$JMX_PORT
;;
PeakThreadCount)
PeakThreadCount
awk '{print $6}' $TOMCAT_NAME.$ITEM.$JMX_PORT
;;
#统计tomcat的线程数
maxThreads)
maxThreads
awk '{print $6}' $TOMCAT_NAME.$ITEM.$JMX_PORT
;;
currentThreadCount)
currentThreadCount
awk '{print $6}' $TOMCAT_NAME.$ITEM.$JMX_PORT
;;
currentThreadsBusy)
currentThreadsBusy
awk '{print $6}' $TOMCAT_NAME.$ITEM.$JMX_PORT
;;
#统计tomcat网络流量
bytesReceived)
GlobalRequestProcessor_bytesReceived
awk '{print $6}' $TOMCAT_NAME.$ITEM.$JMX_PORT
;;
bytesSent)
GlobalRequestProcessor_bytesSent
awk '{print $6}' $TOMCAT_NAME.$ITEM.$JMX_PORT
;;
#统计tomcat的请求数
requestCount)
requestCount
awk '{print $6}' $TOMCAT_NAME.$ITEM.$JMX_PORT
;;
errorCount)
errorCount
awk '{print $6}' $TOMCAT_NAME.$ITEM.$JMX_PORT
;;
#jvm运行时间,如果运行时间没获取到数据,则表示jvm stop ,从而判断tomcat stop
jvmUptime)
jvmUptime
[ $? -eq 0 ] && awk '{print $6/1000}' $TOMCAT_NAME.$ITEM.$JMX_PORT || echo 0
;;
esac

同样,编写好脚本后和上面 python 脚本放在一起。
测试脚本,取值正常

1
2
# ./tomcat_monitor.sh tomcat_02 20020 HeapMemoryUsage.max
1070071808

配置zabbix

zabbix_agent

  1. 修改 /etc/zabbix/zabbix_agentd.confAllowRoot=1

  2. 由于我们是使用的自定义脚本去自动发现相关的服务器并添加到 item,需要先添加到 zabbix_agent.conf

    /etc/zabbix/zabbix_agentd.d/userparameter_tomcat.conf
    1
    2
    UserParameter=tomcat.discovery,/usr/bin/python /opt/zabbix/jmx_tomcat_discovery.py
    UserParameter=tomcat.status[*],/bin/bash /opt/zabbix/tomcat_monitor.sh $1 $2 $3
  3. 添加/修改完成后,停止并重启 zabbix_agent(我试过直接restart,有可能会出现无数据情况)

    shell
    1
    2
    # service zabbix-agent stop
    # service zabbix-agent start
  4. 测试,在 zabbix_server 端上使用 zabbix_get 测试
    如果报权限错误无数据,请参考记一次zabbix_get远程执行取值为空问题

    • tomcat自动发现:zabbix_get -s 192.168.1.132 -p 10050 -k tomcat.discovery
    • tomcat_jmx监控数据源:zabbix_get -s 192.168.1.132 -p 10050 -k tomcat.status[mfa-rst,20020,jvmUptime]

zabbix_server

添加自动发现模板

zabbix web上新增一个模板

并且新增一个发现规则

然后添加监控项目

shell脚本分组添加图表

详细内容

触发器按个人需求自行添加

监控host

在host中导入模板

现在,可以在 configuration->hosts->ubuntu->items 中看到,已经自动添加了多个 tomcat的监控项目

monitoring->screens中添加图表后我们就可以看到相关信息了

参考文章:

评论

:D 一言句子获取中...

加载中,最新评论有1分钟缓存...