老的方法感觉效果不好,又写了一个模板和脚本,请移步:

http://www.cnops.top/posts/748ad64f.html

有兴趣的可以继续往下看。

Zabbix监控JVM(微服务进程)

1、ZabbixServer端配置

Zabbix服务器需安装java,编译需添加启动参数--enable-java

本次安装的编译参数为:

./configure --prefix=/data/zabbix/ --enable-server --enable-agent --with-mysql --enable-ipv6 --with-net-snmp --with-libcurl --with-libxml2 --enable-java

2、ZabbixAgent端配置

ZabbixAgent端不仅需要安装zabbix_agentd,还需要安装zabbix_sender,可以通过地址http://repo.zabbix.com/zabbix/3.0/rhel/7/x86_64/选择合适的版本。

安装

rpm -ivh http://repo.zabbix.com/zabbix/3.0/rhel/7/x86_64/zabbix-sender-3.0.9-1.el7.x86_64.rpm

3、监控原理

微服务的特性:

1、  每个进程是直接以java-jar service.jar的方式启动,并没有依赖于tomcat或者其他web应用。

2、  每台服务器上的微服务并没有固定的数量,可以灵活的增加或者减少。

3、  每个微服务的启动参数已有配置端口很多。

鉴于此种情况,传统的监控方法监控微服务,会造成经常的手动去增加删减web页面配置,服务器内的端口管理也会很混乱。

所以使用discovery自动发现的方式去监控微服务。并将每个微服务的信息通过zabbix_sender发送到ZabbixServer端。

首先java版本为jdk1.8

# java -version

java version "1.8.0_161"

Java(TM) SE Runtime Environment (build 1.8.0_161-b12)

Java HotSpot(TM) 64-Bit Server VM (build 25.161-b12, mixed mode)

关于微服务的信息主要通过jstat获取,如下

# ps -ef|grep java

root 28131 1 0 11:17 ? 00:00:56 java -Xms100M -Xmx500M -Xmn150M -jar /data/work/service_jar/manageMiddle.jar --server.port=20000 --management.port=20001 --config.profile=test

root 28305 1 0 11:26 ? 00:00:51 java -Xms100M -Xmx300M -Xmn100M -jar /data/work/service_jar/resourceService.jar --server.port=18000 --management.port=18001 --config.profile=test

root 29067 1 0 11:59 ? 00:00:54 java -Xms100M -Xmx500M -Xmn150M -jar /data/work/service_jar/systemService.jar --server.port=21000 --management.port=21001 --config.profile=test

root 31345 29980 0 14:03 pts/0 00:00:00 grep --color=auto java

# jstat -gcutil 28131

S0 S1 E O M CCS YGC YGCT FGC FGCT GCT

67.75 0.00 74.28 81.92 97.29 94.90 74 1.248 7 1.065 2.313

# jstat -gc 28131

S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT

14336.0 14848.0 9712.2 0.0 122880.0 91488.9 55808.0 45716.6 56704.0 55169.1 7296.0 6924.1 74 1.248 7 1.065 2.313

关于输出结果的参数解释

S0C:年轻代中第一个survivor(幸存区)的容量 (字节)

S1C:年轻代中第二个survivor(幸存区)的容量 (字节)

S0U:年轻代中第一个survivor(幸存区)目前已使用空间 (字节)

S1U:年轻代中第二个survivor(幸存区)目前已使用空间 (字节)

EC:年轻代中Eden(伊甸园)的容量 (字节)

EU:年轻代中Eden(伊甸园)目前已使用空间 (字节)

OC:Old代的容量 (字节)

OU:Old代目前已使用空间 (字节)

PC:Perm(持久代)的容量 (字节)

PU:Perm(持久代)目前已使用空间 (字节)

YGC:从应用程序启动到采样时年轻代中gc次数

YGCT:从应用程序启动到采样时年轻代中gc所用时间(s)

FGC:从应用程序启动到采样时old代(全gc)gc次数

FGCT:从应用程序启动到采样时old代(全gc)gc所用时间(s)

GCT:从应用程序启动到采样时gc用的总时间(s)

NGCMN:年轻代(young)中初始化(最小)的大小 (字节)

NGCMX:年轻代(young)的最大容量 (字节)

NGC:年轻代(young)中当前的容量 (字节)

OGCMN:old代中初始化(最小)的大小 (字节)

OGCMX:old代的最大容量 (字节)

OGC:old代当前新生成的容量 (字节)

PGCMN:perm代中初始化(最小)的大小 (字节)

PGCMX:perm代的最大容量 (字节)

PGC:perm代当前新生成的容量 (字节)

S0:年轻代中第一个survivor(幸存区)已使用的占当前容量百分比

S1:年轻代中第二个survivor(幸存区)已使用的占当前容量百分比

E:年轻代中Eden(伊甸园)已使用的占当前容量百分比

O:old代已使用的占当前容量百分比

P:perm代已使用的占当前容量百分比

S0CMX:年轻代中第一个survivor(幸存区)的最大容量 (字节)

S1CMX :年轻代中第二个survivor(幸存区)的最大容量 (字节)

ECMX:年轻代中Eden(伊甸园)的最大容量 (字节)

DSS:当前需要survivor(幸存区)的容量 (字节)(Eden区已满)

TT: 持有次数限制

MTT : 最大持有次数限制

Jdk1.8中取消了永久区Perm

4、监控脚本

微服务全部放置在固定的目录内,自动发现微服务脚本为

# cat java_discovery.py

#/usr/bin/python

#This script is used to discovery disk on the server

import subprocess

import os

import socket

import json

import glob

java_names_file='java_names.txt'

javas=[]

if os.path.isfile(java_names_file):

# print 'java_names_file exists!'

#####

##### here should use % (java_names_file) instead of using the python variable java_names_file directly inside the ''' ''' quotes

#####

args='''awk -F':' '{print $1':'$2}' %s''' % (java_names_file)

t=subprocess.Popen(args,shell=True,stdout=subprocess.PIPE).communicate()[0]

#elif glob.glob('/opt/xx/*_tomcat') and not os.path.isdir('/opt/logs/logstash') and not os.path.isdir('/opt/app/elasticsearch/config'):

elif glob.glob('/data/work/service_jar/*.jar'):

t=subprocess.Popen('cd /data/work/service_jar && ls *.jar|grep jar',shell=True,stdout=subprocess.PIPE)

for java in t.stdout.readlines():

if len(java) != 0:

javas.append({'{#JAVA_NAME}':java.strip('\n').strip(':')})

print json.dumps({'data':javas},indent=4,separators=(',',':'))

脚本内的目录可以自由修改

输出结果为json格式

# python java_discovery.py

{

"data":[

{

"{#JAVA_NAME}":"insuranceService.jar"

},

{

"{#JAVA_NAME}":"manageMiddle.jar"

},

{

"{#JAVA_NAME}":"resourceService.jar"

},

{

"{#JAVA_NAME}":"systemService.jar"

}

]

}

对微服务进行信息获取,并利用zabbix_sender发送的脚本为

# cat jstat_status.py

#!/usr/bin/python

import subprocess

import sys

import os

__maintainer__ = "Francis"

jps = '/data/jdk1.8/bin/jps'

jstat = '/data/jdk1.8/bin/jstat'

zabbix_sender = "/usr/bin/zabbix_sender"

zabbix_conf = "/etc/zabbix/zabbix_agentd.conf"

send_to_zabbix = 1

ip=os.popen("ifconfig|grep 'inet '|grep -v '127.0'|xargs|awk -F '[ :]' '{print $3}'").readline().rstrip()

serverip="172.19.138.53"

#"{#JAVA_NAME}":"tomcat_web_1"

def usage():

"""Display program usage"""

print "\nUsage : ", sys.argv[0], " java_name alive|all"

print "Modes : \n\talive : Return pid of running processs\n\tall : Send jstat stats as well"

sys.exit(1)

class Jprocess:

def __init__(self, arg):

self.pdict = {

"jpname": arg,

}

self.zdict = {

"Heap_used" : 0,

"Heap_ratio" : 0,

"Heap_max" : 0,

"Perm_used" : 0,

"Perm_ratio" : 0,

"Perm_max" : 0,

"S0_used" : 0,

"S0_ratio" : 0,

"S0_max" : 0,

"S1_used" : 0,

"S1_ratio" : 0,

"S1_max" : 0,

"Eden_used" : 0,

"Eden_ratio" : 0,

"Eden_max" : 0,

"Old_used" : 0,

"Old_ratio" : 0,

"Old_max" : 0,

"YGC" : 0,

"YGCT" : 0,

"YGCT_avg" : 0,

"FGC" : 0,

"FGCT" : 0,

"FGCT_avg" : 0,

"GCT" : 0,

"GCT_avg" : 0,

}

def chk_proc(self):

# ps -ef|grep java|grep tomcat_web_1|awk '{print $2}'

# print self.pdict['jpname']

pidarg = '''ps -ef|grep java|grep %s|grep -v grep | grep -v jstat_status.py |awk '{print $2}' ''' %(self.pdict['jpname'])

#pidout = subprocess.Popen(pidarg,shell=True,stdout=subprocess.PIPE)

#pid = pidout.stdout.readline().strip('\n')

pid = subprocess.check_output(pidarg, shell=True).strip()

if pid != "" :

self.pdict['pid'] = pid

# print "Process found :", java_name, "with pid :", self.pdict['pid']

else:

self.pdict['pid'] = ""

# print "Process not found"

return self.pdict['pid']

def get_jstats(self):

if self.pdict['pid'] == "":

return False

self.pdict.update(self.fill_jstats("-gc"))

self.pdict.update(self.fill_jstats("-gccapacity"))

self.pdict.update(self.fill_jstats("-gcutil"))

# print "\nDumping collected stat dictionary\n-----\n", self.pdict, "\n-----\n"

def fill_jstats(self, opts):

# print "\nGetting", opts, "stats for process", self.pdict['pid'], "with command : sudo", jstat, opts, self.pdict['pid'] ,"\n"

# jstatout = subprocess.Popen(['sudo','-u','tomcat', jstat, opts, self.pdict['pid']], stdout=subprocess.PIPE)

#print([jstat, opts, self.pdict['pid']])

jstatout = subprocess.Popen([jstat, opts, self.pdict['pid']], stdout=subprocess.PIPE)

stdout, stderr = jstatout.communicate()

legend, data = stdout.split('\n',1)

mydict = dict(zip(legend.split(), data.split()))

return mydict

def compute_jstats(self):

if self.pdict['pid'] == "":

return False

self.zdict['S0_used'] = format(float(self.pdict['S0U']) * 1024,'0.2f')

self.zdict['S0_max'] = format(float(self.pdict['S0C']) * 1024,'0.2f')

self.zdict['S0_ratio'] = format(float(self.pdict['S0']),'0.2f')

self.zdict['S1_used'] = format(float(self.pdict['S1U']) * 1024,'0.2f')

self.zdict['S1_max'] = format(float(self.pdict['S1C']) * 1024,'0.2f')

self.zdict['S1_ratio'] = format(float(self.pdict['S1']),'0.2f')

self.zdict['Old_used'] = format(float(self.pdict['OU']) * 1024,'0.2f')

self.zdict['Old_max'] = format(float(self.pdict['OC']) * 1024,'0.2f')

self.zdict['Old_ratio'] = format(float(self.pdict['O']),'0.2f')

self.zdict['Eden_used'] = format(float(self.pdict['EU']) * 1024,'0.2f')

self.zdict['Eden_max'] = format(float(self.pdict['EC']) * 1024,'0.2f')

self.zdict['Eden_ratio'] = format(float(self.pdict['E']),'0.2f')

# self.zdict['Perm_used'] = format(float(self.pdict['PU']) * 1024,'0.2f')

# self.zdict['Perm_max'] = format(float(self.pdict['PC']) * 1024,'0.2f')

# self.zdict['Perm_ratio'] = format(float(self.pdict['P']),'0.2f')

self.zdict['Heap_used'] = format((float(self.pdict['EU']) + float(self.pdict['S0U']) + float(self.pdict['S1U']) + float(self.pdict['OU'])) * 1024,'0.2f')

self.zdict['Heap_max'] = format((float(self.pdict['EC']) + float(self.pdict['S0C']) + float(self.pdict['S1C']) + float(self.pdict['OC'])) * 1024,'0.2f')

self.zdict['Heap_ratio'] = format(float(self.zdict['Heap_used']) / float(self.zdict['Heap_max'])*100,'0.2f')

self.zdict['YGC'] = self.pdict['YGC']

self.zdict['FGC'] = self.pdict['FGC']

self.zdict['YGCT'] = format(float(self.pdict['YGCT']),'0.3f')

self.zdict['FGCT'] = format(float(self.pdict['FGCT']),'0.3f')

self.zdict['GCT'] = format(float(self.pdict['GCT']),'0.3f')

if self.pdict['YGC'] == '0':

self.zdict['YGCT_avg'] = '0'

else:

self.zdict['YGCT_avg'] = format(float(self.pdict['YGCT'])/float(self.pdict['YGC']),'0.3f')

if self.pdict['FGC'] == '0':

self.zdict['FGCT_avg'] = '0'

else:

self.zdict['FGCT_avg'] = format(float(self.pdict['FGCT'])/float(self.pdict['FGC']),'0.3f')

if self.pdict['YGC'] == '0' and self.pdict['FGC'] == '0':

self.zdict['GCT_avg'] = '0'

else:

self.zdict['GCT_avg'] = format(float(self.pdict['GCT'])/(float(self.pdict['YGC']) + float(self.pdict['FGC'])),'0.3f')

# print "Dumping zabbix stat dictionary\n-----\n", self.zdict, "\n-----\n"

def send_to_zabbix(self, metric):

#### {#JAVA_NAME} tomcat_web_1

#### UserParameter=java.discovery,/usr/bin/python /opt/app/zabbix/sbin/java_discovery.py

#### UserParameter=java.discovery_status[*],/opt/app/zabbix/sbin/jstat_status.sh $1 $2 $3 $4

#### java.discovery_status[tomcat_web_1,Perm_used]

#### java.discovery_status[{#JAVA_NAME},Perm_used]

key = "java.discovery_status[" + self.pdict['jpname'] + "," + metric + "]"

if self.pdict['pid'] != "" and send_to_zabbix > 0:

#print key + ":" + str(self.zdict[metric])

try:

subprocess.call([zabbix_sender, "-c", zabbix_conf, "-k", key, "-o", str(self.zdict[metric])], stdout=FNULL,stderr=FNULL, shell=False)

except OSError, detail:

print "Something went wrong while exectuting zabbix_sender : ", detail

else:

print "Simulation: the following command would be execucted :\n", zabbix_sender, "-c", zabbix_conf, "-k", key, "-o", self.zdict[metric], "\n"

accepted_modes = ['alive', 'all']

if len(sys.argv) == 3 and sys.argv[2] in accepted_modes:

java_name = sys.argv[1]

mode = sys.argv[2]

else:

usage()

#Check if process is running / Get PID

jproc = Jprocess(java_name)

pid = jproc.chk_proc()

if pid != "" and mode == 'all':

jproc.get_jstats()

#print jproc.zdict

jproc.compute_jstats()

FNULL = open(os.devnull, 'w')

for key in jproc.zdict:

#print key,jproc.zdict[key]

jproc.send_to_zabbix(key)

FNULL.close()

# print pid

else:

print 0

触发脚本为

# cat java_discovery_status_sender.py

#/usr/bin/python

#This script is used to discovery disk on the server

import subprocess

import os

import socket

import json

import glob

java_names_file='java_names.txt'

javas=[]

if os.path.isfile(java_names_file):

args='''awk -F':' '{print $1':'$2}' %s''' % (java_names_file)

t=subprocess.Popen(args,shell=True,stdout=subprocess.PIPE).communicate()[0]

elif glob.glob('/data/work/service_jar/*.jar'):

t=subprocess.Popen('cd /data/work/service_jar && ls *.jar|grep jar',shell=True,stdout=subprocess.PIPE)

res=subprocess.check_output('cd /data/work/service_jar && ls *.jar|grep jar',stderr=subprocess.STDOUT,shell = True)

for java in t.stdout.readlines():

if len(java) != 0:

javas.append({'{#JAVA_NAME}':java.strip('\n').strip(':')})

#print json.dumps({'data':javas},indent=4,separators=(',',':'))

#print res

for java in res.strip().split("\n"):

if java:

#print java

out = subprocess.check_output("python /etc/zabbix/scripts/java/jstat_status.py %s all" % java, shell=True)

#print(out)

其中web界面配置Host name的参数必须与Agent端配置文件内Hostname的参数完全相同

将脚本java_discovery_status_sender.py加入crontab

*/1 * * * * root /usr/bin/python /etc/zabbix/scripts/java/java_discovery_status_sender.py

每分钟触发一次,向server端发信息

5、userparameter配置

路径及内容如下

# pwd

/etc/zabbix/zabbix_agentd.d

# cat userparameter_java_discovery_status.conf

UserParameter=java.discovery,/usr/bin/python /etc/zabbix/scripts/java/java_discovery.py

UserParameter=java.discovery_status[*],/usr/bin/python /etc/zabbix/scripts/java/jstat_status.py $1 $2

UserParameter=java.discovery_status_sender,/usr/bin/python /etc/zabbix/scripts/java/java_discovery_status_sender.py

UserParameter=java.discovery_status[*]和UserParameter=java.discovery_status_sender的作用和原理都是一样的,只不过在Agent端可以执行,在Server端通过zabbix_get调用都会出错,暂时没有找到更好的解决方法。所以通过crontab的方法定时向Server端发送监控信息。如果能够解决问题,或者有更好的解决方法请联系我。

重启ZabbixAgent端

6、导入模板

模板下载地址:https://download..net/download/fjp824/10462387

导入模板,并将对应的host关联

可以在Monitoring>Latest data页面根据主机,查看zabbix_trapper接收到的监控信息,如下所以

查看图表展示正常,监控完成。

zabbix监控JAVA微服务_Zabbix监控JVM(微服务进程)相关推荐

  1. java服务监控_Java最流行的微服务框架监控和各种监控数据

    原标题:Java最流行的微服务框架监控和各种监控数据 自动化的监控运维机制 自动化的监控运维机制的运行基础是不间断地收集各个微服务应用的各项指标情况,并根据这些基础指标信息来制定监控和预警规则,更进一 ...

  2. Observability:从零开始创建 Java 微服务并监控它 (一)

    在本教程中,你将学习如何使用 Elastic 可观察性监控 Java 应用程序:日志.基础设施指标.APM 和正常运行时间.通过本教程,你将学到: 创建示例 Java 应用程序. 使用 Filebea ...

  3. 五分钟学会 Spring Boot Admin:微服务应用监控(小白必看,一看就会教程)

    Spring Boot Admin:微服务应用监控 Spring Boot Admin 简介 监控信息演示 结合注册中心使用 功能演示 添加登录认证 文末福利 Spring Boot Admin 可以 ...

  4. 基于Prometheus的微服务应用监控

    基于Prometheus的微服务应用监控 北京易观智库网络科技有限公司 作者:李泰庆 导语: Prometheus是一套开源的系统监控报警框架.它启发于Google的borgmon 监控系统,由工作在 ...

  5. 百度商业大规模微服务分布式监控系统——凤睛

    导读:作为凤睛早期的接入方.后期的核心成员,笔者经历了整个项目前后四年的变迁,看过项目的艰难开端.中期的默默积累以及后期的蓬勃发展.每一次架构的变迁都带着技术浪潮的烙印,也看到项目成员利用有限资源来解 ...

  6. 监控服务器怎么增加碟机,微服务业务监控方法及服务器专利_专利申请于2017-12-15_专利查询 - 天眼查...

    1. 一种微服务业务监控方法,其特征在于,包括: 生成多个调用请求信息,每个所述调用请求信息对应多个微服务,并将各个所述调用 请求信息发送给对应的微服务;每个所述调用请求信息用于使得对应的微服务生成与 ...

  7. Docker实战-部署GPE微服务的监控体系(二)

    前言 上篇文章:我们介绍了GPE体系中,grafana的部署和安装(<Docker实战-部署GPE微服务的监控体系>),今天这个文章,我们继续介绍GPE体系中,Prometheus和Exp ...

  8. Docker实战-部署GPE微服务的监控体系

    Docker实战-部署GPE微服务的监控体系 前言 微服务体系架构里,有很多的解决方案都是使用GPE作为微服务体系的监控体系, 如下图所示: 我们这里经常提到的GPE,包括Grafana,Promet ...

  9. 2022面试200题目和答案分布式+微服务+MYSQL+Redis+JVM+Spring

    200题目和答案分布式+微服务+MYSQL+Redis+JVM+Spring等等 带图MD在资源https://download.csdn.net/download/m0_47987937/86509 ...

最新文章

  1. 织梦文章内容屏蔽替换词语多个敏感字词
  2. 解决django需要手动调整数据库,避免manage.py各种报错
  3. 微信小程序--搜索关键词高亮
  4. python下载特别慢-Python3 用 urllib 下载图片非常慢,会是什么原因呢?
  5. 中文编程——函语言概念
  6. crr树不同步数期权定价 matlab,CRR二叉树模型及例题
  7. FastDFS文件服务器升级内置nginx版本
  8. 火山PC(火山视窗)图形按钮制作器教程
  9. K8S 多 Maser 集群架构和 Dashboard UI 的二进制部署
  10. API开发平台,专注API无代码快速发布
  11. 小米再次回购股票:斥资近1亿港元 传递市场信心
  12. 左右手坐标转换 四元数
  13. MAGSAC:Marginalizing Sample Consensus
  14. 【签证】办理签证有特别要求的国家【签证办理必看】
  15. itextPDF操作PDF,获取PDF内容
  16. 分布式 ID 解决方案帮你总结好啦!收藏拿去面试去。
  17. Ubuntu中文语言包下载失败解决方法
  18. 3dsMax2016卡死的一种解决办法
  19. 用WinGrub来引导Linux的安装
  20. 诺基亚n1系统更新显示无网络_国行版诺基亚8 Sirocco推送安卓9.0系统更新

热门文章

  1. 如何把excel表格信息打印?轻松技巧!怎样打印excel表格文档数据?
  2. 【English】十月英语总结
  3. 神奇的计算机相关文章,神奇的计算机(教学设计)
  4. python列表转json_python递归查询菜单并转换成json
  5. 摄像机、镜头专业词汇详解
  6. 戴尔服务器系统过热,dell服务器过热保护
  7. 【译】Spring Boot Features
  8. Ae 效果快速参考:模拟
  9. 饿了么外卖商家网页IM通信协议
  10. 安卓桌面壁纸_小米全新MIUI 12正式发布,惊艳而强大 堪称安卓最美系统