From 04c95cf8b43d0f1e4e2c31ad241999673ccc0429 Mon Sep 17 00:00:00 2001 From: userjin2123 Date: Wed, 21 Jan 2026 16:52:31 +0900 Subject: [PATCH] =?UTF-8?q?feat=20:=20=EB=AA=A8=EB=8B=88=ED=84=B0=EB=A7=81?= =?UTF-8?q?=EC=9D=84=20=EC=9C=84=ED=95=9C=20=EB=8C=80=EC=8B=9C=EB=B3=B4?= =?UTF-8?q?=EB=93=9C=20=EC=99=80=20yml=20=EB=82=B4=EC=9A=A9=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20-=20spring-api=20-=20websocket-server=20-=20postgre?= =?UTF-8?q?s-exporter=20-=20elasticsearch-exporter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 타겟과 포트 번호는 일단 로컬 환경에 맞춰서 돌려놓았습니다! 운영환경에서는 변경 부탁드려요, 또 데이터 소스도 나중에 환경변수 처리해야할 것 같습니다 --- .gitignore | 1 + docker-compose.yml | 29 + ...\353\213\210\355\204\260\353\247\201.json" | 1906 +++++++++++++++++ grafana/dashboard/Domain Overview.json | 631 ++++++ ...\353\213\210\355\204\260\353\247\201.json" | 1262 +++++++++++ grafana/dashboard/System Overview.json | 980 +++++++++ ...\353\213\210\355\204\260\353\247\201.json" | 817 +++++++ grafana/dashboard/queryTest.json | 696 ++++++ .../provisioning/dashboards/dashboards.yml | 11 + prometheus/prometheus.yml | 20 +- 10 files changed, 6352 insertions(+), 1 deletion(-) create mode 100644 "grafana/dashboard/Content API \354\204\261\353\212\245 \353\252\250\353\213\210\355\204\260\353\247\201.json" create mode 100644 grafana/dashboard/Domain Overview.json create mode 100644 "grafana/dashboard/Playlist API \354\204\261\353\212\245 \353\252\250\353\213\210\355\204\260\353\247\201.json" create mode 100644 grafana/dashboard/System Overview.json create mode 100644 "grafana/dashboard/Watching-session API \354\204\261\353\212\245 \353\252\250\353\213\210\355\204\260\353\247\201.json" create mode 100644 grafana/dashboard/queryTest.json create mode 100644 grafana/provisioning/dashboards/dashboards.yml diff --git a/.gitignore b/.gitignore index 8f2f0b8..e73d733 100644 --- a/.gitignore +++ b/.gitignore @@ -122,3 +122,4 @@ replay_pid* /.gradle /*.log +/data/ \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 40db022..9c8ff94 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -50,6 +50,35 @@ services: networks: - monitoring + postgres-exporter: + image: prometheuscommunity/postgres-exporter + container_name: monitoring-postgres-exporter + restart: unless-stopped + environment: + DATA_SOURCE_NAME: "postgresql://app:app1234@host.docker.internal:5433/app?sslmode=disable" + ports: + - "9187:9187" + extra_hosts: + - "host.docker.internal:host-gateway" + networks: + - monitoring + + elasticsearch-exporter: + image: quay.io/prometheuscommunity/elasticsearch-exporter:latest + container_name: monitoring-elasticsearch-exporter + restart: unless-stopped + command: + - "--es.uri=http://host.docker.internal:9200" + - "--es.all" + - "--es.indices" + - "--es.indices_settings" + - "--es.shards" + ports: + - "9114:9114" + extra_hosts: + - "host.docker.internal:host-gateway" + networks: + - monitoring networks: monitoring: name: monitoring-net \ No newline at end of file diff --git "a/grafana/dashboard/Content API \354\204\261\353\212\245 \353\252\250\353\213\210\355\204\260\353\247\201.json" "b/grafana/dashboard/Content API \354\204\261\353\212\245 \353\252\250\353\213\210\355\204\260\353\247\201.json" new file mode 100644 index 0000000..ee381ee --- /dev/null +++ "b/grafana/dashboard/Content API \354\204\261\353\212\245 \353\252\250\353\213\210\355\204\260\353\247\201.json" @@ -0,0 +1,1906 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 8, + "links": [], + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 1, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(rate(http_server_requests_seconds_bucket{uri=\"/api/contents\", method=\"GET\", job=\"spring-api\"}[1m])) by (le))", + "legendFormat": "p50", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket{uri=\"/api/contents\", method=\"GET\", job=\"spring-api\"}[1m])) by (le))", + "legendFormat": "p95", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(http_server_requests_seconds_bucket{uri=\"/api/contents\", method=\"GET\", job=\"spring-api\"}[1m])) by (le))", + "legendFormat": "p99", + "refId": "C" + } + ], + "title": "API 응답시간 (p50/p95/p99)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 0.02 + }, + { + "color": "red", + "value": 0.05 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 2, + "options": { + "displayMode": "gradient", + "maxVizHeight": 300, + "minVizHeight": 16, + "minVizWidth": 8, + "namePlacement": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true, + "sizing": "auto", + "valueMode": "color" + }, + "pluginVersion": "11.1.4", + "targets": [ + { + "expr": "rate(content_search_elasticsearch_seconds_sum{job=\"spring-api\"}[1m]) / rate(content_search_elasticsearch_seconds_count{job=\"spring-api\"}[1m])", + "legendFormat": "ES 검색", + "refId": "A" + }, + { + "expr": "rate(content_search_count_seconds_sum{job=\"spring-api\"}[1m]) / rate(content_search_count_seconds_count{job=\"spring-api\"}[1m])", + "legendFormat": "ES count", + "refId": "B" + }, + { + "expr": "rate(content_search_mapping_seconds_sum{job=\"spring-api\"}[1m]) / rate(content_search_mapping_seconds_count{job=\"spring-api\"}[1m])", + "legendFormat": "mapping (Redis N+1)", + "refId": "C" + } + ], + "title": "구간별 평균 시간", + "type": "bargauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 50 + }, + { + "color": "red", + "value": 100 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 8 + }, + "id": 3, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.1.4", + "targets": [ + { + "expr": "increase(content_search_elasticsearch_seconds_count{job=\"spring-api\"}[1m])", + "legendFormat": "ES 검색", + "refId": "A" + }, + { + "expr": "increase(content_search_count_seconds_count{job=\"spring-api\"}[1m])", + "legendFormat": "ES count", + "refId": "B" + }, + { + "expr": "increase(content_search_mapping_seconds_count{job=\"spring-api\"}[1m])", + "legendFormat": "mapping", + "refId": "C" + } + ], + "title": "쿼리 호출 횟수 (1분간)", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "mapping 시간이 길면 Redis N+1 문제!\n(20개 content × Redis 조회)", + "fieldConfig": { + "defaults": { + "mappings": [], + "max": 0.1, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 0.02 + }, + { + "color": "red", + "value": 0.04 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 8 + }, + "id": 4, + "options": { + "minVizHeight": 75, + "minVizWidth": 75, + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "sizing": "auto" + }, + "pluginVersion": "11.1.4", + "targets": [ + { + "expr": "rate(content_search_mapping_seconds_sum{job=\"spring-api\"}[1m]) / rate(content_search_mapping_seconds_count{job=\"spring-api\"}[1m])", + "legendFormat": "mapping 평균 시간", + "refId": "A" + } + ], + "title": "Mapping 시간 (N+1 지표)", + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 0.01 + }, + { + "color": "red", + "value": 0.02 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 8 + }, + "id": 5, + "options": { + "minVizHeight": 75, + "minVizWidth": 75, + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "sizing": "auto" + }, + "pluginVersion": "11.1.4", + "targets": [ + { + "expr": "rate(content_search_elasticsearch_seconds_sum{job=\"spring-api\"}[1m]) / rate(content_search_elasticsearch_seconds_count{job=\"spring-api\"}[1m])", + "legendFormat": "ES 검색", + "refId": "A" + } + ], + "title": "ES 검색 평균 시간", + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 14 + }, + "id": 7, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "expr": "rate(content_search_elasticsearch_seconds_sum{job=\"spring-api\"}[1m]) / rate(content_search_elasticsearch_seconds_count{job=\"spring-api\"}[1m])", + "legendFormat": "ES 검색", + "refId": "A" + }, + { + "expr": "rate(content_search_count_seconds_sum{job=\"spring-api\"}[1m]) / rate(content_search_count_seconds_count{job=\"spring-api\"}[1m])", + "legendFormat": "ES count", + "refId": "B" + }, + { + "expr": "rate(content_search_mapping_seconds_sum{job=\"spring-api\"}[1m]) / rate(content_search_mapping_seconds_count{job=\"spring-api\"}[1m])", + "legendFormat": "mapping (Redis N+1)", + "refId": "C" + } + ], + "title": "구간별 시간 추이", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 100 + }, + { + "color": "red", + "value": 500 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 22 + }, + "id": 8, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.1.4", + "targets": [ + { + "expr": "increase(http_server_requests_seconds_count{uri=\"/api/contents\", method=\"GET\", job=\"spring-api\"}[1m])", + "legendFormat": "GET /api/contents", + "refId": "A" + } + ], + "title": "API 호출 횟수 (1분간)", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "green", + "mode": "fixed" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 6, + "y": 22 + }, + "id": 9, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "expr": "rate(http_server_requests_seconds_count{uri=\"/api/contents\", method=\"GET\", job=\"spring-api\"}[1m]) * 60", + "legendFormat": "호출/분", + "refId": "A" + } + ], + "title": "API 호출 횟수 추이", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 10, + "x": 14, + "y": 22 + }, + "id": 10, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "hikaricp_connections_active{job=\"spring-api\"}", + "legendFormat": "Active", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "hikaricp_connections_pending{job=\"spring-api\"}", + "legendFormat": "Pending", + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "hikaricp_connections_idle{job=\"spring-api\"}", + "legendFormat": "Idle", + "refId": "C" + } + ], + "title": "DB 커넥션 추이 - API 서버", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 28 + }, + "id": 100, + "panels": [], + "title": "N+1 최적화 상세 분석", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Before: 50ms대 / After: 0.1ms대\nN+1 최적화 핵심 지표", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "시간 (초)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "line" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "yellow", + "value": 0.01 + }, + { + "color": "red", + "value": 0.05 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 29 + }, + "id": 101, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "expr": "rate(content_search_mapping_seconds_sum{job=\"spring-api\"}[1m]) / rate(content_search_mapping_seconds_count{job=\"spring-api\"}[1m])", + "legendFormat": "Mapping 시간", + "refId": "A" + } + ], + "title": "Mapping 시간 추이", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Redis watcherCount 배치 조회 시간", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "시간 (초)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "line" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "yellow", + "value": 0.005 + }, + { + "color": "red", + "value": 0.01 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 29 + }, + "id": 102, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "expr": "rate(content_search_watcherCount_seconds_sum{job=\"spring-api\"}[1m]) / rate(content_search_watcherCount_seconds_count{job=\"spring-api\"}[1m])", + "legendFormat": "watcherCount 조회", + "refId": "A" + } + ], + "title": "Redis watcherCount 조회 시간 추이", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "ES 검색 및 count 쿼리 시간", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "시간 (초)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 39 + }, + "id": 103, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "expr": "rate(content_search_elasticsearch_seconds_sum{job=\"spring-api\"}[1m]) / rate(content_search_elasticsearch_seconds_count{job=\"spring-api\"}[1m])", + "legendFormat": "ES 검색", + "refId": "A" + }, + { + "expr": "rate(content_search_count_seconds_sum{job=\"spring-api\"}[1m]) / rate(content_search_count_seconds_count{job=\"spring-api\"}[1m])", + "legendFormat": "ES count", + "refId": "B" + } + ], + "title": "ES 쿼리 시간 추이 (검색 + count)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "전체 구간별 호출 횟수 추이", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "호출 수", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 39 + }, + "id": 104, + "options": { + "legend": { + "calcs": [ + "sum", + "mean" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "expr": "rate(content_search_elasticsearch_seconds_count{job=\"spring-api\"}[1m]) * 60", + "legendFormat": "ES 검색", + "refId": "A" + }, + { + "expr": "rate(content_search_count_seconds_count{job=\"spring-api\"}[1m]) * 60", + "legendFormat": "ES count", + "refId": "B" + }, + { + "expr": "rate(content_search_mapping_seconds_count{job=\"spring-api\"}[1m]) * 60", + "legendFormat": "Mapping", + "refId": "C" + }, + { + "expr": "rate(content_search_watcherCount_seconds_count{job=\"spring-api\"}[1m]) * 60", + "legendFormat": "watcherCount", + "refId": "D" + } + ], + "title": "구간별 호출 횟수 추이 (분당)", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 49 + }, + "id": 105, + "panels": [], + "title": "Elasticsearch Cache Metrics", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Query Cache Hit Rate (%). 높을수록 캐시 효율이 좋음", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red" + }, + { + "color": "yellow", + "value": 50 + }, + { + "color": "green", + "value": 80 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 50 + }, + "id": 106, + "options": { + "minVizHeight": 75, + "minVizWidth": 75, + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "sizing": "auto" + }, + "pluginVersion": "11.1.4", + "targets": [ + { + "expr": "100 * sum(rate(elasticsearch_index_stats_query_cache_hits_total{job=\"elasticsearch\"}[5m])) / (sum(rate(elasticsearch_index_stats_query_cache_hits_total{job=\"elasticsearch\"}[5m])) + sum(rate(elasticsearch_index_stats_query_cache_misses_total{job=\"elasticsearch\"}[5m])))", + "legendFormat": "Query Cache Hit Rate", + "refId": "A" + } + ], + "title": "Query Cache Hit Rate", + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Request Cache Hit Rate (%). 높을수록 캐시 효율이 좋음", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red" + }, + { + "color": "yellow", + "value": 50 + }, + { + "color": "green", + "value": 80 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 6, + "y": 50 + }, + "id": 107, + "options": { + "minVizHeight": 75, + "minVizWidth": 75, + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "sizing": "auto" + }, + "pluginVersion": "11.1.4", + "targets": [ + { + "expr": "100 * sum(rate(elasticsearch_index_stats_request_cache_hits_total{job=\"elasticsearch\"}[5m])) / (sum(rate(elasticsearch_index_stats_request_cache_hits_total{job=\"elasticsearch\"}[5m])) + sum(rate(elasticsearch_index_stats_request_cache_misses_total{job=\"elasticsearch\"}[5m])))", + "legendFormat": "Request Cache Hit Rate", + "refId": "A" + } + ], + "title": "Request Cache Hit Rate", + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Cache Hit Rate 추이", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Hit Rate (%)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 50 + }, + "id": 108, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "dfaaun98fjo5cb" + }, + "expr": "100 * sum(rate(elasticsearch_index_stats_query_cache_hits_total{job=\"elasticsearch\"}[5m])) / (sum(rate(elasticsearch_index_stats_query_cache_hits_total{job=\"elasticsearch\"}[5m])) + sum(rate(elasticsearch_index_stats_query_cache_misses_total{job=\"elasticsearch\"}[5m])))", + "legendFormat": "Query Cache", + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "dfaaun98fjo5cb" + }, + "editorMode": "code", + "expr": "100 * sum(rate(elasticsearch_index_stats_request_cache_hits_total{job=\"elasticsearch\"}[5m])) / (sum(rate(elasticsearch_index_stats_request_cache_hits_total{job=\"elasticsearch\"}[5m])) + sum(rate(elasticsearch_index_stats_request_cache_misses_total{job=\"elasticsearch\"}[5m])))", + "legendFormat": "TotalCount Cache", + "range": true, + "refId": "B" + } + ], + "title": "Cache Hit Rate 추이", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Query Cache Hit/Miss 횟수 (초당)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "count/s", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Hit" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Miss" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 56 + }, + "id": 109, + "options": { + "legend": { + "calcs": [ + "sum", + "mean", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "expr": "sum(rate(elasticsearch_index_stats_query_cache_hits_total{job=\"elasticsearch\"}[1m]))", + "legendFormat": "Hit", + "refId": "A" + }, + { + "expr": "sum(rate(elasticsearch_index_stats_query_cache_misses_total{job=\"elasticsearch\"}[1m]))", + "legendFormat": "Miss", + "refId": "B" + } + ], + "title": "Query Cache Hit/Miss", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "TotalCount Cache Hit/Miss 횟수 (초당)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "count/s", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Hit" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Miss" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 56 + }, + "id": 110, + "options": { + "legend": { + "calcs": [ + "sum", + "mean", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "dfaaun98fjo5cb" + }, + "editorMode": "code", + "expr": "sum(rate(elasticsearch_index_stats_request_cache_hits_total{job=\"elasticsearch\"}[1m]))", + "legendFormat": "Hit", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "dfaaun98fjo5cb" + }, + "editorMode": "code", + "expr": "sum(rate(elasticsearch_index_stats_request_cache_misses_total{job=\"elasticsearch\"}[1m]))", + "legendFormat": "Miss", + "range": true, + "refId": "B" + } + ], + "title": "TotalCount Cache Hit/Miss", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "ES Cache 메모리 사용량", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 64 + }, + "id": 111, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "expr": "sum(elasticsearch_index_stats_query_cache_memory_bytes_total{job=\"elasticsearch\"})", + "legendFormat": "Query Cache", + "refId": "A" + }, + { + "expr": "sum(elasticsearch_index_stats_request_cache_memory_bytes_total{job=\"elasticsearch\"})", + "legendFormat": "Request Cache", + "refId": "B" + } + ], + "title": "ES Cache Memory Usage", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "ES 클러스터 기본 정보", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Store Size" + }, + "properties": [ + { + "id": "unit", + "value": "bytes" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 64 + }, + "id": 112, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.1.4", + "targets": [ + { + "expr": "sum(elasticsearch_index_stats_indexing_index_total{job=\"elasticsearch\"})", + "legendFormat": "Total Indexed", + "refId": "A" + }, + { + "expr": "sum(elasticsearch_index_stats_store_size_bytes_total{job=\"elasticsearch\"})", + "legendFormat": "Store Size", + "refId": "B" + }, + { + "expr": "sum(elasticsearch_index_stats_search_query_total{job=\"elasticsearch\"})", + "legendFormat": "Total Queries", + "refId": "C" + } + ], + "title": "ES Cluster Stats", + "type": "stat" + } + ], + "refresh": "5s", + "schemaVersion": 39, + "tags": [ + "content", + "api", + "performance", + "n+1" + ], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "prometheus", + "value": "dfaaun98fjo5cb" + }, + "hide": 0, + "includeAll": false, + "multi": false, + "name": "DS_PROMETHEUS", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + } + ] + }, + "time": { + "from": "now-15m", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "Content API 성능 모니터링", + "uid": "content-api-perf", + "version": 9, + "weekStart": "" +} \ No newline at end of file diff --git a/grafana/dashboard/Domain Overview.json b/grafana/dashboard/Domain Overview.json new file mode 100644 index 0000000..adb53e0 --- /dev/null +++ b/grafana/dashboard/Domain Overview.json @@ -0,0 +1,631 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 7, + "links": [], + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 100, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "expr": "histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket{uri=~\"/api/auth.*\"}[1m])) by (le))", + "legendFormat": "Auth", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket{uri=~\"/api/users.*\"}[1m])) by (le))", + "legendFormat": "User", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket{uri=~\"/api/contents.*\"}[1m])) by (le))", + "legendFormat": "Content", + "refId": "C" + }, + { + "expr": "histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket{uri=~\"/api/playlists.*\"}[1m])) by (le))", + "legendFormat": "Playlist", + "refId": "D" + }, + { + "expr": "histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket{uri=~\"/api/reviews.*\"}[1m])) by (le))", + "legendFormat": "Review", + "refId": "E" + }, + { + "expr": "histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket{uri=~\"/api/follows.*\"}[1m])) by (le))", + "legendFormat": "Follow", + "refId": "F" + }, + { + "expr": "histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket{uri=~\"/api/conversations.*\"}[1m])) by (le))", + "legendFormat": "Conversation", + "refId": "G" + }, + { + "expr": "histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket{uri=~\"/api/notifications.*\"}[1m])) by (le))", + "legendFormat": "Notification", + "refId": "H" + } + ], + "title": "도메인별 p95 응답시간", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "reqps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 101, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "expr": "sum(irate(http_server_requests_seconds_count{uri=~\"/api/auth.*\"}[1m]))", + "legendFormat": "Auth", + "refId": "A" + }, + { + "expr": "sum(irate(http_server_requests_seconds_count{uri=~\"/api/users.*\"}[1m]))", + "legendFormat": "User", + "refId": "B" + }, + { + "expr": "sum(irate(http_server_requests_seconds_count{uri=~\"/api/contents.*\"}[1m]))", + "legendFormat": "Content", + "refId": "C" + }, + { + "expr": "sum(irate(http_server_requests_seconds_count{uri=~\"/api/playlists.*\"}[1m]))", + "legendFormat": "Playlist", + "refId": "D" + }, + { + "expr": "sum(irate(http_server_requests_seconds_count{uri=~\"/api/reviews.*\"}[1m]))", + "legendFormat": "Review", + "refId": "E" + }, + { + "expr": "sum(irate(http_server_requests_seconds_count{uri=~\"/api/follows.*\"}[1m]))", + "legendFormat": "Follow", + "refId": "F" + }, + { + "expr": "sum(irate(http_server_requests_seconds_count{uri=~\"/api/conversations.*\"}[1m]))", + "legendFormat": "Conversation", + "refId": "G" + }, + { + "expr": "sum(irate(http_server_requests_seconds_count{uri=~\"/api/notifications.*\"}[1m]))", + "legendFormat": "Notification", + "refId": "H" + } + ], + "title": "도메인별 TPS (초당 요청)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 0.1 + }, + { + "color": "red", + "value": 0.3 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 102, + "options": { + "displayMode": "gradient", + "maxVizHeight": 300, + "minVizHeight": 16, + "minVizWidth": 8, + "namePlacement": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true, + "sizing": "auto", + "valueMode": "color" + }, + "pluginVersion": "11.1.4", + "targets": [ + { + "expr": "histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket{uri=~\"/api/auth.*\"}[5m])) by (le))", + "legendFormat": "Auth", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket{uri=~\"/api/users.*\"}[5m])) by (le))", + "legendFormat": "User", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket{uri=~\"/api/contents.*\"}[5m])) by (le))", + "legendFormat": "Content", + "refId": "C" + }, + { + "expr": "histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket{uri=~\"/api/playlists.*\"}[5m])) by (le))", + "legendFormat": "Playlist", + "refId": "D" + }, + { + "expr": "histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket{uri=~\"/api/reviews.*\"}[5m])) by (le))", + "legendFormat": "Review", + "refId": "E" + }, + { + "expr": "histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket{uri=~\"/api/follows.*\"}[5m])) by (le))", + "legendFormat": "Follow", + "refId": "F" + }, + { + "expr": "histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket{uri=~\"/api/conversations.*\"}[5m])) by (le))", + "legendFormat": "Conversation", + "refId": "G" + }, + { + "expr": "histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket{uri=~\"/api/notifications.*\"}[5m])) by (le))", + "legendFormat": "Notification", + "refId": "H" + } + ], + "title": "도메인별 p95 현재값", + "type": "bargauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 100 + }, + { + "color": "red", + "value": 500 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 8 + }, + "id": 103, + "options": { + "displayMode": "gradient", + "maxVizHeight": 300, + "minVizHeight": 16, + "minVizWidth": 8, + "namePlacement": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true, + "sizing": "auto", + "valueMode": "color" + }, + "pluginVersion": "11.1.4", + "targets": [ + { + "expr": "sum(increase(http_server_requests_seconds_count{uri=~\"/api/auth.*\"}[1m]))", + "legendFormat": "Auth", + "refId": "A" + }, + { + "expr": "sum(increase(http_server_requests_seconds_count{uri=~\"/api/users.*\"}[1m]))", + "legendFormat": "User", + "refId": "B" + }, + { + "expr": "sum(increase(http_server_requests_seconds_count{uri=~\"/api/contents.*\"}[1m]))", + "legendFormat": "Content", + "refId": "C" + }, + { + "expr": "sum(increase(http_server_requests_seconds_count{uri=~\"/api/playlists.*\"}[1m]))", + "legendFormat": "Playlist", + "refId": "D" + }, + { + "expr": "sum(increase(http_server_requests_seconds_count{uri=~\"/api/reviews.*\"}[1m]))", + "legendFormat": "Review", + "refId": "E" + }, + { + "expr": "sum(increase(http_server_requests_seconds_count{uri=~\"/api/follows.*\"}[1m]))", + "legendFormat": "Follow", + "refId": "F" + }, + { + "expr": "sum(increase(http_server_requests_seconds_count{uri=~\"/api/conversations.*\"}[1m]))", + "legendFormat": "Conversation", + "refId": "G" + }, + { + "expr": "sum(increase(http_server_requests_seconds_count{uri=~\"/api/notifications.*\"}[1m]))", + "legendFormat": "Notification", + "refId": "H" + } + ], + "title": "도메인별 호출량 (1분간)", + "type": "bargauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "reqps" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 16 + }, + "id": 104, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "expr": "sum(irate(http_server_requests_seconds_count{uri=~\"/api/auth.*\", status=~\"5..\"}[1m])) or vector(0)", + "legendFormat": "Auth", + "refId": "A" + }, + { + "expr": "sum(irate(http_server_requests_seconds_count{uri=~\"/api/users.*\", status=~\"5..\"}[1m])) or vector(0)", + "legendFormat": "User", + "refId": "B" + }, + { + "expr": "sum(irate(http_server_requests_seconds_count{uri=~\"/api/contents.*\", status=~\"5..\"}[1m])) or vector(0)", + "legendFormat": "Content", + "refId": "C" + }, + { + "expr": "sum(irate(http_server_requests_seconds_count{uri=~\"/api/playlists.*\", status=~\"5..\"}[1m])) or vector(0)", + "legendFormat": "Playlist", + "refId": "D" + }, + { + "expr": "sum(irate(http_server_requests_seconds_count{uri=~\"/api/reviews.*\", status=~\"5..\"}[1m])) or vector(0)", + "legendFormat": "Review", + "refId": "E" + }, + { + "expr": "sum(irate(http_server_requests_seconds_count{uri=~\"/api/follows.*\", status=~\"5..\"}[1m])) or vector(0)", + "legendFormat": "Follow", + "refId": "F" + }, + { + "expr": "sum(irate(http_server_requests_seconds_count{uri=~\"/api/conversations.*\", status=~\"5..\"}[1m])) or vector(0)", + "legendFormat": "Conversation", + "refId": "G" + }, + { + "expr": "sum(irate(http_server_requests_seconds_count{uri=~\"/api/notifications.*\", status=~\"5..\"}[1m])) or vector(0)", + "legendFormat": "Notification", + "refId": "H" + } + ], + "title": "도메인별 에러율 (5xx)", + "type": "timeseries" + } + ], + "refresh": "10s", + "schemaVersion": 39, + "tags": [], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "prometheus", + "value": "dfaaun98fjo5cb" + }, + "hide": 0, + "includeAll": false, + "multi": false, + "name": "DS_PROMETHEUS", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + } + ] + }, + "time": { + "from": "now-15m", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "Domain Overview", + "uid": "domain-overview", + "version": 4, + "weekStart": "" +} \ No newline at end of file diff --git "a/grafana/dashboard/Playlist API \354\204\261\353\212\245 \353\252\250\353\213\210\355\204\260\353\247\201.json" "b/grafana/dashboard/Playlist API \354\204\261\353\212\245 \353\252\250\353\213\210\355\204\260\353\247\201.json" new file mode 100644 index 0000000..f950601 --- /dev/null +++ "b/grafana/dashboard/Playlist API \354\204\261\353\212\245 \353\252\250\353\213\210\355\204\260\353\247\201.json" @@ -0,0 +1,1262 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 5, + "links": [], + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 1, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(rate(http_server_requests_seconds_bucket{uri=\"/api/playlists\", method=\"GET\", job=\"spring-api\"}[1m])) by (le))", + "legendFormat": "p50", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket{uri=\"/api/playlists\", method=\"GET\", job=\"spring-api\"}[1m])) by (le))", + "legendFormat": "p95", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(http_server_requests_seconds_bucket{uri=\"/api/playlists\", method=\"GET\", job=\"spring-api\"}[1m])) by (le))", + "legendFormat": "p99", + "refId": "C" + } + ], + "title": "API 응답시간 (p50/p95/p99)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 0.1 + }, + { + "color": "red", + "value": 0.3 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 2, + "options": { + "displayMode": "gradient", + "maxVizHeight": 300, + "minVizHeight": 16, + "minVizWidth": 8, + "namePlacement": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true, + "sizing": "auto", + "valueMode": "color" + }, + "pluginVersion": "11.1.4", + "targets": [ + { + "expr": "rate(playlist_search_mapping_seconds_sum{job=\"spring-api\"}[1m]) / rate(playlist_search_mapping_seconds_count{job=\"spring-api\"}[1m])", + "legendFormat": "mapping (DTO 변환)", + "refId": "A" + }, + { + "expr": "rate(playlist_search_repository_main_seconds_sum{job=\"spring-api\"}[1m]) / rate(playlist_search_repository_main_seconds_count{job=\"spring-api\"}[1m])", + "legendFormat": "repository.main", + "refId": "B" + }, + { + "expr": "rate(playlist_search_repository_count_seconds_sum{job=\"spring-api\"}[1m]) / rate(playlist_search_repository_count_seconds_count{job=\"spring-api\"}[1m])", + "legendFormat": "repository.count", + "refId": "C" + } + ], + "title": "구간별 평균 시간", + "type": "bargauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 50 + }, + { + "color": "red", + "value": 100 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 8 + }, + "id": 3, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.1.4", + "targets": [ + { + "expr": "increase(playlist_search_repository_main_seconds_count{job=\"spring-api\"}[1m])", + "legendFormat": "main 쿼리", + "refId": "A" + }, + { + "expr": "increase(playlist_toDto_subscriberCount_seconds_count{job=\"spring-api\"}[1m])", + "legendFormat": "toDto 호출", + "refId": "B" + }, + { + "expr": "increase(playlist_toContentSummary_tags_seconds_count{job=\"spring-api\"}[1m])", + "legendFormat": "tags 쿼리", + "refId": "C" + } + ], + "title": "N+1 호출 횟수 (1분간)", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "max": 50, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 10 + }, + { + "color": "red", + "value": 20 + } + ] + }, + "unit": "x" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 8 + }, + "id": 4, + "options": { + "minVizHeight": 75, + "minVizWidth": 75, + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "sizing": "auto" + }, + "pluginVersion": "11.1.4", + "targets": [ + { + "expr": "increase(playlist_toDto_subscriberCount_seconds_count{job=\"spring-api\"}[1m]) / increase(playlist_search_repository_main_seconds_count{job=\"spring-api\"}[1m])", + "legendFormat": "toDto / main", + "refId": "A" + } + ], + "title": "N+1 비율 (toDto / main)", + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 5 + }, + { + "color": "red", + "value": 8 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 8 + }, + "id": 5, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.1.4", + "targets": [ + { + "expr": "hikaricp_connections_active{job=\"spring-api\"}", + "legendFormat": "Active", + "refId": "A" + }, + { + "expr": "hikaricp_connections_pending{job=\"spring-api\"}", + "legendFormat": "Pending", + "refId": "B" + }, + { + "expr": "hikaricp_connections_idle{job=\"spring-api\"}", + "legendFormat": "Idle", + "refId": "C" + } + ], + "title": "DB 커넥션 - API 서버", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [], + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 14 + }, + "id": 6, + "options": { + "legend": { + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "expr": "rate(playlist_toDto_subscriberCount_seconds_sum{job=\"spring-api\"}[1m])", + "legendFormat": "subscriberCount", + "refId": "A" + }, + { + "expr": "rate(playlist_toDto_subscribedByMe_seconds_sum{job=\"spring-api\"}[1m])", + "legendFormat": "subscribedByMe", + "refId": "B" + }, + { + "expr": "rate(playlist_toDto_contents_seconds_sum{job=\"spring-api\"}[1m])", + "legendFormat": "contents", + "refId": "C" + } + ], + "title": "toDto 내부 시간 분포", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 16, + "x": 8, + "y": 14 + }, + "id": 7, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "expr": "rate(playlist_search_repository_main_seconds_count{job=\"spring-api\"}[1m]) * 60", + "legendFormat": "main 쿼리/분", + "refId": "A" + }, + { + "expr": "rate(playlist_toDto_subscriberCount_seconds_count{job=\"spring-api\"}[1m]) * 60", + "legendFormat": "toDto/분", + "refId": "B" + }, + { + "expr": "rate(playlist_toContentSummary_tags_seconds_count{job=\"spring-api\"}[1m]) * 60", + "legendFormat": "tags 쿼리/분", + "refId": "C" + } + ], + "title": "호출 횟수 추이", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 22 + }, + "id": 8, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "expr": "rate(playlist_search_mapping_seconds_sum{job=\"spring-api\"}[1m]) / rate(playlist_search_mapping_seconds_count{job=\"spring-api\"}[1m])", + "legendFormat": "mapping (DTO 변환)", + "refId": "A" + }, + { + "expr": "rate(playlist_search_repository_main_seconds_sum{job=\"spring-api\"}[1m]) / rate(playlist_search_repository_main_seconds_count{job=\"spring-api\"}[1m])", + "legendFormat": "repository.main", + "refId": "B" + }, + { + "expr": "rate(playlist_toDto_contents_seconds_sum{job=\"spring-api\"}[1m]) / rate(playlist_toDto_contents_seconds_count{job=\"spring-api\"}[1m])", + "legendFormat": "toDto.contents", + "refId": "C" + }, + { + "expr": "rate(playlist_toContentSummary_tags_seconds_sum{job=\"spring-api\"}[1m]) / rate(playlist_toContentSummary_tags_seconds_count{job=\"spring-api\"}[1m])", + "legendFormat": "tags 쿼리", + "refId": "D" + } + ], + "title": "구간별 시간 추이", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "yellow", + "value": 100 + }, + { + "color": "red", + "value": 500 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 30 + }, + "id": 9, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.1.4", + "targets": [ + { + "expr": "increase(http_server_requests_seconds_count{uri=\"/api/playlists\", method=\"GET\", job=\"spring-api\"}[1m])", + "legendFormat": "GET /api/playlists", + "refId": "A" + } + ], + "title": "API 호출 횟수 (1분간)", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "green", + "mode": "fixed" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 6, + "y": 30 + }, + "id": 11, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "expr": "rate(http_server_requests_seconds_count{uri=\"/api/playlists\", method=\"GET\", job=\"spring-api\"}[1m]) * 60", + "legendFormat": "호출/분", + "refId": "A" + } + ], + "title": "API 호출 횟수 추이", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 10, + "x": 14, + "y": 30 + }, + "id": 10, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "expr": "hikaricp_connections_active{job=\"spring-api\"}", + "legendFormat": "Active", + "refId": "A" + }, + { + "expr": "hikaricp_connections_pending{job=\"spring-api\"}", + "legendFormat": "Pending", + "refId": "B" + }, + { + "expr": "hikaricp_connections_idle{job=\"spring-api\"}", + "legendFormat": "Idle", + "refId": "C" + } + ], + "title": "DB 커넥션 추이 - API 서버", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 36 + }, + "id": 20, + "panels": [], + "title": "배치 쿼리 메트릭", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "yellow", + "value": 0.01 + }, + { + "color": "red", + "value": 0.05 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 37 + }, + "id": 21, + "options": { + "displayMode": "gradient", + "maxVizHeight": 300, + "minVizHeight": 16, + "minVizWidth": 8, + "namePlacement": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true, + "sizing": "auto", + "valueMode": "color" + }, + "pluginVersion": "11.1.4", + "targets": [ + { + "expr": "rate(playlist_search_subscriberCount_seconds_sum{job=\"spring-api\"}[1m]) / rate(playlist_search_subscriberCount_seconds_count{job=\"spring-api\"}[1m])", + "legendFormat": "subscriberCount (배치)", + "refId": "A" + }, + { + "expr": "rate(playlist_search_subscribedByMe_seconds_sum{job=\"spring-api\"}[1m]) / rate(playlist_search_subscribedByMe_seconds_count{job=\"spring-api\"}[1m])", + "legendFormat": "subscribedByMe (배치)", + "refId": "B" + }, + { + "expr": "rate(playlist_search_contents_seconds_sum{job=\"spring-api\"}[1m]) / rate(playlist_search_contents_seconds_count{job=\"spring-api\"}[1m])", + "legendFormat": "contents (배치)", + "refId": "C" + }, + { + "expr": "rate(playlist_search_tags_seconds_sum{job=\"spring-api\"}[1m]) / rate(playlist_search_tags_seconds_count{job=\"spring-api\"}[1m])", + "legendFormat": "tags (배치)", + "refId": "D" + }, + { + "expr": "rate(playlist_search_mapping_seconds_sum{job=\"spring-api\"}[1m]) / rate(playlist_search_mapping_seconds_count{job=\"spring-api\"}[1m])", + "legendFormat": "mapping (DTO 변환)", + "refId": "E" + } + ], + "title": "배치 쿼리 구간별 평균 시간", + "type": "bargauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "시간 (초)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 37 + }, + "id": 22, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "expr": "rate(playlist_search_subscriberCount_seconds_sum{job=\"spring-api\"}[1m]) / rate(playlist_search_subscriberCount_seconds_count{job=\"spring-api\"}[1m])", + "legendFormat": "subscriberCount", + "refId": "A" + }, + { + "expr": "rate(playlist_search_subscribedByMe_seconds_sum{job=\"spring-api\"}[1m]) / rate(playlist_search_subscribedByMe_seconds_count{job=\"spring-api\"}[1m])", + "legendFormat": "subscribedByMe", + "refId": "B" + }, + { + "expr": "rate(playlist_search_contents_seconds_sum{job=\"spring-api\"}[1m]) / rate(playlist_search_contents_seconds_count{job=\"spring-api\"}[1m])", + "legendFormat": "contents", + "refId": "C" + }, + { + "expr": "rate(playlist_search_tags_seconds_sum{job=\"spring-api\"}[1m]) / rate(playlist_search_tags_seconds_count{job=\"spring-api\"}[1m])", + "legendFormat": "tags", + "refId": "D" + }, + { + "expr": "rate(playlist_search_mapping_seconds_sum{job=\"spring-api\"}[1m]) / rate(playlist_search_mapping_seconds_count{job=\"spring-api\"}[1m])", + "legendFormat": "mapping", + "refId": "E" + } + ], + "title": "배치 쿼리 시간 추이", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "배치 쿼리 총 시간 = subscriberCount + subscribedByMe + contents + tags + mapping", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 45 + }, + "id": 23, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "expr": "(rate(playlist_search_subscriberCount_seconds_sum{job=\"spring-api\"}[1m]) / rate(playlist_search_subscriberCount_seconds_count{job=\"spring-api\"}[1m])) + (rate(playlist_search_subscribedByMe_seconds_sum{job=\"spring-api\"}[1m]) / rate(playlist_search_subscribedByMe_seconds_count{job=\"spring-api\"}[1m])) + (rate(playlist_search_contents_seconds_sum{job=\"spring-api\"}[1m]) / rate(playlist_search_contents_seconds_count{job=\"spring-api\"}[1m])) + (rate(playlist_search_tags_seconds_sum{job=\"spring-api\"}[1m]) / rate(playlist_search_tags_seconds_count{job=\"spring-api\"}[1m])) + (rate(playlist_search_mapping_seconds_sum{job=\"spring-api\"}[1m]) / rate(playlist_search_mapping_seconds_count{job=\"spring-api\"}[1m]))", + "legendFormat": "After (배치 총합)", + "refId": "A" + }, + { + "expr": "rate(playlist_search_mapping_seconds_sum{job=\"spring-api\"}[1m]) / rate(playlist_search_mapping_seconds_count{job=\"spring-api\"}[1m])", + "legendFormat": "Before (mapping only - N+1 포함)", + "refId": "B" + } + ], + "title": "Before vs After 처리 시간 비교", + "type": "timeseries" + } + ], + "refresh": "5s", + "schemaVersion": 39, + "tags": [], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "prometheus", + "value": "dfaaun98fjo5cb" + }, + "hide": 0, + "includeAll": false, + "multi": false, + "name": "DS_PROMETHEUS", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + } + ] + }, + "time": { + "from": "now-15m", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "Playlist API 성능 모니터링", + "uid": "playlist-api-perf", + "version": 6, + "weekStart": "" +} \ No newline at end of file diff --git a/grafana/dashboard/System Overview.json b/grafana/dashboard/System Overview.json new file mode 100644 index 0000000..ffe6c04 --- /dev/null +++ b/grafana/dashboard/System Overview.json @@ -0,0 +1,980 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 6, + "links": [], + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 1, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "expr": "histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket{uri=~\"/api/.*\"}[1m])) by (le))", + "legendFormat": "p95 전체", + "refId": "A" + } + ], + "title": "전체 API p95 응답시간", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "reqps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 2, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "expr": "sum(irate(http_server_requests_seconds_count{uri=~\"/api/.*\"}[1m]))", + "legendFormat": "TPS", + "refId": "A" + } + ], + "title": "전체 TPS (초당 요청)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 0.1 + }, + { + "color": "red", + "value": 0.3 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 3, + "options": { + "displayMode": "gradient", + "maxVizHeight": 300, + "minVizHeight": 16, + "minVizWidth": 8, + "namePlacement": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true, + "sizing": "auto", + "valueMode": "color" + }, + "pluginVersion": "11.1.4", + "targets": [ + { + "expr": "topk(10, histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket{uri=~\"/api/.*\"}[5m])) by (le, uri)))", + "legendFormat": "{{uri}}", + "refId": "A" + } + ], + "title": "API별 p95 응답시간 (상위 10)", + "type": "bargauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 100 + }, + { + "color": "red", + "value": 500 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 8 + }, + "id": 4, + "options": { + "displayMode": "gradient", + "maxVizHeight": 300, + "minVizHeight": 16, + "minVizWidth": 8, + "namePlacement": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true, + "sizing": "auto", + "valueMode": "color" + }, + "pluginVersion": "11.1.4", + "targets": [ + { + "expr": "topk(10, sum(increase(http_server_requests_seconds_count{uri=~\"/api/.*\"}[1m])) by (uri))", + "legendFormat": "{{uri}}", + "refId": "A" + } + ], + "title": "API별 호출량 (1분간, 상위 10)", + "type": "bargauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "reqps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 18 + }, + "id": 5, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "expr": "sum(irate(http_server_requests_seconds_count{uri=~\"/api/.*\", status=~\"4..\"}[1m]))", + "legendFormat": "4xx", + "refId": "A" + }, + { + "expr": "sum(irate(http_server_requests_seconds_count{uri=~\"/api/.*\", status=~\"5..\"}[1m]))", + "legendFormat": "5xx", + "refId": "B" + } + ], + "title": "에러율 (4xx, 5xx)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 5 + }, + { + "color": "red", + "value": 8 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 12, + "y": 18 + }, + "id": 6, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.1.4", + "targets": [ + { + "expr": "hikaricp_connections_active{job=\"spring-api\"}", + "legendFormat": "Active", + "refId": "A" + }, + { + "expr": "hikaricp_connections_pending{job=\"spring-api\"}", + "legendFormat": "Pending", + "refId": "B" + }, + { + "expr": "hikaricp_connections_idle{job=\"spring-api\"}", + "legendFormat": "Idle", + "refId": "C" + } + ], + "title": "DB 커넥션 - API 서버", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 5 + }, + { + "color": "red", + "value": 8 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 18, + "y": 18 + }, + "id": 11, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.1.4", + "targets": [ + { + "expr": "hikaricp_connections_active{job=\"websocket-server\"}", + "legendFormat": "Active", + "refId": "A" + }, + { + "expr": "hikaricp_connections_pending{job=\"websocket-server\"}", + "legendFormat": "Pending", + "refId": "B" + }, + { + "expr": "hikaricp_connections_idle{job=\"websocket-server\"}", + "legendFormat": "Idle", + "refId": "C" + } + ], + "title": "DB 커넥션 - WS 서버", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 22 + }, + "id": 8, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "expr": "hikaricp_connections_active{job=\"spring-api\"}", + "legendFormat": "Active", + "refId": "A" + }, + { + "expr": "hikaricp_connections_pending{job=\"spring-api\"}", + "legendFormat": "Pending", + "refId": "B" + } + ], + "title": "DB 커넥션 추이 - API 서버", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decmbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 26 + }, + "id": 7, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "expr": "jvm_memory_used_bytes{area=\"heap\", job=\"spring-api\"} / 1024 / 1024", + "legendFormat": "{{id}} Used", + "refId": "A" + }, + { + "expr": "sum(jvm_memory_max_bytes{area=\"heap\", job=\"spring-api\"}) / 1024 / 1024", + "legendFormat": "Max", + "refId": "B" + } + ], + "title": "JVM Heap - API 서버", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decmbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 6, + "y": 26 + }, + "id": 12, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "expr": "jvm_memory_used_bytes{area=\"heap\", job=\"websocket-server\"} / 1024 / 1024", + "legendFormat": "{{id}} Used", + "refId": "A" + }, + { + "expr": "sum(jvm_memory_max_bytes{area=\"heap\", job=\"websocket-server\"}) / 1024 / 1024", + "legendFormat": "Max", + "refId": "B" + } + ], + "title": "JVM Heap - WS 서버", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 28 + }, + "id": 13, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "expr": "hikaricp_connections_active{job=\"websocket-server\"}", + "legendFormat": "Active", + "refId": "A" + }, + { + "expr": "hikaricp_connections_pending{job=\"websocket-server\"}", + "legendFormat": "Pending", + "refId": "B" + } + ], + "title": "DB 커넥션 추이 - WS 서버", + "type": "timeseries" + } + ], + "refresh": "10s", + "schemaVersion": 39, + "tags": [], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "prometheus", + "value": "dfaaun98fjo5cb" + }, + "hide": 0, + "includeAll": false, + "multi": false, + "name": "DS_PROMETHEUS", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + } + ] + }, + "time": { + "from": "now-15m", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "System Overview", + "uid": "system-overview", + "version": 4, + "weekStart": "" +} \ No newline at end of file diff --git "a/grafana/dashboard/Watching-session API \354\204\261\353\212\245 \353\252\250\353\213\210\355\204\260\353\247\201.json" "b/grafana/dashboard/Watching-session API \354\204\261\353\212\245 \353\252\250\353\213\210\355\204\260\353\247\201.json" new file mode 100644 index 0000000..ad9e041 --- /dev/null +++ "b/grafana/dashboard/Watching-session API \354\204\261\353\212\245 \353\252\250\353\213\210\355\204\260\353\247\201.json" @@ -0,0 +1,817 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": null, + "links": [], + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 1, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(rate(http_server_requests_seconds_bucket{uri=~\"/api/contents/.*/watching-sessions\", method=\"GET\"}[1m])) by (le))", + "legendFormat": "p50", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket{uri=~\"/api/contents/.*/watching-sessions\", method=\"GET\"}[1m])) by (le))", + "legendFormat": "p95", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(http_server_requests_seconds_bucket{uri=~\"/api/contents/.*/watching-sessions\", method=\"GET\"}[1m])) by (le))", + "legendFormat": "p99", + "refId": "C" + } + ], + "title": "API 응답시간 (p50/p95/p99)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 0.005 + }, + { + "color": "red", + "value": 0.01 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 2, + "options": { + "displayMode": "gradient", + "maxVizHeight": 300, + "minVizHeight": 16, + "minVizWidth": 8, + "namePlacement": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true, + "sizing": "auto", + "valueMode": "color" + }, + "pluginVersion": "11.1.4", + "targets": [ + { + "expr": "rate(watching_session_redis_find_seconds_sum[1m]) / rate(watching_session_redis_find_seconds_count[1m])", + "legendFormat": "Redis: 세션 조회", + "refId": "A" + }, + { + "expr": "rate(watching_session_redis_hasmore_seconds_sum[1m]) / rate(watching_session_redis_hasmore_seconds_count[1m])", + "legendFormat": "Redis: hasMore", + "refId": "B" + }, + { + "expr": "rate(watching_session_redis_count_seconds_sum[1m]) / rate(watching_session_redis_count_seconds_count[1m])", + "legendFormat": "Redis: count", + "refId": "C" + }, + { + "expr": "rate(watching_session_db_user_seconds_sum[1m]) / rate(watching_session_db_user_seconds_count[1m])", + "legendFormat": "DB: User 배치", + "refId": "D" + }, + { + "expr": "rate(watching_session_db_content_seconds_sum[1m]) / rate(watching_session_db_content_seconds_count[1m])", + "legendFormat": "DB: Content", + "refId": "E" + }, + { + "expr": "rate(watching_session_db_tag_seconds_sum[1m]) / rate(watching_session_db_tag_seconds_count[1m])", + "legendFormat": "DB: Tag", + "refId": "F" + } + ], + "title": "구간별 평균 시간", + "type": "bargauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 50 + }, + { + "color": "red", + "value": 100 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 3, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.1.4", + "targets": [ + { + "expr": "increase(watching_session_redis_find_seconds_count[1m])", + "legendFormat": "Redis 세션 조회", + "refId": "A" + }, + { + "expr": "increase(watching_session_db_user_seconds_count[1m])", + "legendFormat": "DB User", + "refId": "B" + }, + { + "expr": "increase(watching_session_db_content_seconds_count[1m])", + "legendFormat": "DB Content", + "refId": "C" + } + ], + "title": "호출 횟수 (1분간)", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Redis 총 시간 vs DB 총 시간 비교", + "fieldConfig": { + "defaults": { + "mappings": [], + "max": 0.05, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 0.01 + }, + { + "color": "red", + "value": 0.02 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 12, + "y": 8 + }, + "id": 4, + "options": { + "minVizHeight": 75, + "minVizWidth": 75, + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "sizing": "auto" + }, + "pluginVersion": "11.1.4", + "targets": [ + { + "expr": "(rate(watching_session_redis_find_seconds_sum[1m]) + rate(watching_session_redis_hasmore_seconds_sum[1m]) + rate(watching_session_redis_count_seconds_sum[1m])) / (rate(watching_session_redis_find_seconds_count[1m]) + rate(watching_session_redis_hasmore_seconds_count[1m]) + rate(watching_session_redis_count_seconds_count[1m]))", + "legendFormat": "Redis Total", + "refId": "A" + } + ], + "title": "Redis 평균 총 시간", + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "DB 쿼리 총 시간", + "fieldConfig": { + "defaults": { + "mappings": [], + "max": 0.05, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 0.01 + }, + { + "color": "red", + "value": 0.02 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 18, + "y": 8 + }, + "id": 5, + "options": { + "minVizHeight": 75, + "minVizWidth": 75, + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "sizing": "auto" + }, + "pluginVersion": "11.1.4", + "targets": [ + { + "expr": "(rate(watching_session_db_user_seconds_sum[1m]) + rate(watching_session_db_content_seconds_sum[1m]) + rate(watching_session_db_tag_seconds_sum[1m])) / (rate(watching_session_db_user_seconds_count[1m]) + rate(watching_session_db_content_seconds_count[1m]) + rate(watching_session_db_tag_seconds_count[1m]))", + "legendFormat": "DB Total", + "refId": "A" + } + ], + "title": "DB 평균 총 시간", + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/Redis.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/DB.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 14 + }, + "id": 6, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "expr": "rate(watching_session_redis_find_seconds_sum[1m]) / rate(watching_session_redis_find_seconds_count[1m])", + "legendFormat": "Redis: 세션 조회", + "refId": "A" + }, + { + "expr": "rate(watching_session_redis_hasmore_seconds_sum[1m]) / rate(watching_session_redis_hasmore_seconds_count[1m])", + "legendFormat": "Redis: hasMore", + "refId": "B" + }, + { + "expr": "rate(watching_session_redis_count_seconds_sum[1m]) / rate(watching_session_redis_count_seconds_count[1m])", + "legendFormat": "Redis: count", + "refId": "C" + }, + { + "expr": "rate(watching_session_db_user_seconds_sum[1m]) / rate(watching_session_db_user_seconds_count[1m])", + "legendFormat": "DB: User 배치", + "refId": "D" + }, + { + "expr": "rate(watching_session_db_content_seconds_sum[1m]) / rate(watching_session_db_content_seconds_count[1m])", + "legendFormat": "DB: Content", + "refId": "E" + }, + { + "expr": "rate(watching_session_db_tag_seconds_sum[1m]) / rate(watching_session_db_tag_seconds_count[1m])", + "legendFormat": "DB: Tag", + "refId": "F" + } + ], + "title": "구간별 응답시간 추이", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "bars", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 22 + }, + "id": 7, + "options": { + "legend": { + "calcs": [ + "sum" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "expr": "increase(watching_session_redis_find_seconds_count[1m])", + "legendFormat": "Redis: 세션 조회", + "refId": "A" + }, + { + "expr": "increase(watching_session_redis_hasmore_seconds_count[1m])", + "legendFormat": "Redis: hasMore", + "refId": "B" + }, + { + "expr": "increase(watching_session_redis_count_seconds_count[1m])", + "legendFormat": "Redis: count", + "refId": "C" + }, + { + "expr": "increase(watching_session_db_user_seconds_count[1m])", + "legendFormat": "DB: User", + "refId": "D" + }, + { + "expr": "increase(watching_session_db_content_seconds_count[1m])", + "legendFormat": "DB: Content", + "refId": "E" + }, + { + "expr": "increase(watching_session_db_tag_seconds_count[1m])", + "legendFormat": "DB: Tag", + "refId": "F" + } + ], + "title": "호출 횟수 추이 (Stacked)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Redis vs DB 시간 비율", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [], + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Redis" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "DB" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 22 + }, + "id": 8, + "options": { + "displayLabels": [ + "name", + "percent" + ], + "legend": { + "displayMode": "table", + "placement": "right", + "showLegend": true, + "values": [ + "value", + "percent" + ] + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "11.1.4", + "targets": [ + { + "expr": "sum(rate(watching_session_redis_find_seconds_sum[1m])) + sum(rate(watching_session_redis_hasmore_seconds_sum[1m])) + sum(rate(watching_session_redis_count_seconds_sum[1m]))", + "legendFormat": "Redis", + "refId": "A" + }, + { + "expr": "sum(rate(watching_session_db_user_seconds_sum[1m])) + sum(rate(watching_session_db_content_seconds_sum[1m])) + sum(rate(watching_session_db_tag_seconds_sum[1m]))", + "legendFormat": "DB", + "refId": "B" + } + ], + "title": "Redis vs DB 시간 비율", + "type": "piechart" + } + ], + "refresh": "5s", + "schemaVersion": 39, + "tags": [ + "watching-session", + "websocket", + "performance", + "redis" + ], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "prometheus", + "value": "prometheus" + }, + "hide": 0, + "includeAll": false, + "multi": false, + "name": "DS_PROMETHEUS", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + } + ] + }, + "time": { + "from": "now-15m", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "WatchingSession 성능 모니터링", + "uid": "watching-session-perf", + "version": 1, + "weekStart": "" +} diff --git a/grafana/dashboard/queryTest.json b/grafana/dashboard/queryTest.json new file mode 100644 index 0000000..bde7476 --- /dev/null +++ b/grafana/dashboard/queryTest.json @@ -0,0 +1,696 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 1, + "links": [], + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "dfaaun98fjo5cb" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 4, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "dfaaun98fjo5cb" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "tomcat_threads_busy_threads", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "busy_threads", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "tomcat_threads_busy_threads", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "dfaaun98fjo5cb" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 5, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "dfaaun98fjo5cb" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "tomcat_threads_current_threads", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "current_threads", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "tomcat_threads_current_threads", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "dfaaun98fjo5cb" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 2, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "dfaaun98fjo5cb" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "hikaricp_connections_pending", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{job}}-pending", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "hikaricp_pending", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "dfaaun98fjo5cb" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "spring-api-actvie" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": false, + "viz": true + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 8 + }, + "id": 1, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "dfaaun98fjo5cb" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "hikaricp_connections_active", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{job}}-actvie", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "hikmaricp_active", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "dfaaun98fjo5cb" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 16 + }, + "id": 6, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "dfaaun98fjo5cb" + }, + "editorMode": "code", + "expr": "rate(pg_stat_database_xact_commit{datname=\"app\"}[5m])", + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "DB 트랜잭션/초", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "dfaaun98fjo5cb" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 1 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "spring-api-timeout" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "spring-api-timeout" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": false, + "viz": true + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 16 + }, + "id": 3, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "dfaaun98fjo5cb" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "hikaricp_connections_timeout_total", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{job}}-timeout", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "hikaricp_timeout", + "type": "timeseries" + } + ], + "refresh": "5s", + "schemaVersion": 39, + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "2026-01-16T03:22:32.463Z", + "to": "2026-01-16T04:39:15.742Z" + }, + "timepicker": {}, + "timezone": "browser", + "title": "queryTest", + "uid": "afab72s7j32tca", + "version": 7, + "weekStart": "" +} \ No newline at end of file diff --git a/grafana/provisioning/dashboards/dashboards.yml b/grafana/provisioning/dashboards/dashboards.yml new file mode 100644 index 0000000..391325b --- /dev/null +++ b/grafana/provisioning/dashboards/dashboards.yml @@ -0,0 +1,11 @@ +apiVersion: 1 + +providers: + - name: 'default' + orgId: 1 + folder: '' + type: file + disableDeletion: false + editable: true + options: + path: /var/lib/grafana/dashboards \ No newline at end of file diff --git a/prometheus/prometheus.yml b/prometheus/prometheus.yml index dccf57e..aedeb62 100644 --- a/prometheus/prometheus.yml +++ b/prometheus/prometheus.yml @@ -9,4 +9,22 @@ scrape_configs: - job_name: "pushgateway" honor_labels: true static_configs: - - targets: ["pushgateway:9091"] \ No newline at end of file + - targets: ["pushgateway:9091"] + + - job_name: "spring-api" + static_configs: + - targets: [ "host.docker.internal:80" ] + metrics_path: /actuator/core/prometheus + + - job_name: "websocket-server" + static_configs: + - targets: [ "host.docker.internal:80" ] + metrics_path: /actuator/ws/prometheus + + - job_name: "postgres" + static_configs: + - targets: [ "postgres-exporter:9187" ] + + - job_name: "elasticsearch" + static_configs: + - targets: [ "elasticsearch-exporter:9114" ]