前言

近期发现业务高峰期时刻会出现CPU繁忙导致的timeout异常,通过监控来看是因为Node上面的一些Pod突发抢占了大量CPU导致的。

问: 没有限制CPU吗?是不是限制的CPU使用值就可以解决了呢?

解: 其实不能根本解决这个问题,因为使用的容器引擎是Docker,而Docker是使用了cgroups技术,这就引入了一个老大难的问题,cgroup的隔离性。当问题发生时并没有办法把异常CPU进程直接摁住,而会有短暂的高峰,现象为:限制了CPU为2核,突发时CPU可能是4、5、6等,然后容器会被kill掉,K8S会尝试重建容器。

那么该如何解决?

  1. 使用隔离性更好的容器引擎,如 kata(VM级别)。
  2. 优化程序

方案1

我们可以知道方案1解决的比较彻底,而且只需要全局处理一次即可,但技术比较新颖,不知道会不会带来其它问题,我们之后准备拿出部分Node尝试kata container。

方案2

对应用开发者要求比较高,需要对应的开发者针对性介入,短期收益很高,我们先部署了这种。

如何实施?

我们知道程序在运行中,除非特别严重的BUG,CPU高峰一般非常短暂,这时候靠人肉抓包基本上是来不及的,也很耗费精力,我们就希望有一个程序能在CPU达到一定阈值的时候自动抓取线程堆栈来事后针对性优化,并且一定时间内只允许运行一次防止循环抓包导致程序不可用。

根据要实现的最终效果我们发现与Grafana、Prometheus的告警机制十分接近,我们要做的就是接收告警的webhook,去对应的容器中获取线程堆栈就行。

于是我们利用了 Grafana ,写了一个程序来完成这个功能。

项目信息

开发语言: Go、Shell

项目地址: https://github.com/majian159/k8s-java-debug-daemon

k8s-java-debug-daemon

利用了 Grafana 的告警机制,配合阿里的 arthas,来完成高CPU使用率线程的堆栈抓取。

整体流程如下:

  1. 为 Grafana 添加 webhook 类型的告警通知渠道,地址为该程序的 url(默认的hooks路径为 /hooks)。
  2. 配置Grafana图表,并设置告警阈值
  3. 当 webhook 触发时,程序会自动将 craw.sh 脚本拷贝到对应 Pod 的容器中并执行。
  4. 程序将 stdout 保存到本地文件。

效果预览



默认行为

  • 每 node 同时运行执行数为10

    可以在 ./internal/defaultvalue.go 中更改
    var defaultNodeLockManager = nodelock.NewLockManager(10)
  • 默认使用集群内的Master配置

    可以在 ./internal/defaultvalue.go 中更改
    func DefaultKubernetesClient(){}
    
    // default
    func getConfigByInCluster(){} func getConfigByOutOfCluster(){}
  • 默认使用并实现了一个基于本地文件的堆栈存储器, 路径位于工作路径下的 stacks

    可以在 ./internal/defaultvalue.go 中更改
    func GetDefaultNodeLockManager(){}
  • 默认取最繁忙的前50个线程的堆栈信息 (可在 craw.sh 中修改)
  • 采集样本时间为2秒 (可在 craw.sh 中修改)

如何使用

Docker Image

majian159/java-debug-daemon

为 Grafana 新建一个通知频道

注意点

  1. 需要打开 Send reminders, 不然 Grafana 默认在触发告警后一直没有解决不会重复发送告警
  2. Send reminder every 可以控制最快多久告警一次

为 Grafana 新建一个告警图表

如果嫌麻烦可以直接导入以下配置, 在自行更改

{
"datasource": "prometheus",
"alert": {
"alertRuleTags": {},
"conditions": [
{
"evaluator": {
"params": [
1
],
"type": "gt"
},
"operator": {
"type": "and"
},
"query": {
"params": [
"A",
"5m",
"now"
]
},
"reducer": {
"params": [],
"type": "last"
},
"type": "query"
}
],
"executionErrorState": "keep_state",
"for": "10s",
"frequency": "30s",
"handler": 1,
"name": "Pod 高CPU堆栈抓取",
"noDataState": "no_data",
"notifications": [
{
"uid": "AGOJRCqWz"
}
]
},
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 9,
"w": 24,
"x": 0,
"y": 2
},
"hiddenSeries": false,
"id": 14,
"legend": {
"alignAsTable": true,
"avg": true,
"current": true,
"max": true,
"min": false,
"rightSide": true,
"show": true,
"total": false,
"values": true
},
"lines": true,
"linewidth": 1,
"nullPointMode": "null",
"options": {
"dataLinks": []
},
"percentage": false,
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "container_memory_working_set_bytes{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", image!=\"\", container!=\"POD\"}* on (namespace, pod) group_left(node) max by(namespace, pod, node, container) (kube_pod_info)",
"legendFormat": "{{node}} - {{namespace}} - {{pod}} - {{container}}",
"refId": "A"
}
],
"thresholds": [
{
"colorMode": "critical",
"fill": true,
"line": true,
"op": "gt",
"value": 1
}
],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Pod CPU",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
}

Queries配置

Metrics 中填写

container_memory_working_set_bytes{job="kubelet", metrics_path="/metrics/cadvisor", image!="", container!="POD"} * on (namespace, pod) group_left(node) max by(namespace, pod, node, container) (kube_pod_info)

Legend 中填写

{{node}} - {{namespace}} - {{pod}} - {{container}}

配置完如下:

Alert配置

IS ABOVE

CPU使用值,这边配置的是超过1核CPU就报警, 可以根据需要自己调节

Evaluate every

每多久计算一次

For

Pedding时间

配置完应该如下:

构建

二进制

# 为当前系统平台构建
make # 指定目标系统, GOOS: linux darwin window freebsd
make GOOS=linux

Docker镜像

make docker

# 自定义镜像tag
make docker IMAGE=test

巧用Grafana和Arthas自动抓取K8S中异常Java进程的线程堆栈的更多相关文章

  1. SQL Server定时自动抓取耗时SQL并归档数据发邮件脚本分享

    SQL Server定时自动抓取耗时SQL并归档数据发邮件脚本分享 第一步建库和建表 USE [master] GO CREATE DATABASE [MonitorElapsedHighSQL] G ...

  2. IIS崩溃时自动抓取Dump

    背景:在客户现场,IIS有时会崩溃,开发环境没法重现这个bug,唯有抓取IIS的崩溃是的Dump文件分析. IIS崩溃时自动抓取Dump,需要满足下面几个条件 1.启动 Windows Error R ...

  3. 自动抓取java堆栈

    参数1 进程名字,参数2 最大线程数 例: pid为8888,达到1000个线程时自动抓取堆栈信息 ./autojstack.sh 8888 1000 & #!/bin/bashfileNam ...

  4. SQL Server定时自动抓取耗时SQL并归档数据脚本分享

    原文:SQL Server定时自动抓取耗时SQL并归档数据脚本分享 SQL Server定时自动抓取耗时SQL并归档数据脚本分享 第一步建库 USE [master] GO CREATE DATABA ...

  5. APP自动化框架LazyAndroid使用手册(2)--元素自动抓取

    作者:黄书力 概述 前面的一篇博文简要介绍了安卓自动化测试框架LazyAndroid的组成结构和基本功能,本文将详细描述此框架中元素自动抓取工具lazy-uiautomaterviewer的使用方法. ...

  6. 学习笔记CB010:递归神经网络、LSTM、自动抓取字幕

    递归神经网络可存储记忆神经网络,LSTM是其中一种,在NLP领域应用效果不错. 递归神经网络(RNN),时间递归神经网络(recurrent neural network),结构递归神经网络(recu ...

  7. 【VIP视频网站项目】VIP视频网站项目v1.0.3版本发布啦(程序一键安装+电影后台自动抓取+代码结构调整)

    在线体验地址:http://vip.52tech.tech/ GIthub源码:https://github.com/xiugangzhang/vip.github.io 项目预览 主页面 登录页面 ...

  8. scrapy自动抓取蛋壳公寓最新房源信息并存入sql数据库

    利用scrapy抓取蛋壳公寓上的房源信息,以北京市为例,目标url:https://www.dankegongyu.com/room/bj 思路分析 每次更新最新消息,都是在第一页上显示,因此考虑隔一 ...

  9. scrapy实现自动抓取51job并分别保存到redis,mongo和mysql数据库中

    项目简介 利用scrapy抓取51job上的python招聘信息,关键词为“python”,范围:全国 利用redis的set数据类型保存抓取过的url,现实避免重复抓取: 利用脚本实现每隔一段时间, ...

随机推荐

  1. coding++:win10家庭版升级专业版方案

    win10家庭版升级专业版密钥: VK7JG-NPHTM-C97JM-9MPGT-3V66T 4N7JM-CV98F-WY9XX-9D8CF-369TT FMPND-XFTD4-67FJC-HDR8C ...

  2. JS 剑指Offer(三) 替换字符串中的空格

    请实现一个函数,把字符串 s 中的每个空格替换成"%20". 实现这个函数的方法很简单,在JS中可以直接应用正则表达式,代码如下 直接将全局中的space换成%20,一行代码搞定 ...

  3. scikit_learn分类器详解

    1       分类 分类是将事物按特性进行分类,例如将手写数字图片分类为对应的数字. 1.1  MINIST数字图片集分类 MINST就是一个70000张规格较小的手写数字图片,如何将他们分类为对应 ...

  4. Flink| 实时需要分析

    ========================实时流量统计 1. 实时热门商品HotItems 每隔 5 分钟输出最近一小时内点击量最多的前 N 个商品. 抽取出业务时间戳,告诉 Flink 框架基 ...

  5. 【php】文件的上传与下载

    一. 生活中常见的地方: a) 例如邮箱.空间.文库.百度云.微爱等地方,都可以看到文件的上传和下载的应用,因此,上传和下载的功能非常重要!二. PHP当中的文件上传和下载 a) 我们需要进行一些设置 ...

  6. mybatis源码配置文件解析之一:解析properties标签

    mybatis作为日常开发的常用ORM框架,在开发中起着很重要的作用,了解其源码对日常的开发有很大的帮助.源码版本为:3-3.4.x,可执行到github进行下载. 从这篇文章开始逐一分析mybati ...

  7. EntityFramework Core 3.x上下文构造函数可以注入实例呢?

    前言 今天讨论的话题来自一位微信好友遇到问题后请求我的帮助,当然他的意图并不是本文标题,只是我将其根本原因进行了一个概括,接下来我们一起来探索标题的问号最终的答案是怎样的呢? 上下文构造函数是否可以注 ...

  8. MTK Android Driver :Key

    MTK Android Driver :Key 1.按键配置(根据原理图):DCT(Driver Customization Tool): ..\mediatek\custom\prj\kernel\ ...

  9. matplotlib PyQt5 nivigationBar 中pan和zoom功能的探索

    为matplotlib生成的图添加编辑条,我们导入NavigationToolbar2QT from matplotlib.backends.backend_qt5agg import Navigat ...

  10. tf.train.MomentumOptimizer 优化器

    tf.train.MomentumOptimizer( learning_rate, momentum, use_locking=False, use_nesterov=False, name='Mo ...