인터페이스 성능 최적화 전략

이전 프로젝트에서 인터페이스 지연 문제를 해결하기 위해 여러 최적화 작업을 수행했습니다. 이번 글에서는 이러한 최적화 방법들을 소개하겠습니다.

인터페이스 최적화 방법

  • 배치 처리: 반복적인 데이터 삽입이나 업데이트는 배치 처리를 통해 한 번에 수행하여 I/O 횟수를 줄일 수 있습니다.
    <code>
    // 단건 삽입 예시
    list.forEach(msg -> {
        insert();
    });
    // 배치 삽입 예시
    batchInsert(list);
    </code>
  • 비동기 처리: 시간이 오래 걸리고 결과가 즉시 필요하지 않은 작업은 비동기적으로 처리할 수 있습니다. 예를 들어, 투자 상품 구매 시 계좌 입금과 파일 기록은 비동기로 처리할 수 있습니다.
  • 공간을 시간으로 대체: 자주 사용되며 자주 변경되지 않는 데이터는 캐싱을 통해 저장하여 데이터베이스 조회나 재계산을 줄일 수 있습니다. 캐시는 Redis, Memcached, 로컬 캐시 등 다양한 형태가 있습니다.
  • 프리페치: 필요한 데이터를 미리 계산하거나 캐싱하여 인터페이스 응답 속도를 높일 수 있습니다. 예를 들어, 투자 상품의 연간 수익률은 미리 계산해두고 사용할 때 조회할 수 있습니다.
  • 풀링: 데이터베이스 연결 풀이나 스레드 풀 등을 사용하여 객체 생성과 소멸의 비용을 줄일 수 있습니다. 이는 리소스 재사용성을 높입니다.
  • 병렬 처리: 독립적인 작업들은 병렬로 처리하여 전체 처리 시간을 단축할 수 있습니다. 예를 들어, 사용자의 계좌 정보와 상품 정보를 동시에 조회할 수 있습니다.
  • 인덱스 활용: 데이터베이스 인덱스를 적절히 사용하면 검색 성능을 크게 향상시킬 수 있습니다. 그러나 인덱스가 효율적으로 작동하지 않는 경우도 있으므로 주의해야 합니다.
  • 대형 트랜잭션 피하기: 긴 시간 동안 실행되는 트랜잭션은 데이터베이스 리소스를 잠그게 되어 다른 요청에 영향을 줄 수 있습니다. 이런 경우 트랜잭션 범위를 줄이거나 비 데이터베이스 작업을 분리할 수 있습니다.
    <code>
    public BasicResult purchaseRequest(PurchaseRecord record) {
        BasicResult result = new BasicResult();
        taskMapper.insert(buildTask(record, TaskType.PENSION_ACCOUNT));
        taskMapper.insert(buildTask(record, TaskType.PENSION_SYNC));
        // push 알림은 별도로 처리
        pushService.sendNotification(record);
        result.setInfo(ResultInfo.SUCCESS);
        return result;
    }
    </code>
  • 코드 구조 개선: 요구사항 변화에 따라 코드가 복잡해지면 성능 저하가 발생할 수 있습니다. 이를 방지하기 위해 코드를 재구성하고 불필요한 작업을 제거하는 것이 중요합니다.
  • 깊은 페이징 문제 해결: 큰 오프셋으로 데이터를 가져오는 것은 성능 저하를 초래할 수 있습니다. 대신 최근 ID를 기준으로 데이터를 가져오는 방법을 사용할 수 있습니다.
    <code>
    // 성능 저하 예시
    SELECT * FROM purchase_record WHERE productCode = 'PA9044' AND status = 4 ORDER BY orderTime DESC LIMIT 100000, 200;
    // 성능 개선 예시
    SELECT * FROM purchase_record WHERE productCode = 'PA9044' AND status = 4 AND id > 100000 LIMIT 200;
    </code>
  • SQL 최적화: 적절한 인덱스 사용, 적절한 쿼리 작성 등으로 데이터베이스 쿼리 성능을 향상시킬 수 있습니다.
  • 락의 세분화: 공유 자원에 대한 접근을 최소화하기 위해 필요한 부분만 락을 걸어야 합니다. 이는 동시성 문제를 해결하고 성능을 향상시킵니다.
    <code>
    // 잘못된 락 사용 예시
    synchronized (this) {
        sharedMethod();
        nonSharedMethod();
    }
    // 올바른 락 사용 예시
    nonSharedMethod();
    synchronized (this) {
        sharedMethod();
    }
    </code>

태그: 인터페이스 최적화 배치 처리 비동기 처리 캐싱 프리페치

9월 13일 20:36에 게시됨