promql

taeni·2025년 4월 1일

7일간 최대 memory 사용률

max by (namespace, statefulset) (
  label_replace(
    max_over_time(container_memory_usage_bytes{container="backup-agent"}[7d]),
    "statefulset", "$1", "pod", "^(.*)-[0-9]+$"
  )
)

7일간 최대 cpu 사용률

max by (namespace, statefulset) (
  label_replace(
    max_over_time(
      rate(container_cpu_usage_seconds_total{container="backup-agent"}[5m])[7d:]
    ) * 1000,
    "statefulset", "$1", "pod", "^(.*)-[0-9]+$"
  )
)

MEMORY SUM

{ "size": 0, "query": { "bool": { "must": [ { "range": { "@timestamp": { "gte": "now-1h", "lte": "now" } } }, { "prefix": { "service.address": "10.156.133.121" } } ] } }, "aggs": { "max_memory_used_rss": { "max": { "field": "redis.info.memory.used.rss" } }, "total_max_memory_used_rss": { "sum": { "field": "redis.info.memory.used.rss" } } } }

memory 사용률 40% 미만

GET your_index/_search
{
  "_source": [
    "rscId",
    "service.address"
  ],
  "script_fields": {
    "used_memory_percent": {
      "script": {
        "source": "doc['redis.info.memory.used.value'].value * 100 / doc['redis.info.memory.max.value'].value",
        "lang": "painless"
      }
    }
  },
  "query": {
    "bool": {
      "must": [
        {
          "range": {
            "redis.info.memory.max.value": {
              "gte": 4294967296
            }
          }
        },
        {
          "script": {
            "script": {
              "source": "doc['redis.info.memory.used.value'].value < doc['redis.info.memory.max.value'].value * 0.4",
              "lang": "painless"
            }
          }
        }
      ]
    }
  }
}

rscId로 group

GET your_index/_search
{
  "size": 0,
  "aggs": {
    "group_by_rscId": {
      "terms": {
        "field": "rscId.keyword",
        "size": 10000
      },
      "aggs": {
        "group_by_service_address": {
          "terms": {
            "field": "service.address.keyword",
            "size": 10000
          },
          "aggs": {
            "top_hits": {
              "top_hits": {
                "_source": ["rscId", "service.address", "redis.info.memory.max.value"],
                "size": 1
              }
            },
            "avg_used_memory_percent": {
              "bucket_script": {
                "buckets_path": {
                  "used": "avg_used_memory",
                  "max": "avg_max_memory"
                },
                "script": "params.used * 100 / params.max"
              }
            },
            "avg_used_memory": {
              "avg": {
                "field": "redis.info.memory.used.value"
              }
            },
            "avg_max_memory": {
              "avg": {
                "field": "redis.info.memory.max.value"
              }
            }
          }
        }
      }
    }
  },
  "query": {
    "bool": {
      "must": [
        {
          "range": {
            "redis.info.memory.max.value": {
              "gte": 4294967296
            }
          }
        },
        {
          "script": {
            "script": {
              "source": "doc['redis.info.memory.used.value'].value < doc['redis.info.memory.max.value'].value * 0.4",
              "lang": "painless"
            }
          }
        }
      ]
    }
  }
}
<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Elasticsearch 결과 변환</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 20px; }
        textarea { width: 100%; height: 200px; margin-top: 10px; }
        button { margin: 10px 0; padding: 10px; cursor: pointer; }
        table { width: 100%; border-collapse: collapse; margin-top: 20px; }
        th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
        th { background-color: #f4f4f4; }
    </style>
</head>
<body>

    <h2>Elasticsearch 결과 변환</h2>

    <label for="jsonInput">Elasticsearch JSON 응답 입력:</label>
    <textarea id="jsonInput" placeholder="여기에 Elasticsearch JSON 데이터를 입력하세요..."></textarea>
    <button onclick="processInput()">변환하기</button>

    <table id="resultTable">
        <thead>
            <tr>
                <th>rscId</th>
                <th>Service Address</th>
                <th>Max Memory</th>
                <th>Max Used Memory Percent</th>
            </tr>
        </thead>
        <tbody>
            <!-- 결과가 여기에 추가됨 -->
        </tbody>
    </table>

    <script>
        function formatElasticsearchData(response) {
            const result = [];
            
            try {
                response.aggregations.group_by_rscId.buckets.forEach(rscBucket => {
                    const rscId = rscBucket.key;

                    rscBucket.group_by_service_address.buckets.forEach(serviceBucket => {
                        const serviceAddress = serviceBucket.key;
                        const maxMemory = serviceBucket.top_hits.hits.hits[0]._source["redis.info.memory.max.value"];
                        const maxUsedMemoryPercent = serviceBucket.avg_used_memory_percent.value.toFixed(2); // 소수점 2자리

                        result.push({ rscId, serviceAddress, maxMemory, maxUsedMemoryPercent });
                    });
                });
            } catch (error) {
                alert("잘못된 JSON 형식입니다. 올바른 데이터를 입력하세요.");
                console.error("Parsing error:", error);
                return [];
            }

            return result;
        }

        function processInput() {
            const inputText = document.getElementById("jsonInput").value.trim();
            if (!inputText) {
                alert("JSON 데이터를 입력하세요.");
                return;
            }

            try {
                const jsonData = JSON.parse(inputText);
                const results = formatElasticsearchData(jsonData);
                displayResults(results);
            } catch (error) {
                alert("JSON 파싱에 실패했습니다. 올바른 JSON을 입력하세요.");
                console.error("JSON Parse Error:", error);
            }
        }

        function displayResults(results) {
            const tableBody = document.querySelector("#resultTable tbody");
            tableBody.innerHTML = ""; // 기존 내용 초기화

            if (results.length === 0) {
                tableBody.innerHTML = "<tr><td colspan='4' style='text-align:center;'>데이터가 없습니다.</td></tr>";
                return;
            }

            results.forEach(item => {
                const row = `<tr>
                    <td>${item.rscId}</td>
                    <td>${item.serviceAddress}</td>
                    <td>${item.maxMemory.toLocaleString()} Bytes</td>
                    <td>${item.maxUsedMemoryPercent} %</td>
                </tr>`;
                tableBody.innerHTML += row;
            });
        }
    </script>

</body>
</html>
{
  "query": {
    "bool": {
      "must": {
        "script": {
          "script": {
            "source": """
              if (!doc.containsKey('redis.info.memory.used.rss') || !doc.containsKey('redis.info.memory.max.value')) {
                return false;
              }
              if (doc['redis.info.memory.used.rss'].size() == 0 || doc['redis.info.memory.max.value'].size() == 0) {
                return false;
              }
              return doc['redis.info.memory.used.rss'].value > doc['redis.info.memory.max.value'].value;
            """,
            "lang": "painless"
          }
        }
      },
      "must_not": {
        "prefix": {
          "rscId": "cube"
        }
      }
    }
  }
}
profile
정태인의 블로그

0개의 댓글