이전 프로젝트에서 인터페이스 지연 문제를 해결하기 위해 여러 최적화 작업을 수행했습니다. 이번 글에서는 이러한 최적화 방법들을 소개하겠습니다.
인터페이스 최적화 방법
- 배치 처리: 반복적인 데이터 삽입이나 업데이트는 배치 처리를 통해 한 번에 수행하여 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>