서비스 레이어에 데이터 캐싱하기

1

개발고민

목록 보기
1/1

물류 도메인에서 주문에 따라 상품을 찾아내는 작업하는 것 을 피킹이라하는데
추천 하는 위치의 우선순위가 기획적으로 변경되어 피킹 추천 배치를 수정하는 일을 맡았다

Body

실제 재고는 피킹을 하는 시점에서 빠지지만
로직에서는 재고에 맞춰 출고를 해야하기때문에 로직상에서 추천에 몇개가 쓰였는지? 또는 몇개가 남았는지? 데이터로 가지고 있어야 했다.

데이터 형식은 key, value 였고 이 데이터를 어디에 저장할지 고민이 되었다.

그래서 생각한 대안이 몇가지가 있었는데 이 세가지다
1. Rdbms
2. Redis
3. static 클래스 변수

Rdbms
별도의 테이블을 두어 데이터를 적재하는 방법이다.
생각은 해보았지만 바로 제외된 방법이다
왜냐하면 사용한 재고 수만큼 비례하여 IO가 발생해야했기때문에 일종의 캐시 성격의 저장 장소로는 부적합 하다고 판단했다.

Redis
Redis는 메모리에 저장하여 비교적 빠르게 데이터를 읽고 쓸 수 있지만 해당 로직이 분산처리가 필요하다던가, 각각 다른 쓰레드에서 처리한 데이터를 적재하는것이 아니기때문에 살짝(?) 오버핸들링이라고 생각했다.
또한 적은 확률이지만 Redis에 문제가 생길경우 재고에 영향이 갈 수 있기때문에 부적합 하다고 판단했다.

클래스내에 static 클래스 변수
클래스내에 static 변수로 컬렉션을 지정하여 저장하는 방법이다.
메모리에 항시 떠있지만 GC대상이 아니므로 Memory Leak이 발생하지 않도록 메모리 관리를 해줘야 한다.
그렇게 되면 또하나의 관리 대상이 되기때문에 (개발 히스토리가 생겼다고도 할 수 있다) 이 부분이 단점 인 것 같다.

결론은 마지막 static 클래스 변수를 선택했다.
5초에 한번씩 도는 배치여서 메모리에 항시 떠있어도 사용성이 높기 때문에 괜찮다고 판단했고 해당 서비스에서만 접근하기때문에 서비스 레이어 내에 두기로 했다.

@Slf4j
@Service
@RequiredArgsConstructor
public class OutboundRecommendationService {

    private static final HashMap<Long, Integer> usedAmountMap;
    
    ... 후략

재고 테이블의 pk를 key, 추천 로직을 돌면서 사용한 재고수를 value로 두었다.
대신 staitc 변수는 GC대상이 아니므로 Memory Leak이 발생하지 않도록 초기화를 꼼꼼히 해주어야한다.
하지만 초기화를 해줘야하는 것도 또하나의 관리대상이 되기때문에 단점이 없다고는 할 수 없을 것 같다.

usedAmountMap.clear();

평소에 이런 클래스 변수를 두는 일이 적어 좀 낮설게 느껴지긴 했지만 익숙한것이 모두 정답은 아니기 때문에 나름의 생각을 가지고 선택 해 보았다.

0개의 댓글