Elastic APM 是基于 Elastic Stack 构建的应用程序性能监视系统。 它使你可以实时监视软件服务和应用程序-收集有关传入请求,数据库查询,对缓存的调用,外部 HTTP 请求等的响应时间的详细性能信息。 这样可以轻松快速地找出并解决性能问题。
Elastic APM 适配 OpenTracing,这意味着您可以利用已经可用的大量库来跟踪应用程序中的组件(例如 MongoDB intrumentation)。
例如,你将能够在高度分布式的环境(微服务体系结构)中跟踪请求,并轻松快速地发现潜在的瓶颈。
Elastic APM 由一个称为 APM-Server 的组件组成,用于收集跟踪并将其发送到 ElasticSearch 以及与应用程序或服务一起运行的各个代理。
安装 APM 服务器
我们首先需要在 k8s 上安装 APM-Server,以收集代理的跟踪并将其转发到 Elasticseach。 它由用于配置设置的 ConfigMap 组成:
apm.configmap.yml
# apm.configmap.yml
---
apiVersion: v1
kind: ConfigMap
metadata:
namespace: monitoring
name: apm-server-config
labels:
app: apm-server
data:
apm-server.yml: |-
apm-server:
host: "0.0.0.0:8200"
output.elasticsearch:
hosts: ['${ELASTICSEARCH_HOST:elasticsearch}:${ELASTICSEARCH_PORT:9200}']
username: ${ELASTICSEARCH_USERNAME}
password: ${ELASTICSEARCH_PASSWORD}
setup.kibana:
host: '${KIBANA_HOST:kibana}:${KIBANA_PORT:5601}'
---
APM 服务器需要公开端口8200,以允许代理转发其跟踪。 以下服务将该端口暴露给环境:
apm.service.yml
# apm.service.yml
---
apiVersion: v1
kind: Service
metadata:
namespace: monitoring
name: apm-server
labels:
app: apm-server
spec:
ports:
- port: 8200
name: apm-server
selector:
app: apm-server
---
最后是 Deployment,它描述了要部署的容器:
apm.deployment.yml
# apm.deployment.yml
---
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: monitoring
name: apm-server
labels:
app: apm-server
spec:
replicas: 1
selector:
matchLabels:
app: apm-server
template:
metadata:
labels:
app: apm-server
spec:
containers:
- name: apm-server
image: docker.elastic.co/apm/apm-server:7.6.2
env:
- name: ELASTICSEARCH_HOST
value: elasticsearch-client.monitoring.svc.cluster.local
- name: ELASTICSEARCH_PORT
value: "9200"
- name: ELASTICSEARCH_USERNAME
value: elastic
- name: ELASTICSEARCH_PASSWORD
valueFrom:
secretKeyRef:
name: elasticsearch-pw-elastic
key: password
- name: KIBANA_HOST
value: kibana.monitoring.svc.cluster.local
- name: KIBANA_PORT
value: "5601"
ports:
- containerPort: 8200
name: apm-server
volumeMounts:
- name: config
mountPath: /usr/share/apm-server/apm-server.yml
readOnly: true
subPath: apm-server.yml
volumes:
- name: config
configMap:
name: apm-server-config
---
现在,我们可以部署堆栈的这个新组件:
kubectl apply -f apm.configmap.yml \
-f apm.service.yml \
-f apm.deployment.yml
$ kubectl apply -f apm.configmap.yml \
> -f apm.service.yml \
> -f apm.deployment.yml
configmap/apm-server-config created
service/apm-server created
deployment.apps/apm-server created
检查一切是否正常运行:
kubectl get all -n monitoring -l app=apm-server
$ kubectl get all -n monitoring -l app=apm-server
NAME READY STATUS RESTARTS AGE
pod/apm-server-58b6b7d8d9-jk8r9 1/1 Running 0 43s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/apm-server ClusterIP 10.108.187.142 <none> 8200/TCP 43s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/apm-server 1/1 1 1 43s
NAME DESIRED CURRENT READY AGE
replicaset.apps/apm-server-58b6b7d8d9 1 1 1 43s
现在,我们可以在 Spring-Boot 应用程序上安装代理。
在 Spring-Boot 应用上安装 Java agent
在本文的最后一部分中,我们将在示例应用程序 spring-boot-simple 上配置 Elastic APM Java agent。
首先,我们需要 jar elastic-apm-agent-1.8jar 放入容器中。 添加以下行以在 Docker 构建映像时下载代理 JAR。
RUN wget -O /apm-agent.jar https://search.maven.org/remotecontent?filepath=co/elastic/apm/elastic-apm-agent/1.8.0/elastic-apm-agent-1.8.0.jar
Dockfile:
FROM openjdk:8-jdk-alpine
COPY target/spring-boot-simple.jar /app.jar
RUN wget -O /apm-agent.jar https://search.maven.org/remotecontent?filepath=co/elastic/apm/elastic-apm-agent/1.8.0/elastic-apm-agent-1.8.0.jar
CMD java -jar /app.jar
其次,将以下依赖项添加到您的应用程序中,以便您能够集成开放式跟踪库(了解更多)和/或使用 Elastic APM API 手动检测某些组件(了解更多)。
<dependency>
<groupId>co.elastic.apm</groupId>
<artifactId>apm-agent-api</artifactId>
<version>${elastic-apm.version}</version>
</dependency>
<dependency>
<groupId>co.elastic.apm</groupId>
<artifactId>apm-opentracing</artifactId>
<version>${elastic-apm.version}</version>
</dependency>
<dependency>
<groupId>io.opentracing.contrib</groupId>
<artifactId>opentracing-spring-cloud-mongo-starter</artifactId>
<version>${opentracing-spring-cloud.version}</version>
</dependency>
然后,我们将更改 Deployment,以在启用 Java 代理并将其连接到 APM 服务器的情况下启动 Spring-Boot 应用程序。
# spring-boot-simple.deployment.yml
---
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: default
name: spring-boot-simple
labels:
app: spring-boot-simple
spec:
replicas: 1
selector:
matchLabels:
app: spring-boot-simple
template:
metadata:
labels:
app: spring-boot-simple
spec:
containers:
- image: gjeanmart/spring-boot-simple:0.0.1-SNAPSHOT
imagePullPolicy: Always
name: spring-boot-simple
command:
- "java"
- "-javaagent:/apm-agent.jar"
- "-Delastic.apm.active=$(ELASTIC_APM_ACTIVE)"
- "-Delastic.apm.server_urls=$(ELASTIC_APM_SERVER)"
- "-Delastic.apm.service_name=spring-boot-simple"
- "-jar"
- "app.jar"
env:
- name: SPRING_DATA_MONGODB_HOST
value: mongo
- name: ELASTIC_APM_ACTIVE
value: "true"
- name: ELASTIC_APM_SERVER
value: http://apm-server.monitoring.svc.cluster.local:8200
ports:
- containerPort: 8080
---
现在重新应用部署,并且 spring-boot-simple 应该重新启动:
kubectl apply -f spring-boot-simple.yml
然后,我们执行像在第一篇文章中介绍的那样:
kubectl get svc
上面显示所有的 service:
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 10h
mongo ClusterIP 10.98.1.3 <none> 27017/TCP 9h
spring-boot-simple NodePort 10.101.241.38 <none> 8080:30202/TCP 9h
我们通过如下的方式来找到 spring-boot-simple 的服务地址:
minikube service spring-boot-simple --url
$ minikube service spring-boot-simple --url
🏃 Starting tunnel for service spring-boot-simple.
|-----------|--------------------|-------------|------------------------|
| NAMESPACE | NAME | TARGET PORT | URL |
|-----------|--------------------|-------------|------------------------|
| default | spring-boot-simple | | http://127.0.0.1:62891 |
|-----------|--------------------|-------------|------------------------|
http://127.0.0.1:62891
❗ Because you are using docker driver on Mac, the terminal needs to be open to run it.
get messages
curl -X GET http://YourIP:YourPort/message
get messages (slow request)
使用属性 sleep = <ms> 可以减慢请求的速度。
curl -X GET http://YourIP:YourPort/message?sleep=3000
get messages (error)
curl -X GET http://YourIP:YourPort/message?error=true
针对我的情况就是:
$ curl http://127.0.0.1:62891
Greetings from Spring Boot!liuxg:minikube liuxg$
liuxg:minikube liuxg$ curl http://127.0.0.1:62891
Greetings from Spring Boot!
liuxg:minikube liuxg$ curl http://127.0.0.1:62891
Greetings from Spring Boot!
liuxg:minikube liuxg$ curl http://127.0.0.1:62891/message?sleep=300
[{"id":"5eace24730c49e000198b8d6","message":"hello+world=","postedAt":"2020-05-02T03:00:23.860+0000"}]
liuxg:minikube liuxg$ curl http://127.0.0.1:62891/message?sleep=5000
[{"id":"5eace24730c49e000198b8d6","message":"hello+world=","postedAt":"2020-05-02T03:00:23.860+0000"}]
liuxg:minikube liuxg$ curl http://127.0.0.1:62891/message?error=true
{"timestamp":"2020-05-02T12:39:07.913+0000","status":500,"error":"Internal Server Error","message":"java.lang.Exception: Random error","path":"/message"}
liuxg:minikube liuxg$ curl http://127.0.0.1:62891/message?error=true
{"timestamp":"2020-05-02T12:39:12.307+0000","status":500,"error":"Internal Server Error","message":"java.lang.Exception: Random error","path":"/message"}
我们打开Kibana APM应用:
我们可以看到在 Kibana 中有一个叫做 spring-boot-simple 的 Service。我们点击上面的超链接:
我们可以看到里面的 transactions。点击其中的 getMessages:
它详细地显示了我们快的和慢的 transaction 所花的时间在哪里。我们也可以点击 Error 来查看 erros:
我们可以看到 Error 的详细的信息。