[Elasticsearch] ELK쿼리로 API 호출 건수 집계해보기 (+Kibana Dev tools aggs field)
Why
API 호출 추이를 Whatap 필터링으로도 확인 가능하나,
특정 조건을 걸거나, 집계를 하고싶어서
ELK 쿼리로 직접 작성해보았다.
https://www.whatap.io/
내가 원했던 쿼리는
1. 메뉴 검색 API 관련, 호출 건수 집계
2. 시나리오 구분
2.1 검색바에서 Enter 치는 경우 : "/api/common/v1/search-menu-list?*"
2.2 검색바에서 입력값 변경되는 경우(interval로 작동) : "/api/common/v1/search-menu-list-by-typing?*"
3. 날짜 범위 설정
4. 실행 환경 구분 : prd, stage, dev, local
5. 주기별 집계 (일별/주별/월별/년별)
/* API 호출건수 조회 쿼리 (url별 환경별 날짜별) */
GET api-log-index/_search
{
"size" : 0,
"query": {
"bool": {
"should": [
{
"wildcard": {
"request_uri": "/api/common/v1/search-menu-list-by-typing?*"
}
},
{
"wildcard": {
"request_uri": "/api/common/v1/search-menu-list?*"
}
}
]
}
},
"aggs": {
"custom_field_1_timestamp": {
"date_range": {
"field": "@timestamp",
"format":"yyyy-MM-dd-HH:mm:ss",
"time_zone":"+09:00",
"ranges": [
{
"from": "2024-09-01-00:00:00",
"to": "2025-10-17-00:00:00"
}
]
},
"aggs": {
"custom_field_2_uri": {
"terms": {
"script": {
"source": "def uri = doc['request_uri'].value; if (uri.startsWith('/api/common/v1/search-menu-list-by-typing?')){ return 'typing'; } else { return 'enter';}"
},
"min_doc_count": 1
},
"aggs": {
"custom_field_3_env": {
"terms": {
"field": "fields.env"
},
"aggs": {
"custom_field_4_day_count": {
"date_histogram": {
"field": "@timestamp",
"calendar_interval": "day"
}
},
"custom_field_5_week_count": {
"date_histogram": {
"field": "@timestamp",
"calendar_interval": "week"
}
},
"custom_field_6_month_count": {
"date_histogram": {
"field": "@timestamp",
"calendar_interval": "month"
}
},
"custom_field_7_year_count": {
"date_histogram": {
"field": "@timestamp",
"calendar_interval": "year"
}
}
}
}
}
}
}
}
}
}
결과 분석
- 24년9월1일부터 ~ 24년10월17일 오늘까지
- 총 19055번의 메뉴API가 호출되었고
- 그중 타이핑이 약 1만번, 타이핑 후 엔터동작이 약 9천번 발생. (천번정도는 타이핑 후 enter를 치지 않았다는 뜻)
- 24년10월15일날 오후늦게 API url을 수정했기 때문에, day_count가 15일부터 시작.
/* 결과 */
{
"took": 54,
"timed_out": false,
"_shards": {
"total": 6,
"successful": 6,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 10000,
"relation": "gte"
},
"max_score": null,
"hits": []
},
"aggregations": {
"custom_field_1_timestamp": {
"buckets": [
{
"key": "2024-09-01-00:00:00-2025-10-17-00:00:00",
"from": 1725116400000,
"from_as_string": "2024-09-01-00:00:00",
"to": 1760626800000,
"to_as_string": "2025-10-17-00:00:00",
"doc_count": 19055,
"custom_field_2_uri": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "typing",
"doc_count": 10036,
"custom_field_3_env": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "prd",
"doc_count": 10036,
"custom_field_5_week_count": {
"buckets": [
{
"key_as_string": "2024-10-14T00:00:00.000Z",
"key": 1728864000000,
"doc_count": 10036
}
]
},
"custom_field_6_month_count": {
"buckets": [
{
"key_as_string": "2024-10-01T00:00:00.000Z",
"key": 1727740800000,
"doc_count": 10036
}
]
},
"custom_field_4_day_count": {
"buckets": [
{
"key_as_string": "2024-10-15T00:00:00.000Z",
"key": 1728950400000,
"doc_count": 170
},
{
"key_as_string": "2024-10-16T00:00:00.000Z",
"key": 1729036800000,
"doc_count": 8568
},
{
"key_as_string": "2024-10-17T00:00:00.000Z",
"key": 1729123200000,
"doc_count": 1298
}
]
},
"custom_field_7_year_count": {
"buckets": [
{
"key_as_string": "2024-01-01T00:00:00.000Z",
"key": 1704067200000,
"doc_count": 10036
}
]
}
}
]
}
},
{
"key": "enter",
"doc_count": 9019,
"custom_field_3_env": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "prd",
"doc_count": 9019,
"custom_field_5_week_count": {
"buckets": [
{
"key_as_string": "2024-10-14T00:00:00.000Z",
"key": 1728864000000,
"doc_count": 9019
}
]
},
"custom_field_6_month_count": {
"buckets": [
{
"key_as_string": "2024-10-01T00:00:00.000Z",
"key": 1727740800000,
"doc_count": 9019
}
]
},
"custom_field_4_day_count": {
"buckets": [
{
"key_as_string": "2024-10-15T00:00:00.000Z",
"key": 1728950400000,
"doc_count": 136
},
{
"key_as_string": "2024-10-16T00:00:00.000Z",
"key": 1729036800000,
"doc_count": 7763
},
{
"key_as_string": "2024-10-17T00:00:00.000Z",
"key": 1729123200000,
"doc_count": 1120
}
]
},
"custom_field_7_year_count": {
"buckets": [
{
"key_as_string": "2024-01-01T00:00:00.000Z",
"key": 1704067200000,
"doc_count": 9019
}
]
}
}
]
}
}
]
}
}
]
}
}
}
고도화 포인트
API url을 기준으로
호출 시간대나, 호출 건수, 딥하게는 파라미터까지 분석이 가능하고
이를 활용할 수도 있을 것 같다.
예를들면 다음과 같다.
- 갑작스럽게 호출 건수 급증 => 대용량 트래픽 감지
- 관리 목록에 없는 url 포함 => 비정상접근 알림 발송
- 특정 호출건 추적
- 특정 시간대 건수 알림 => 정기적 모니터링 수행
ex.
(트래픽 집중 시간대에만) 짧은 집계 주기 적용 (초/분/시 단위) => 1초에 1000건 이상 api 호출되는 경우 => 카카오톡,SMS,팀즈 등 Alert 발송
+ 날짜 동적 필터링
ex. 어제 23시59분59초까지의 데이터만 필터
GET api-log-index/_search
{
"size": 0,
"query": {
// 비즈니스 로직
},
"aggs": {
"custom_field_1_timestamp": {
"date_range": {
"field": "@timestamp",
"format": "yyyy-MM-dd-HH:mm:ss",
"time_zone": "+09:00",
"ranges": [
{
"from": "1970-01-01-00:00:00", // 대과거
"to": "now-1d/d+23h+59m+59s" // 어제 23시 59분 59초
}
]
}
}
}
}
'IT > Elasticsearch' 카테고리의 다른 글
[Elasticsearch] ELK Query Count Filter (aggs Field) (0) | 2024.07.31 |
---|---|
[Elasticsearch] 쿠버네티스 워커노드 CPU 100% 장애 복기 (8) | 2024.07.24 |
[Elasticsearch] Elastic Contributor Program 이란? (0) | 2024.07.10 |
[Elasticsearch] ILM - Cluster 성능 개선 (0) | 2024.07.10 |
[Elasticsearch] 백엔드 장애 감지 알림 시스템 구축 (ELK 기반 준실시간 서버 로그 모니터링) (0) | 2024.07.06 |