? ? ? ?最近公司有幾個服務遇到了瓶頸,也就是數據量增加了,沒有人發(fā)現,這不是缺少一個監(jiān)控服務和告警的系統嗎???
? ? ? 主要需求是監(jiān)控每個服務,順帶監(jiān)控一下服務器和一些中間件,這里采集的2種,zabbix和prometheus,由于我們要監(jiān)控的是Docker容器中的服務,最終選擇prometheus。
如下:
一 實現功能
- 服務宕機,不能提供服務,飛書收到告警信息。
- 容器中服務占用分配內存達到50, 飛書收到預警信息。
- 容器中服務中JVM堆內存占用達到80, 飛書收到預警信息。
- 服務發(fā)生OOM后,服務可以立刻重啟。
?二:流程圖
?三 步驟
確定要監(jiān)控的docker服務, 這里以公司的A服務為例子
- 查看服務的Dockerfile 和run.sh? ?
Dockerfile是構建docker鏡像,run.sh是啟動服務用的
?1.1 Dockerfile中java執(zhí)行命令添加:
"-XX:+HeapDumpOnOutOfMemoryError","-XX:HeapDumpPath=/temp/dump","-XX:+ExitOnOutOfMemoryError","-XX:MaxRAMPercentage=75.0"
-XX:+HeapDumpOnOutOfMemoryError:參數表示當JVM發(fā)生OOM時,自動生成DUMP文件
-XX:HeapDumpPath=/temp/dump:生成dump目錄文件的位置
-XX:+ExitOnOutOfMemoryError:JVM在第一次出現內存不足錯誤時退出,啟動JVM實例
-XX:MaxRAMPercentage=75.0:?這為JVM定義了75%的總內存限制
查看服務目前容器大小,和占用內存大小,保證占用內存穩(wěn)定在30%一下。
docker stats dcda4228b794
?這邊找了一個47%的,只給了1G的容器大小。需求中超過50%就會告警。
如果超過50%,需要在啟動容器的run.sh命令中提升初始容器大小
修改--memory 1024m \ ??--memory-swap 1024m \的值,是容器的內存大小
以上是容器要做的一些調整,也是自己定義的規(guī)則。
2. Idea中找到A應用,修改POM和 application.properties文件
application.properties中添加
management.endpoint.health.show-details=always
management.endpoints.web.exposure.include=*
這邊要注意,如果你是yml文件?management.endpoints.web.exposure.include=*,
這個 * 一定要加 ''單引號,*在yml文件中是通配符。
POM中添加,目的是當前服務可以提供一些監(jiān)控指標
<dependency>
????<groupId>org.springframework.boot</groupId>
????<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
????<groupId>io.micrometer</groupId>
????<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
?注意,如果你的服務屬于對外接口訪問服務,有Shiro攔截的話要配置
filterChainDefinitionMap.put("/actuator/prometheus", "anon");
至此完成代碼的整改,可以提交代碼,部署服務。
確定服務正常啟動:輸入docker ps -a? (不加-a就看正常運行的服務,-a是看所有的服務,包括停止的)
?去服務器廠商放開當前服務對外的端口號,主要是對指定監(jiān)控的服務器放開,不是所有
環(huán)境地址訪問 ?http://ip:port/actuator/prometheus
看到如下,就是提供的指標數據
?3 docker容器監(jiān)控服務
部署prometheus,alertmanager,garfana, 還有一個推消息給飛書的服務, 這個大家如果想找到怎么部署,可以留言,我整理一下,寫出來。不過后面有時間我也會更新這邊部署監(jiān)控文章的。
1. cadvisor 是容器內個服務的監(jiān)控指標提取
2. prometheus-webhook-feishu 是網上找的一個開源的飛書通知服務
3.alertmanager是告警管理 --通知2下發(fā)告警的
4.grafana是可視化大屏,對prometheus采集的數據可視化展示
5.node-exporter 是服務器監(jiān)控,提取服務器的指標數據
6.prometheus 是核心的監(jiān)控服務
4. 配置prometheus
進入prometheus
?看到這幾個文件夾/文件,其中主要配置實例在prometheus.yml中,rules文件下是配置告警規(guī)則的。
進入prometheus.yml仿照- job_name: 自己創(chuàng)建一個
- job_name: "A"????# 監(jiān)控的job名稱
????metrics_path: '/actuator/prometheus'???# 監(jiān)控的指標路徑
????static_configs:
??????- targets: ['ip:port']????#監(jiān)控的服務器和端口端口已經開放
????????labels:
??????????serviceId: A-snapshot???#服務id告警展示
??????????serviceName: A-web??#服務名稱 ??告警展示
重啟prometheus
docker restart prometheus
訪問http://ip:9090/查看配置的任務,如下up狀態(tài)代表服務正常啟動,配置任務成功。
?rules下有配置服務器/服務的告警規(guī)則
1. 服務器內存使用超過98%告警規(guī)則
??(node_memory_MemTotal_bytes - (node_memory_MemFree_bytes+node_memory_Buffers_bytes+node_memory_Cached_bytes )) / node_memory_MemTotal_bytes * 100 > 98
?(node_filesystem_size_bytes - node_filesystem_avail_bytes) / node_filesystem_size_bytes * 100 > 95
會對配置在prometheus中沒有job都做監(jiān)控,up==0標識改服務宕機,提示。
可以做驗證
?docker stop A服務容器id
?
飛書收到這個通知,如何配置?prometheus-alertmanager-feishu的流程后續(xù)會同步上
4.配置其他告警規(guī)則 這里配置容器內存超過50提示,和服務jvm中堆占用80提示
配置路徑/minitor/prometheus/rules
可以自己重新定義一個yml ,下面yml下面所有規(guī)則都會被prometheus識別,一般按照項目建一個文件
容器內存超過50
groups:
# 組名。報警規(guī)則組名稱
- name: A服務內存預警
rules:
- alert: a服務內存使用率預警
# expr:基于PromQL表達式告警觸發(fā)條件,用于計算是否有時間序列滿足該條件。
expr: container_memory_usage_bytes{image="a:latest"}/container_spec_memory_limit_bytes{image="a:latest"} * 100 > 50
# for:評估等待時間,可選參數。用于表示只有當觸發(fā)條件持續(xù)一段時間后才發(fā)送告警。在等待期間新產生告警的狀態(tài)為pending。
for: 20s # for語句會使 Prometheus 服務等待指定的時間, 然后執(zhí)行查詢表達式。(for 表示告警持續(xù)的時長,若持續(xù)時長小于該時間就不發(fā)給alertmanager了,大于
該時間再發(fā)。for的值不要小于prometheus中的scrape_interval,例如scrape_interval為30s,for為15s,如果觸發(fā)告警規(guī)則,則再經過for時長后也一定會告警,這是因為>最新的度量指標還沒有拉取,在15s時仍會用原來值進行計算。另外,要注意的是只有在第一次觸發(fā)告警時才會等待(for)時長。)
# labels:自定義標簽,允許用戶指定要附加到告警上的一組附加標簽。
labels:
# severity: 指定告警級別。有三種等級,分別為 warning, critical 和 emergency 。嚴重等級依次遞增。
severity: critical
# annotations: 附加信息,比如用于描述告警詳細信息的文字等,annotations的內容在告警產生時會一同作為參數發(fā)送到Alertmanager。
annotations:
title: "a服務內存使用率預警"
serviceName: "{{ $labels.serviceName }}"
instance: "{{ $labels.instance }}"
value: "{{ $value }}"
btn: "點擊查看詳情 :玫瑰:"
link: "http://xxxxxxxxx:9090/targets"
template: "**${serviceName}**(${instance})正式服務內存使用率已經超過閾值 **50%**, 請及時處理!\n當前值: ${value}%"
expr:container_memory_usage_bytes{image="a:latest"}/container_spec_memory_limit_bytes{image="a:latest"} * 100 > 50
這個可以在之前prometheus查看
服務jvm中堆占用80提示
- name: A服務堆內存超高預警
rules:
- alert: A服務堆內存使用率超高預警
expr: sum(jvm_memory_used_bytes{serviceId="a", area="heap"})*100/sum(jvm_memory_max_bytes{serviceId="a", area="heap"}) > 80
for: 20s
labels:
severity: red
annotations:
title: "a服務堆內存使用率超高預警"
serviceName: "{{ $labels.serviceName }}"
instance: "{{ $labels.instance }}"
value: "{{ $value }}"
btn: "點擊查看詳情 :玫瑰:"
link: "http://xxxxxxxx:9090/targets"
template: "**${serviceName}**(${instance})正式環(huán)境服務內存使用率已經超過閾值 **80%**, 請及時處理!\n當前值: ${value}%"
?expr: sum(jvm_memory_used_bytes{serviceId="job中配置的", area="heap"})*100/sum(jvm_memory_max_bytes{serviceId="job中配置的", area="heap"}) > 80
?
?重啟prometheus
5 驗證容器內存超過50 ?堆內存超80 ?和出現OOM后容器自動重啟服務
?在服務中加一個測試oom的接口, 正式發(fā)布后,這個接口要去掉
如下: 會不斷的生成不回收的對象 /dev/d
package xxx;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
*/
@Slf4j
@RestController
@RequestMapping("dev")
public class Controller {
@RequestMapping("/a")
public Integer message() {
log.info(">>>>info");
log.debug(">>>>>Debug");
return Runtime.getRuntime().availableProcessors();
}
@RequestMapping("/d")
public String messaged(HttpServletRequest request) throws InterruptedException {
log.info(">>>>info");
log.debug(">>>>>Debug");
List<Object> list = new ArrayList<>();
new Thread(new Runnable() {
@Override
public void run() {
List<Object> list2 = new ArrayList<>();
int initSize = 1024 * 1024 * 300;
Map<String, Object> map = new HashMap<>();
int i= 0;
while(true) {
try{
Thread.sleep(5000);
} catch(Exception e) {
e.printStackTrace();
}
//每次添加50M
int userMemory = 1024*1024*10;
i++;
map.put("userMemory" + i, new byte[userMemory]);
list.add(map);
list2.add(map);
}
}
}).start();
return "OK";
}
}
這里對A服務運行dev/d接口
先看dev/a 是看運行的cpu個數,驗證服務是否啟動
這時候別著急讓服務OOM
先看cAdvisor,容器監(jiān)控都靠他,監(jiān)控別的服務器容器也要在對應服務器上安裝。
環(huán)境運行: http://ip:19190/
點擊Docker Containers可以看具體容器的信息,找到你要配置的容器A
里面包括很多參數指標信息,這里先看容器內存
?
?和docker stats運行的值基本一致
Jvm堆內存使用占比,我們可以根據cAdvisor提供的
jvm_memory_used_bytes
jvm_memory_max_bytes
執(zhí)行接口,查看對應數據,驗證告警信息。
?等會我們執(zhí)行增加jvm堆內存的接口,要看容器的內存使用,和jvm中堆占比都上升,知道堆內存占比100%發(fā)生OOM后,容器重啟服務,過程中,會提示容器內存使用超過50%,堆內存使用超過80%
1. 系統OOM 產生dump文件 之前第一步有配置
2. 系統OOM 會立刻重啟服務,保證不宕機,服務可用
3. 容器內存超50% 告警
4. 堆內存超80% 告警
第一個:
在docker下dump/temp發(fā)現?java_pid6.hprof 文件--后面講
第二個 服務立刻重啟,并且輸入dev/a? 還是可以訪問的
第三個 收到告警
這個過程,百分比是慢慢上升的可以通過docker stats/cadvisor看數據
- 繼續(xù)監(jiān)控
?此時堆內存已經達到91 > 80
?容器內存也快達到,瓶頸
?
- 繼續(xù)監(jiān)控,突然會服務重新,出現OOM,
也可以docker logs -f xxx查看日志,此時對象都釋放掉了
又回到服務初始容器內存占比和jvm堆使用占比
至此,完成了服務宕機告警,容器內存超50%告警,堆內存超80%告警,服務出現OOM后服務重啟。
6 可視化監(jiān)控的頁面grafana
可以通過看大屏數據,感覺還挺牛的,可以自定義。
http://xxxxx:3000/??? grafana可視化監(jiān)控,是對prometheus采集的數據做大屏展示
如:展示剛剛容器中jvm的一些指標信息? 配置模板id:4701 用過grafana你就知道了。相當于一個模版id
?展示當前服務器中所有容器的cpu,內存,硬盤等使用情況
模板id: 116000 是查看當前容器中各服務,cpu,內存使用情況。
?也可以對整個服務器做監(jiān)控展示? ? 模板id:8919
grafana的更多常用模板地址:Dashboards | Grafana Labs?
目前監(jiān)控的實現方案如上,有好的優(yōu)化方案和新的監(jiān)控點,告警點互相討論。
7?上面代碼出現OOM,簡單排查過程
主要是分析dump文件
通過寫的代碼,看到開啟一個線程,不停的給ArrayList插入一個value是10M的Map
在配置java啟動中,我們把oom自動生成的dump文件拿出來
進到容器中把文件cp到宿主機
?分析工具:MemoryAnalyzer? 導入文件
1 進入Leak Suspects ?2進入Dominator Tree
進入Leak Suspects 點擊detail ?發(fā)現出現一堆HashMap沒有回收,這和我們的代碼問題一致
?
?進入 Dominator Tree查看
發(fā)現有很多的HashMap key 是遞增的,value是一個10M的Byte[]
代碼都是自己寫的。哈哈。
?定位代碼:
服務地址:
Promethues: ??http://xxxx:9090
Grafana: http://xxxx:3000
Alertmanager: http://xxxx:19093文章來源:http://www.zghlxwxcb.cn/news/detail-621318.html
cAdvisor的所有容器監(jiān)控 http://xxxxx:19190/containers/文章來源地址http://www.zghlxwxcb.cn/news/detail-621318.html
到了這里,關于prometheus 配置服務器監(jiān)控、服務監(jiān)控、容器中服務監(jiān)控與告警的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!