본문 바로가기
Develop/etc

[백엔드 실무 스터디] 3, 4. DB와 외부 연동

by 연로그 2025. 8. 4.
반응형

서론

이 글은 '주니어 백엔드 개발자가 반드시 알아야 할 실무 지식' 책을 읽고 진행하는 스터디 내용을 정리한다. 책을 읽고 학습하는 게 아니라, 책의 내용을 주제로 경험을 공유하는 스터디이기 때문에 포스팅 내용은 책과 관련이 없다. 이번 글은 '3장 성능을 좌우하는 DB 설계와 쿼리', '4장 외부 연동이 문제일 때 살펴봐야 할 것들'을 읽고 진행한 스터디 내용을 정리했다. (경험 공유) 표기는 스터디원들이 실무에서의 경험을 정리한 것이며, 항상 정답인 예제가 아니다.

 

 

 


3장. 성능을 좌우하는 DB 설계와 쿼리

 

선택도 (58p)

  • 인덱스에서 특정 컬럼의 고유한 값 비율
  • 선택도가 높다 = 고유값이 많다

 

 

커버링 인덱스 (59p)

  • 인덱스 안에 포함된 데이터를 사용하므로 실제 데이터에 접근할 필요 없음.
  • 쿼리를 충족시키는데 필요한 모든 데이터를 갖고 있는 인덱스

 

 

설문조사를 좋아요하는 CUD를 어떻게 개선할까? (63p)

  • 설문조사와 설문조사를 좋아요 하는 집계 수를 join 해서 조회하는 쿼리가 있다고 가정. 이를 어떻게 개선하면 좋을까?
  • 개선할 수 있는 방법
    1. 설문조사 테이블에 좋아요 집계 컬럼 추가
      • 좋아요 CUD 발생 할때마다 설문조사의 집계 컬럼 변경
      • 또는 배치로 정합성 맞추기
    2. 설문조사 조회 쿼리 / 좋아요 수 조회 쿼리를 분리 후 캐싱
    3. 현재 상태(join 쿼리) 유지
  • (경험 공유) update가 너무 많은 케이스를 개선
    • update가 많은 값 Redis에 적재
    • 일정 주기마다 Redis 조회해서 DB 업뎃

 

delete 쿼리와 디스크 용량 (74p)

  • delete 쿼리를 실행하면 삭제되었다는 표시만 남기고, 디스크 용량이 줄어들지는 않는다
  • 삭제된 공간은 향후 재사용되나, 단편화 현상이 발생할 수 있다
    • 데이터 추가/변경/삭제 과정에서 데이터가 흩어져 저장 → 빈 공간 생성
  • 참고: https://dev.mysql.com/doc/refman/8.0/en/delete.html
 

MySQL :: MySQL 8.0 Reference Manual :: 15.2.2 DELETE Statement

DELETE is a DML statement that removes rows from a table. A DELETE statement can start with a WITH clause to define common table expressions accessible within the DELETE. See Section 15.2.20, “WITH (Common Table Expressions)”. Single-Table Syntax DELE

dev.mysql.com

 

 

DB Replica (75p)

  • 우리 서버의 replica 개수 확인하는 법
    • AWS > Aurora and RDS > Databases

 

 

쿼리 타임아웃 (77p)

  • hikari의 max-life-time
    • 히카리 풀에서 커넥션이 살아있을 수 있는 시간
    • 이 값이 작으면 Aurora Failover 시 더 유연하게 작동
      • Failover: 프라이머리 DB 인스턴스에 장애가 발생 시 자동으로 다른 인스턴스가 그 역할을 대신함
      • max-life-time 값이 작으면 커넥션이 더 자주 만료되고 재생성
      • 이전 프라이머리 인스턴스와의 연결이 끊어지고, 신규 프라이머리로 연결을 다시 수립
    • DB wait_timeout보다 짧게 설정하는 것을 권장
      • 네트워크 지연, 애플리케이션 성능 지연 고려
      • DB wait_timeout이 더 작으면 DB서버는 커넥션 종료했지만, client app에서는 커넥션 살아있다고 판단 → 커넥션 누수 발생 가능

 

 

타임아웃 발생 시 수행되는 로직

  • 상황마다 다른데 보통 예외를 그대로 전파
  • (경험 공유) 조회 시 필수 값이 아니면 null이나 empty 처리

 

 

DB 최대 연결 개수 (85p)

  • SHOW VARIABLES LIKE 'max_connections';
  • 하나의 DB에 여러 서버가 붙으면 커넥션 고갈 문제가 있지 않을까?
    • 디폴트 값은 151이지만 사내에서는 훨씬 크게 늘려서 사용 중 (디폴트 값 참고: MySQL 8.0 문서)
    • 주의가 필요하나 (값을 크게 커스텀했기 때문에) 생각보다 자주 발생할 일은 아니라고 예상

 

 

(경험 공유) 슬로우 쿼리 개선

  • 데이터 전체 조회로 인한 슬로우 쿼리
    • 데이터가 많아질수록 실행시간 증가
    • 인덱스 적용된 컬럼 기준으로 나눠서 조회
  • 조회 조건이 많아 인덱스를 타지 않았던 이슈
    • 인덱스가 존재하는 컬럼으로만 조회하도록 개선
    • 그 외 필터링은 애플리케이션 로직에서 적용
  • 조인 조회 쿼리 수행 시 varchar 컬럼의 캐릭터셋 불일치 이슈
    • 쿼리 속도 늦어짐
    • 트래픽이 적은 새벽 시간에 캐릭터셋 변경
  • 타입 불일치로 인덱스 활용이 힘들었던 경험
    • int형이어야 하는데 테이블에 varchar로 선언됨
    • where 조건에서는 숫자지만 테이블은 varchar → 수행 시 타입 변환이 필요 → 리소스 낭비 & 인덱스도 안 탐
    • 컬럼 타입 변경으로 해소 (데이터가 얼마 쌓여있지 않은 상황이라 가능했었음)

 

 


4장. 외부 연동이 문제일 때 살펴봐야 할 것들

 

타임아웃 (91p)

  • (경험 공유) 모든 서버에서 자주 사용하는 플랫폼의 응답 지연
    • 스노우볼 효과
      • A → B → C 서버로의 의존성이 존재하고, 모든 서버에서 D 서버를 호출한다고 가정
      • D 서버의 API가 지연 시 A 서버에서는 정말 긴 타임아웃 필요
    • 후속 대응 - 외부 서버/API 별로 타임아웃 다르게 설정

 

 

재시도 (96p)

  • (경험 공유) 재시도 대신 이벤트 활용했던 이유
    • 재시도 실패에 대한 처리 용이
    • 재시도가 반드시 성공해야 하는 상황
    • 변경 기능이 멱등하지 않은 케이스가 많음
  • 조회용 외부 API 호출도 재시도가 필요할까?
    • 아예 잘못된 요청인 경우 존재 (ex: request에 필수값이 null로 들어갔다)
    • 일시적 오류는 보통 1~2초 유지되는 경우가 많아서 1~2초 내 재시도 시 유의미한 값을 받아오기 힘들 것 같음

 

 

동시 요청 제한 (100p)

  • tomcat 스레드 200, 대기가능 100개면 301번째 요청은 어떻게 되는가?

 

 

서킷 브레이커 (102p)

  • 빠른 실패 처리
  • 불필요한 트래픽 전파 방지
  • (경험 공유) 서킷 브레이커와 예외 처리
    • 이벤트 중복 발행을 방지하기 위해 Redis에 중복 체크 정보를 저장
    • 서킷 브레이커가 열리면 모든 이벤트를 중복이 아닌 것으로 처리
    • 이벤트 발행이 더 중요한 도메인이기 때문

 

 

외부 연동과 DB 연동 (104p)

  • 외부연동 / DB 연동 수행 실패했을 때 해야 할 일
외부연동 DB연동 해야할 일 
O X 데이터 주기적으로 맞추기
X O 외부 연동만 다시 시도
외부 연동 실패 응답하면 DB로직 수행도 수행하지 않도록 개선
X X 재수행
X read timeout O 데이터 주기적으로 맞추기
or 재수행 및 수행 시 이미 성공 완료된 건인지 확인
  • insert → 외부 call → update 구조라면 어떻게 대응할 수 있을까?
    • 외부 call 지연을 대비해 서킷 걸어서 빠르게 실패시킨다
  • (경험 공유) 트랜잭션 범위를 작게 쓰자
  • (경험 공유) 외부/DB 데이터 불일치해도 당장 처리하지 않음
    • 실시간이 중요하지 않음
    • 원인이 다양해서 수동으로 확인 후 처리
 

JPA Transactional 잘 알고 쓰고 계신가요? | 카카오페이 기술 블로그

JPA Transactional과 그에 따른 DB 쿼리 성능과의 관계에 대해서 설명합니다.

tech.kakaopay.com

 

 

HTTP 커넥션 풀 (109p)

  • 브라우저에는 자체 HTTP 커넥션 풀이 존재
  • 서버-서버는 HttpClient, FeignClient 등의 클라이언트 라이브러리
    • 커넥션 풀 크기
    • 커넥션 가져오는 대기 시간
    • 커넥션 유지 시간 (keep alive)
  • (경험 공유) 외부 API 호출 타임아웃 이슈 개선 공유
    • keep-alive 설정이 없을 때, 타임아웃이 자주 발생했었음
    • HTTP 커넥션 유지 → 3 way handshake 안 해도 됨 → 응답 속도 빨라짐
반응형