复杂和高并发下的服务,必须保证每次gc不会出现性能下降,各种性能指标不会出现波动,gc回收规律而且干净,所以必须找到合适的jvm设置。而要找到合适的jvm设置,必须要了解当前java服务的jvm使用情况。所以我觉得非常有必要对java服务的jvm使用情况实时监控。
业务系统涉及到的java服务分为:tomcat类型、jar包类型、k8s微服务类型。
方案一:业务系统java服务采用的是SpringBoot框架,SpringBoot自带监控功能Actuator,可以帮助实现对程序内部运行情况监控,比如监控状况、Bean加载情况、环境变量、日志信息、线程信息、健康检查、审计、统计和HTTP追踪等。Actuator同时还可以与外部应用监控系统整合,比如Prometheus,可以选择使用HTTP端点或JMX来管理和监视应用程序。
方案二:通过JMX Exporter来暴露 Java 应用的JVM监控指标,JMX Exporter有两种用法。
# 方法一:启动独立进程
JVM启动时指定参数,暴露JMX的RMI接口,JMX-Exporter调用RMI获取JVM运行时状态数据,
转换为Prometheus metrics格式,并暴露端口让Prometheus采集。
# 方法二:JVM进程内启动(in-process)
JVM启动时指定参数,通过javaagent 的形式运行JMX-Exporter 的jar包,
进程内读取JVM运行时状态数据,转换为Prometheus metrics格式,并暴露端口让Prometheus采集。
说明:官方不推荐使用第一种方式,一方面配置复杂,另一方面因为它需要一个单独的进程,而这个进程本身的监控又成了新的问题,所以本文重点围绕第二种用法讲如何在K8S 环境下使用JMX Exporter暴露JVM监控指标。
1、监控系统架构图
2、监控系统说明
由于kubernetes集群中有多个业务系统,分别部署在不同的namespace空间,针对不同的监控类型数据,如主机资源监控数据、容器监控数据、应用程序监控数据,分别采用不同的prometheus来采集数据。
jmx_prometheus_javaagent-0.16.1.jar和prometheus-jmx-config.yaml
# 修改前
FROM java:8u111-jdk
RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo 'Asia/Shanghai' >/etc/timezone
ADD mpmt-cp-adapter.jar adapter.jar
EXPOSE 8083
ENTRYPOINT ["java","-Xmx2048m","-Xms512m","-XX:MaxMetaspaceSize=512m","-XX:MetaspaceSize=256m","-Djava.security.egd=file:/dev/./urandom","-jar","/adapter.jar","--spring.profiles.active=test"]
# 修改后
FROM java:8u111-jdk
RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo 'Asia/Shanghai' >/etc/timezone
ADD mpmt-cp-adapter.jar adapter.jar
ADD prometheus-jmx-config.yaml /prometheus-jmx-config.yaml
ADD jmx_prometheus_javaagent-0.16.1.jar /jmx_prometheus_javaagent-0.16.1.jar
EXPOSE 8083
EXPOSE 7070
ENTRYPOINT ["java","-javaagent:/jmx_prometheus_javaagent-0.16.1.jar=7070:prometheus-jmx-config.yaml","-Xmx2048m","-Xms512m","-XX:MaxMetaspaceSize=512m","-XX:MetaspaceSize=256m","-Djava.security.egd=file:/dev/./urandom","-jar","/adapter.jar","--spring.profiles.active=test"]
# 修改前
---
apiVersion: v1
kind: Service
metadata:
name: mpmt-adapter-svc
labels:
app: mpmt-adapter
spec:
type: NodePort
ports:
- port: 8083
targetPort: 8083
protocol: TCP
nodePort: 31087
selector:
app: mpmt-adapter
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mpmt-adapter
spec:
serviceName: "mpmt-adapter"
podManagementPolicy: Parallel
replicas: 1
updateStrategy:
type: RollingUpdate
selector:
matchLabels:
app: mpmt-adapter
template:
metadata:
labels:
app: mpmt-adapter
spec:
containers:
- name: mpmt-adapter
image: server.harbor.com:8888/library/mpmt-adapter:202107191029
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8083
resources:
requests:
cpu: "500m"
memory: "4Gi"
limits:
cpu: "1000m"
memory: "6Gi"
# 修改后
---
apiVersion: v1
kind: Service
metadata:
name: mpmt-adapter-svc
labels:
app: mpmt-adapter
system: pasz #增加内容
owner: sdjw #增加内容
env: test #增加内容
spec:
type: NodePort
ports:
- port: 8083
targetPort: 8083
protocol: TCP
nodePort: 31087
selector:
app: mpmt-adapter
system: pasz #增加内容
owner: sdjw #增加内容
env: test #增加内容
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mpmt-adapter
spec:
serviceName: "mpmt-adapter"
podManagementPolicy: Parallel
updateStrategy:
type: RollingUpdate
selector:
matchLabels:
app: mpmt-adapter
system: pasz #增加内容
owner: sdjw #增加内容
env: test #增加内容
template:
metadata:
labels:
app: mpmt-adapter
system: pasz #增加内容
owner: sdjw #增加内容
env: test #增加内容
spec:
containers:
- name: mpmt-adapter
image: server.harbor.com:8888/library/mpmt-adapter:202107191029
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8083
name: jdk #增加内容
- containerPort: 7070
name: jvm #增加内容
resources:
requests:
cpu: "500m"
memory: "4Gi"
limits:
cpu: "1000m"
memory: "6Gi"
问题一:为什么需要添加lables标签?
1、在不同的namespace空间下,部署着不同的业务系统,同时将不同业务系统的监控数据通过grafana展示,那如果对服务进行细化区分会不会更好呢?比如说同样的monitor服务,不同namespace空间下都有,如果加上多种标签,系统名称、系统属主、系统环境等等,这样在告警时,是不是就能更好的知道当前什么系统、是哪家客户的,是生产环境还是测试环境以及什么服务出现了问题呢,这样就可以快速响应并处理问题。
效果如下图所示:
2、添加lables标签还有一个目的就是实现告警分组,试想一下如果k8s集群中有多种业务系统,如A、B系统,A系统的告警信息发送到A系统告警钉钉群,B系统的告警信息发送到B系统告警钉钉群,这样A系统告警钉钉群成员就可以收到负责业务的告警信息,B系统告警钉钉群就不会收到。在企业中,告警分组也是常见的需求。
以下是alertmanager的配置文件,效果如下图所示:
问题二:为什么需要对容器端口增加name标签?
2、对pod中多个容器端口进行name设置,如果上面jdk和name,jdk表示微服务容器业务端口名称,jvm是jvm进程监控端口名称,这里所有业务系统中所有的服务的jvm进程监控端口都未7070,并且name值均为jvm。设置不同的name名称是为了在prometheus.yaml文件中精准匹配jvm进程端口。
# 在master节点
mkdir -p /data/pkgs/jvm_exporter
vim prometheus.yaml
CSDN下载地址:https://download.csdn.net/download/m0_37814112/20480830
问题一:如何重写变量名称?
说明:__meta_kubernetes_pod_host_ip、__meta_kubernetes_pod_container_port_name、__meta_kubernetes_namespace、__meta_kubernetes_pod_name、__meta_kubernetes_pod_node_name、__meta_kubernetes_pod_phase、__meta_kubernetes_pod_ready、__meta_kubernetes_pod_label_system、__meta_kubernetes_pod_label_owner、__meta_kubernetes_pod_label_env等这些变量是kubernetes自带的原生标签名称。通过action: replace,可替换__meta_kubernetes_namespace变成kubernetes_namespace,其它依次类推。
原生标签,如下图所示:
重新替换标签后,效果如下图所示:
问题二:如何新增标签?
说明:__meta_kubernetes_pod_label_app、__meta_kubernetes_pod_label_system、__meta_kubernetes_pod_label_owner、__meta_kubernetes_pod_label_env等这些标签不是kubernetes自带的原生标签,而是在微服务yaml文件里定义的,通过kubernetes转换成的。
# 1、根据yaml文件定义的prometheus服务部署在k8s-worker-112节点上,在该节点上创建数据存储目录
[root@k8s-worker-112 ~]# mkdir -pv /data/basic-data/prometheus
# 2、在k8s-master-111节点上执行
# 把default账号通过clusterrolebing绑定到clusterrole上
kubectl create clusterrolebinding nfs-clusterrolebinding -n default --clusterrole=cluster-admin --user=system:serviceaccount:default:default
# 注意:nfs-clusterrolebinding可自定义设置
# 3、在k8s-master-111节点上执行
[root@k8s-master-111 ~]# cd /data/pkgs/jvm_exporter
[root@k8s-master-111 ~]# kubectl create -f prometheus.yaml
# 4、查看pod状态(如下图所示)
[root@k8s-master-111 ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
prometheus-server-54dd9f5568-wc44l 1/1 Running 0 8
1、检查rules规则是否生效,如下图所示:
2、检查目标target是否为up,如下图所示:
《八、企业级监控系统之实现多节点Altermanager告警分组》
说明:这里默认grafana是已经安装了的,如果需要安装请参考《一、企业级监控之使用docker容器化部署grafana》
JVM监控模板
说明:这里就不介绍了。
说明:这里就不介绍了。
更多详细内容请参考:企业级K8s集群运维实战