본문 바로가기
728x90

전체 글22

CloudFront 캐시 무효화 비용 — 파일 수가 아니라 경로 수로 센다 CloudFront 캐시 무효화 요금은 지운 파일 수가 아니라 요청한 경로 수로 매긴다. /* 하나로 수천 개를 지워도 1건이고, 파일 100개를 하나씩 적으면 100건이다.매달 무료 1,000건이 있는데, 이건 배포(distribution)마다가 아니라 계정 전체 합산이다. 배포가 여럿이면 생각보다 빨리 넘는다.그리고 경로 대신 태그로 무효화하는 기능이 생겼다. 태그 하나도 경로 1건으로 센다.과금 단위는 "경로"다AWS 문서가 과금 규칙을 이렇게 정리한다.한 달에 처음 1,000개 경로는 무료이고, 넘는 경로마다 요금이 붙는다경로는 파일 하나(/images/logo.jpg)일 수도, 여러 파일(/images/*)일 수도 있다*가 들어간 경로는 수천 개를 지워도 1건이다요청 하나에 경로를 여러 개 묶어.. 2026. 9. 18.
메서드 이름이 트랜잭션을 결정한다 — Spring AOP 일괄 트랜잭션의 함정 AOP로 트랜잭션을 일괄 적용하는 Spring 프로젝트라 @Transactional이 거의 없다. 적용 기준이 클래스 이름이 Impl로 끝나고 메서드 이름이 insert·update·delete·callSP로 시작하는가다.savePayment라고 이름을 지으면 트랜잭션이 안 걸린다. 에러도 안 나고 단일 INSERT면 테스트도 통과한다.차이는 여러 테이블을 쓰다가 예외가 났을 때만 드러난다. 앞의 것은 커밋되고 뒤에서 죽어, 원장에 반쪽짜리 데이터가 남는다.구조AOP 설정이 이렇다.// 대상: com.example.app..*Impl.*(..)// 메서드명이 insert*, update*, delete*, callSP* 로 시작하면 쓰기 트랜잭션// 어떤 Exception 이든 롤백처음 보면 깔끔하다. .. 2026. 9. 17.
튜닝하다 조건을 떨어뜨렸다 — 쿼리를 고치면 결과부터 대조한다 쿼리 튜닝을 하다가 조건을 떨어뜨렸다. VIP 대상자가 7천 명으로 나왔고, 에러는 하나도 없었다. 석 달 동안 아무도 몰랐다.성능 튜닝의 진짜 위험은 느려지는 게 아니라 답이 조용히 달라지는 것이다. 빨라진 건 눈에 보이고 답이 달라진 건 안 보인다.그래서 규칙을 하나 만들었다. 쿼리를 고치면 성능이 아니라 결과부터 대조한다.점포에서 온 문의회원 등급 설정에서 신규 VIP 대상이 7천 명으로 나오는데 이게 맞나요?그 점포 전체 회원이 그 정도 규모다. 거의 전원이 VIP 대상이라는 뜻이다. 누가 봐도 이상한데, 화면은 아무 에러 없이 그 숫자를 보여주고 있었다.조건이 사라져 있었다대상자를 세는 쿼리는 이런 모양이다. 회원별 누적 결제금액을 구하고, 설정한 금액 이상인 사람만 센다.SELECT COUNT.. 2026. 9. 16.
계정 이관 마지막 열흘: 인증 앞단화, 알람, 그리고 문서 알람 45개를 한꺼번에 만들었더니 45통이 왔다. 최초 1회뿐이고 고장이 아닌데, 놀라서 ok_actions를 떼면 복구 알림이 영영 사라진다.두 달짜리 계정 이관의 마지막 열흘 기록이다. 운영을 새 박스로 옮기고, 인증을 앞단으로 빼고, 알람과 감사 로그를 걸고, 인수인계 문서를 썼다.가장 자주 틀린 건 인프라가 아니라 문서를 쓸 때였다.CI를 별도 박스로 뺐다기존에는 CI와 API가 한 박스에 있었다. 조사하다 이렇게 정리됐다.운영 박스 중 이 박스가 가장 껄끄럽다 — CI가 여기 있어서 여기가 흔들리면 배포 수단 자체가 없어진다.배포로 고쳐야 하는 상황에서 배포가 안 되는 구조다. 전용 박스로 분리했다.인증은 앱이 아니라 앞단에 둔다처음엔 사무실 IP로 제한했다가, ALB의 OIDC 인증으로 바꿨다.. 2026. 9. 15.
npm ci와 npm install 차이 — 속도가 아니라 락 파일을 대하는 태도다 npm ci와 npm install의 차이는 속도가 아니라 락 파일을 대하는 태도다. npm install은 필요하면 package-lock.json을 고쳐 쓰고, npm ci는 한 글자도 안 고치고 안 맞으면 멈춘다.그래서 CI에서는 npm ci가 맞다. 커밋된 락 파일과 다른 트리가 설치되는 일이 구조적으로 불가능하기 때문이다.대신 조용히 발목을 잡는 설정이 하나 있다. NODE_ENV=production이 먼저 잡혀 있으면 devDependencies가 설치되지 않는다. 빌드 도구가 거기 있으면 설치는 성공하고 빌드가 실패한다.한 줄로 갈리는 지점npm install은 "package.json을 만족하는 트리를 만든다"에 가깝고, npm ci는 "락 파일에 적힌 트리를 그대로 재현한다"에 가깝다.그.. 2026. 9. 14.
Spring readOnly 트랜잭션을 리더로 보내면 생기는 read-after-write 문제 결제를 취소하고 저장 성공까지 떴는데, 화면이 다시 그려지면 취소 이전 상태가 보였다. 새로고침하면 정상이고 DB도 정상이었다. 화면만 틀렸다.원인은 @Transactional(readOnly = true)를 리더 복제본으로 보내는 라우팅이었다. 저장 직후의 조회가 복제가 따라오기 전의 리더를 읽은 것이다.readOnly = true는 "읽기만 한다"가 아니라 "이 결과는 조금 낡아도 된다"는 선언이다. 방금 바꾼 것을 다시 보는 화면에는 붙이면 안 된다.구조부터이 앱은 읽기와 쓰기 DB를 나눠 쓴다. Spring의 AbstractRoutingDataSource로, 현재 트랜잭션이 읽기 전용이면 리더 복제본으로, 아니면 라이터로 보낸다.protected Object determineCurrentLooku.. 2026. 9. 13.
728x90