종료에 120초가 걸리던 이유: ScheduledThreadPoolExecutor의 대기 큐
배포 때마다 찍히는 에러 알림 한 건을 따라가다 보니, 죽어 있던 graceful shutdown 설정을 깨운 커밋과 큐에 남은 지연 작업들이 나왔습니다. JDK의 종료 정책 한 줄을 바꿔 destroy()를 120초에서 1ms로 줄인 과정을 기록했습니다.
커밋하지 않은 SELECT 하나가 전 API를 멈춘 이유. MySQL 메타데이터 락
운영 데이터를 보정하다 트랜잭션을 24분간 열어뒀는데, 앞의 15분은 아무 일도 없었습니다. 서비스가 멈춘 건 그 사이 배포가 던진 ALTER TABLE 한 줄 때문이었고, 정작 InnoDB 행 락 지표는 끝까지 0이었습니다.
MySQL Gap Lock 데드락. 가설 반증과 격리 수준 변경으로 해결
컨슈머들이 같은 테이블에 DELETE + INSERT를 병렬 수행하면서 REPEATABLE READ의 gap lock으로 데드락이 났습니다. 처음 세운 서브쿼리 가설은 performance_schema.data_locks 비교로 반증됐고, 진짜 원인은 격리 수준이었습니다.
커넥션 풀 고갈 문제를 Redis Atomic 연산으로 개선하기
1000명 규모 조직에서 50~100명이 동시에 이슈를 생성하는 상황을 가정하고, 목표 지표를 먼저 못 박은 뒤 부하 테스트로 검증했습니다.
왜 롤백이 되었을까
로컬에서만 알림이 저장되지 않고 dev/prod는 멀쩡했습니다. 디버거로는 분명히 저장되는데 DB에는 없었고, AOP 로그를 따라가며 트랜잭션이 되감긴 지점을 좁혔습니다.
만든 것
코드가 공개돼 있고, 남이 쓰고 있는 것들.
Apache KafkaIn Review
KAFKA-20922. Kafka Streams 상태 저장소의 이터레이터 3개 경로에서 역직렬화 결과가 null일 때 발생하던 예외에 가드를 추가했습니다.
apache/kafka #23175 ↗안부Live
부모님 돌봄을 기록하고 가족과 나누는 웹 서비스. 기획부터 배포, 운영까지 혼자 만들고 있습니다.
anboo.app ↗