분류

개발 · 8쪽

DB·백엔드에서 실제로 터지는 문제와 USB·CD 굽기 교과서를 모았다. 느린 쿼리, 락과 트랜잭션, 장애와 확장, 배포와 관측은 태그로 나눠 찾는다.

96편 · 글 80 · 강 16 · 마지막 글 2026.09.28

교과서굽기 16강

개발 글

96편 중 85–96

  1. 다른 상품을 샀는데 왜 서로 기다릴까, SELECT FOR UPDATE

    재고를 잠그는 쿼리가 개발 DB 에선 멀쩡했다. 그런데 프로모션 날 주문 API 가 통째로 멈췄다. 서로 다른 상품을 산 사람끼리 줄을 서고 있었다.

  2. DB 는 몇 초 만에 살아났는데 서비스는 왜 계속 죽어 있을까

    DB 가 몇 초 느려졌을 뿐인데 서비스가 무너졌고, 원인이 사라진 뒤에도 회복이 안 됐다. 범인은 「실패하면 세 번 재시도」라는 지극히 상식적인 설정이었다.

  3. 100페이지만 가면 타임아웃, OFFSET 페이지네이션

    목록 1페이지는 10ms 인데 100페이지쯤 가면 타임아웃이 난다. 그 깊이까지 넘기는 건 사람이 아니라 크롤러다. OFFSET 은 건너뛰는 척하면서 사실 다 읽고 있다.

    5분#DB#페이지네이션#인덱스#쿼리
  4. 운영에서만 느린 목록 API, 범인은 ORM N+1

    목록 API 가 로컬에선 50ms 인데 운영에선 1.5초가 걸렸다. 느린 쿼리는 하나도 없었다. 범인은 쿼리 하나가 아니라 101번이라는 개수였다.

    5분#DB#ORM#쿼리
  5. MySQL 의 utf8 은 UTF-8 이 아니다

    닉네임에 이모지를 넣었더니 500 에러가 났다. 인코딩은 분명 utf8 로 맞췄는데도. MySQL 의 utf8 은 이름만 UTF-8 이고, 문자 하나에 3바이트까지만 담는다.

    6분#DB#MySQL#인코딩#DB 운영
  6. 인덱스를 걸었는데 LIKE '%검색어%' 가 느리다

    검색을 LIKE '%키워드%' 로 만들었더니 데이터가 늘면서 몇 초씩 걸렸다. 인덱스를 걸어 뒀는데도. 앞이 열린 패턴 앞에서는 B-tree 가 손쓸 방법이 없다.

  7. 한 번 눌렀는데 두 번 결제됐다면, 멱등성

    사용자는 결제 버튼을 한 번 눌렀는데 청구는 두 번 나갔다. 응답을 못 받았다고 다시 보낸 게 원인이었다. 그런데 보낸 쪽은 처리가 됐는지 안 됐는지 알 길이 없다.

    5분#백엔드#멱등성#결제#장애·확장
  8. keep-alive 를 안 쓰면 악수만 하다 끝난다

    상대 서비스는 5ms 만에 처리하는데 우리 쪽에서 재면 40ms 가 나왔다. 사라진 35ms 는 요청마다 연결을 새로 맺는 데 쓰이고 있었다. 설정은 맞았다. 쓰는 법이 틀렸다.

  9. 블로그를 열었다

    공부한 게 머릿속에만 있으면 없는 거나 마찬가지더라. 그래서 쌓아 둘 자리를 만들었다. 브루니 월드 안의 한 칸이던 블로그는 2026-10-23 부터 따로 열린다.

    1분#기록
  10. 배포할 때마다 502 가 조금씩 난다

    무중단 배포를 설정했는데 배포할 때마다 502 가 몇십 건씩 났다. 설정은 다 맞았다. 서버가 내려가는 순간과 트래픽이 끊기는 순간이 같지 않았을 뿐이다.

    5분#백엔드#배포#무중단#배포·관측
  11. 컬럼은 있는데 인덱스를 안 탄다면, 복합 인덱스 순서 문제

    (status, created_at) 인덱스를 만들었는데 created_at 만으로 찾으면 인덱스를 안 탄다. 그래서 인덱스를 자꾸 더 만들게 된다. 순서 기준을 알면 오히려 개수가 준다.

  12. 적중률 95% 인데 정각마다 DB 가 튄다, 캐시 스탬피드

    캐시 적중률은 95% 인데 정각마다 DB 부하가 순간적으로 치솟았다. 알림도 안 울릴 만큼 짧아서 더 고약했다. 같은 시각에 만든 캐시가 같은 시각에 한꺼번에 만료되고 있었다.