这篇文章介绍了如何利用 Apache Flink 的内置指标零碎以及如何应用 Prometheus 来高效地监控流式应用程序。
为什么抉择 Prometheus?
随着深刻地理解 Prometheus,你会发现一些十分好的性能:
- 服务发现使配置更加容易。Prometheus 反对 consul,etcd,kubernetes 以及各家私有云厂商主动发现。对于监控指标动静发现,这点特地符合 Cloud 时代,利用动静扩缩的特点。咱们无奈设想,在 Cloud 时代,须要运维一直更改配置。
- 开源社区建设了数百个 exporter。基本上涵盖了所有基础设施和支流中间件。
- 工具库可从您的应用程序获取自定义指标。基本上支流开发语言都有对应的工具库。
- 它是 CNCF 旗下的 OSS,是继 Kubernetes 之后的第二个毕业我的项目。Kubernetes 曾经与 Promethues 深度联合,并在其所有服务中公开了 Prometheus 指标。
- Pushgateway,Alermanager 等组件,基本上涵盖了一个残缺的监控生命周期。
Flink 官网曾经提供了对接 Prometheus 的 jar 包,很不便就能够集成。因为本系列文章重点在 Flink on Kubernetes,因而咱们所有的操作都是基于这点开展。
部署 Prometheus
对 k8s 不相熟的同学,能够查阅 k8s 相干文档。因为部署不是本博客的重点,所以咱们间接贴出 yaml 文件:
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: monitor
namespace: kube-system
labels:
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: monitor
labels:
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: monitor
labels:
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: monitor
subjects:
- kind: ServiceAccount
name: monitor
namespace: kube-system
---
apiVersion: v1
kind: ConfigMap
metadata:
labels:
app: monitor
name: monitor
namespace: kube-system
data:
prometheus.yml: |-
global:
scrape_interval: 10s
evaluation_interval: 10s
scrape_configs:
- job_name: kubernetes-pods
kubernetes_sd_configs:
- role: pod
relabel_configs:
- action: keep
regex: true
source_labels:
- __meta_kubernetes_pod_annotation_prometheus_io_scrape
- action: replace
regex: (.+)
source_labels:
- __meta_kubernetes_pod_annotation_prometheus_io_path
target_label: __metrics_path__
- action: replace
regex: ([^:]+)(?::\d+)?;(\d+)
replacement: $1:$2
source_labels:
- __address__
- __meta_kubernetes_pod_annotation_prometheus_io_port
target_label: __address__
- action: labelmap
regex: __meta_kubernetes_pod_label_(.+)
- action: replace
source_labels:
- __meta_kubernetes_namespace
target_label: kubernetes_namespace
- action: replace
source_labels:
- __meta_kubernetes_pod_name
target_label: kubernetes_pod_name
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
labels:
app: monitor
name: monitor
namespace: kube-system
spec:
serviceName: monitor
selector:
matchLabels:
app: monitor
replicas: 1
template:
metadata:
labels:
app: monitor
spec:
containers:
- args:
- --config.file=/etc/prometheus/prometheus.yml
- --storage.tsdb.path=/data/prometheus
- --storage.tsdb.retention.time=10d
image: prom/prometheus:v2.19.0
imagePullPolicy: IfNotPresent
name: prometheus
ports:
- containerPort: 9090
protocol: TCP
readinessProbe:
httpGet:
path: /-/ready
port: 9090
initialDelaySeconds: 30
timeoutSeconds: 30
livenessProbe:
httpGet:
path: /-/healthy
port: 9090
initialDelaySeconds: 30
timeoutSeconds: 30
resources:
limits:
cpu: 1000m
memory: 2018Mi
requests:
cpu: 1000m
memory: 2018Mi
volumeMounts:
- mountPath: /etc/prometheus
name: config-volume
- mountPath: /data
name: monitor-persistent-storage
restartPolicy: Always
priorityClassName: system-cluster-critical
serviceAccountName: monitor
initContainers:
- name: "init-chown-data"
image: "busybox:latest"
imagePullPolicy: "IfNotPresent"
command: ["chown", "-R", "65534:65534", "/data"]
volumeMounts:
- name: monitor-persistent-storage
mountPath: /data
subPath: ""
volumes:
- configMap:
defaultMode: 420
name: monitor
name: config-volume
volumeClaimTemplates:
- metadata:
name: monitor-persistent-storage
namespace: kube-system
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
storageClassName: gp2
---
apiVersion: v1
kind: Service
metadata:
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: nlb
labels:
app: monitor
name: monitor
namespace: kube-system
spec:
ports:
- name: http
port: 9090
protocol: TCP
targetPort: 9090
selector:
app: monitor
type: LoadBalancer
这里咱们简略说下,因为咱们想利用 Prometheus 的 Kubernetes 的服务发现的形式,所以须要 RBAC 受权,受权 prometheus 实例对集群中的 pod 有一些读取权限。
为什么咱们要应用主动发现的形式那?
相比配置文件的形式,主动发现更加灵便。尤其是当你应用的是 flink on native kubernetes,整个 job manager 和 task manager 是依据作业的提交主动创立的,这种动态性,显然是配置文件无奈满足的。
因为咱们的集群在 eks 上,所以大家在应用其余云的时候,须要略做调整。
定制镜像
这里咱们基本上应用上一篇文章介绍的 demo 上,减少监控相干,所以 Dockerfile 如下:
FROM flink
COPY /plugins/metrics-prometheus/flink-metrics-prometheus-1.11.0.jar /opt/flink/lib
RUN mkdir -p $FLINK_HOME/usrlib
COPY ./examples/streaming/WordCount.jar $FLINK_HOME/usrlib/my-flink-job.jar
Flink 的 Classpath 位于 /opt/flink/lib,所以插件的 jar 包须要放到该目录下
作业提交
因为咱们的 Pod 必须减少肯定的标识,从而让 Prometheus 实例能够发现。所以提交命令稍作更改,如下:
./bin/flink run-application -p 8 -t kubernetes-application \
-Dkubernetes.cluster-id=my-first-cluster \
-Dtaskmanager.memory.process.size=2048m \
-Dkubernetes.taskmanager.cpu=2 \
-Dtaskmanager.numberOfTaskSlots=4 \
-Dkubernetes.container.image=iyacontrol/flink-world-count:v0.0.2 \
-Dkubernetes.container.image.pull-policy=Always \
-Dkubernetes.namespace=stream \
-Dkubernetes.jobmanager.service-account=flink \
-Dkubernetes.rest-service.exposed.type=LoadBalancer \
-Dkubernetes.rest-service.annotations=service.beta.kubernetes.io/aws-load-balancer-type:nlb,service.beta.kubernetes.io/aws-load-balancer-internal:true \
-Dkubernetes.jobmanager.annotations=prometheus.io/scrape:true,prometheus.io/port:9249 \
-Dkubernetes.taskmanager.annotations=prometheus.io/scrape:true,prometheus.io/port:9249 \
-Dmetrics.reporters=prom \
-Dmetrics.reporter.prom.class=org.apache.flink.metrics.prometheus.PrometheusReporter \
local:///opt/flink/usrlib/my-flink-job.jar
- 给 jobmanager 和 taskmanager 减少了 annotations
- 减少了 metrcis 相干的配置,指定应用 prometheus reporter
对于 prometheus reporter:
参数:
-
port
– 可选, Prometheus 导出器监听的端口,默认为 9249。为了可能在一台主机上运行报告程序的多个实例(例如,当一个 TaskManager 与 JobManager 并置时),倡议应用这样的端口范畴 9250-9260。 -
filterLabelValueCharacters
– 可选, 指定是否过滤标签值字符。如果启用,则将删除所有不匹配 [a-zA-Z0-9:_] 的字符,否则将不删除任何字符。禁用此选项之前,请确保您的标签值合乎 Prometheus 要求。
成果
提交工作后,咱们看下实际效果。
首先查看 Prometheus 是否发现了咱们的 Pod。
而后查看具体的 metrics,是否被精确抓取。
指标曾经收集,后续大家就能够抉择 grafana 绘图了。或是减少相应的报警规定。例如:
总结
当然除了 Prometheus 被动发现 Pod,而后定期抓取 metrcis 的形式,flink 也反对向 PushGateway 被动 push metrcis。
Flink 通过 Reporter
来向内部零碎提供 metrcis。通过在 conf/flink-conf.yaml
中配置一个或多个 Reporter,能够将 metrcis 公开给内部零碎。这些 Reporter 在启动时将在每个作业和工作管理器上实例化。
所有 Reporter 都必须至多具备 class 或 factory.class 属性。能够 / 应该应用哪个属性取决于 Reporter 的实现。无关更多信息,请参见各个 Reporter 配置局部。一些 Reporter 容许指定报告距离。
指定多个 Reporter 的示例配置:
metrics.reporters: my_jmx_reporter,my_other_reporter
metrics.reporter.my_jmx_reporter.factory.class: org.apache.flink.metrics.jmx.JMXReporterFactory
metrics.reporter.my_jmx_reporter.port: 9020-9040
metrics.reporter.my_jmx_reporter.scope.variables.excludes:job_id;task_attempt_num
metrics.reporter.my_other_reporter.class: org.apache.flink.metrics.graphite.GraphiteReporter
metrics.reporter.my_other_reporter.host: 192.168.1.1
metrics.reporter.my_other_reporter.port: 10000
启动 Flink 时,必须能够拜访蕴含 reporter 的 jar。反对 factory.class 属性的 reporter 能够作为插件加载。否则,必须将 jar 放在 /lib 文件夹中。
你能够通过实现 org.apache.flink.metrics.reporter.MetricReporter 接口来编写本人的 Reporter。如果 reporter 定期发送报告,则还必须实现 Scheduled 接口。通过额定实现 MetricReporterFactory,你的 reporter 也能够作为插件加载。