[MariaDB] ON DUPLICATE KEY UPDATE 대량 upsert 시 신규 데이터가 사라지는 버그 (ha_index_read_idx_map)
·
Develop/Database
들어가며저희 팀은 외부에서 주기적으로 전달받는 데이터를 하나의 테이블에 저장하는 배치 파이프라인을 운영하고 있습니다. 한 번 실행에 보통 수천 건의 항목이 들어오고 이걸 MariaDB 11.2.2에 upsert합니다.이번 글은 이 upsert 과정에서 발견한 이상한 증상을 추적한 기록입니다. 결론부터 말하면 원인은 MariaDB의 long unique 인덱스 였습니다.증상한 번의 배치 실행에서 신규로 추가되어야 할 항목이 24개 있었습니다. 그런데 실제로는 이 중 1개만 테이블에 반영되었습니다. 배치를 다시 돌리면 1개가 더 늘어서 총 2개가 됩니다. 실행할 때마다 정확히 1개씩만 증가하는 패턴이었습니다.전체 insert row의 규모는 수천 건이었고 이 24개는 그 안에 섞여 있던 신규 항목의 일부였습..
[Spring Boot/DevOps] JVM GC 튜닝을 위한 Prometheus로 지표 연동
·
Develop/SpringBoot
들어가며 [Spring Boot] Redis 캐시 Desync 트러블슈팅: JVM 힙 설정 오류 분석증상Redis 캐시 응답이 간헐적으로 이상해지는 문제가 발생했습니다. 타입이 맞지 않는 응답과 함께 이런 예외들이 로그에 산발적으로 찍혔습니다.org.springframework.data.redis.RedisSystemException: Unknown rgosiwoo.tistory.com 지난 글에서 -Xmx600m 고정값을 -XX:MaxRAMPercentage=75.0으로 바꿔서 문제를 해결했습니다.로그를 눈으로 살펴보며 해가며 확인하는 방식은 한계가 있어서, 이번엔 Prometheus/Grafana로 GC/힙 지표를 상시 모니터링할 수 있도록 연동한 과정을 정리했습니다.1. Spring Boot에 의존..
[Spring Boot] Redis 캐시 Desync 트러블슈팅: JVM 힙 설정 오류 분석
·
Develop/SpringBoot
증상Redis 캐시 응답이 간헐적으로 이상해지는 문제가 발생했습니다. 타입이 맞지 않는 응답과 함께 이런 예외들이 로그에 산발적으로 찍혔습니다.org.springframework.data.redis.RedisSystemException: Unknown redis exception at org.springframework.data.redis.FallbackExceptionTranslationStrategy.getFallback(FallbackExceptionTranslationStrategy.java:49) at org.springframework.data.redis.connection.lettuce.LettuceConnection.await(LettuceConnection.jav..
[Spring Boot] "Invalid character found in the request target", RFC 3986에서 차이나는 '[' 와 '&'
·
Develop/SpringBoot
들어가며여러 서비스가 공유해서 쓰는 범용 Redis 캐시 서버를 Spring Boot(Tomcat) 기반 REST API로 운영하고 있습니다. Node.js 클라이언트뿐 아니라 Java로 작성된 배치 스케줄러도 같은 API를 호출하는 구조입니다. 이 서비스에서 GET 요청에 대해서 해당 문제가 종종 발견되어 해결하는 과정에서의 판단과 근거를 담은 포스팅입니다.증상java.lang.IllegalArgumentException: Invalid character found In the request target재현을 위해 로컬 테스트 환경에서는 아래 두 값을 썼습니다.const BRACKET_ONLY_KEY = "TEST_dummy_[TAG] 테스트 상품명 예시_00G_지역_0000";const AMPERSA..
[Airflow] Scheduler 메인 스케줄링 흐름 정리 (3.2.2v)
·
Develop/Airflow
1. Scheduler란?Airflow로 DAG를 짜본 사람이라면 한 번쯤 이런 생각을 해봤을 겁니다. 내가 만든 이 DAG, 대체 누가 언제 실행시켜주는 걸까. 그 답이 Scheduler입니다. Airflow 공식 문서는 Scheduler를 "모든 Dag와 태스크를 모니터링하다가, 의존성이 충족된 태스크를 실행시키는 컴포넌트"라고 정의합니다. 실제로 이 역할을 맡고 있는 SchedulerJob이라는 프로세스 하나가 하는 일은 생각보다 많습니다. SchedulerJob은 while 루프를 돌면서, 정해진 주기(scheduler_heartbeat_sec)마다 아래 일들을 순서대로 처리합니다. 지금 어떤 DAG들이 등록돼 있는지 확인하고실행할 시간이 된 DAG가 있으면 DagRun을 만들고그 안의 태스크들..
[Airflow] git-sync Init:Error 트러블슈팅
·
Develop/Airflow
들어가며회사에서 데이터를 수집해서 JSON 데이터를 이관하는 파이프라인을 Airflow(2.6.3)로 운영하고 있습니다. Executor는 KubernetesExecutor라서 태스크 하나마다 Executor pod이 새로 뜨는 구조이고, Helm 커뮤니티 차트(airflow-helm/charts, release airflow-8.8.0)로 배포돼 있습니다. DAG 파일은 Bitbucket 저장소를 git-sync로 동기화해서 가져오는데, 이 차트에서는 Scheduler뿐 아니라 Executor pod에도 dags.gitSync 설정이 그대로 적용됩니다. 그래서 태스크 하나가 뜰 때마다 Executor pod의 pod_template에 git-sync가 init container(dags-git-clon..
[Airflow] Airflow 2.x vs 3.x, 주요 변경점 정리
·
Develop/Airflow
들어가며회사에서 운영 중인 Airflow는 2.6.1 버전입니다. KubernetesExecutor로 Task마다 Pod를 띄우고, 외부 MySQL을 메타데이터 DB로 쓰는 구조로 하루 3,600만 건 규모의 데이터 파이프라인을 돌리고 있습니다.최근 MariaDB "Too many connections" 이슈를 디버깅하면서 워커들이 메타데이터 DB에 직접 붙는 구조라는 걸 다시 확인하게 됐고, 그러다 문득 "최신 Airflow 3.x는 이 부분이 어떻게 달라졌을까?" 궁금해졌습니다. 찾아보니 Airflow 3.0은 단순 마이너 업데이트가 아니라 아키텍처 자체를 갈아엎은 수준의 변화였습니다.이 글은 회사에서 쓰고 있는 2.6.1과 최신 3.x를 기준으로, 실제 운영 관점에서 체감이 클 만한 변화들을 정리한..
[Airflow] Airflow 아키텍처 이해하기, 3.3.0v (Dag, Operator, Task)
·
Develop/Airflow
들어가며회사에서 크롤링 데이터를 수집해서 JSON데이터를 이관하는 파이프라인을 운영하고 있습니다. Spring Batch로 정기 스케줄러를 구성하고, Node.js 기반 수집 모듈로 각 플랫폼 데이터를 가져와 Airflow로 전체 흐름을 관리하는 구조입니다. 저희 팀이 쓰고 있는 버전은 2.6.1입니다.이전에 공식 문서를 기준으로 아키텍처를 개인적으로 한 번 정리한 적이 있는데, 그때는 프로젝트 구성 버전인 2.6.1 버전으로 정리했습니다. 확인해보니 Airflow 3.0에서 아키텍처 자체가 크게 바뀌었더라고요. 이번에는 최신 3.3.0 공식 문서를 기준으로 컴포넌트 구성을 다시 정리하려고 합니다.이 글은 Airflow 공식 문서(Architecture Overview, 3.3.0 기준)를 바탕으로 정리..