처음에 GC를 수행하고
이랬던 상황에서
프로필 조회 API를 3~4번 연속했더니
이렇게 메모리 사용량이 커졌다.
@Around("execution(* com.plaything.api.domain.profile.controller.*Controller*.*(..))")
public Object around(final ProceedingJoinPoint joinPoint) throws Throwable {
// 메모리 사용량 측정 전에 기본 정보 로깅
String methodName = joinPoint.getSignature().getName();
log.info("Starting method: {}", methodName);
// 시작 시점의 메모리 상태 기록
MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
MemoryUsage heapBefore = memoryBean.getHeapMemoryUsage();
try {
Object result = joinPoint.proceed();
// 종료 시점의 메모리 상태와 차이 계산
MemoryUsage heapAfter = memoryBean.getHeapMemoryUsage();
long usedMemoryDiff = heapAfter.getUsed() - heapBefore.getUsed();
log.info("Method: {}, Memory change: {} bytes", methodName, usedMemoryDiff);
return result;
} catch (Throwable t) {
log.error("Error in {}: {}", methodName, t.getMessage());
throw t;
}
}
}
이렇게 AOP를 활용해서 메모리 사용량을 추적하기로 했다.
약 2MB정도의 메모리를 사용한다.
이 API는 마이페이지에 들어갈 때마다 호출되기 때문에 생각보다 자주 호출된다.
우선, Circuit Breaker를 쓰지 않고 이렇게 구성했다. 객체를 json 형태로 변환한 뒤에 레디스에 저장하고, 레디스에 저장된 json을 읽어와서 objectmapper로 객체로 변환한다.
결과는 어떨까?
최적화가 굉장히 잘됐다. 처음에 레디스에 저장하는 비용이 조금 들긴 하지만, 그 이후에 메모리 사용이 0으로 줄었다.
또한 긍정적인 점은 SQL 쿼리가 7개 나가던 것이 사라지고, 레디스 1번 조회로 대체된다는 점이다.
그렇다면, 프로필을 DB에서 계속 조회하면서 메모리를 사용하는 대신 레디스에 넣어놓고(6시간만), 포인트 키조회같은 경우는 DB를 사용하는 방식을 쓰는 게 낫겠다.
물론, 이 API를 그대로 쓸 수는 없다.
부하가 그렇게 크지는 않을 것으로 예상되는 작업들이다.