본문 바로가기
공부/Cache

캐시 KEY값 고도화하기 - 1

by 고구밍 2022. 5. 30.

 

 

문제

더보기

팀장님의 이야기

"성훈님, 저희 캐시가 너무 잘 작동하는데요
5초동안 상세 페이지 들어가기 누르면 계속해서 같은 페이지만 들어가 집니다"

 

"그 아침에 캐시문제로 수정이 잘 반영이 안 됬을 때, a상품봤다가 b상품봤을 때 a상품 정보가 나왔었나요?"

"다른 상품을 요청 할 때, 캐시를 비워 줄 수 있는지 테스트 해볼게요"
"현재는 수정 삭제할 경우, 캐시 비워주는 구조로 되어 있습니다. (접근법이 달랐네요.) "
 
 
팀장님
"단순 조회만 하는경우는 캐쉬에 할당하는게 손해입니다"
 
 
 
"그럼 연산이 불필요한 부분은 사용하지 않는 것 도 좋겠네요."
 
 

 
문제 1 )
아이템 상세페이지를 조회할 때 ItemId에 대해서 여러개의 키값이 적용이 되지 않음
 
 
문제 2 ) 
put 등 업데이트 사항에 대해서 캐시가 비워지지 않음
 
 

 
// 엄성훈 - 거래완료취소 유저의 isTrade를 true -> false 업데이트
    @Transactional
    @Caching(evict = {
            @CacheEvict(cacheNames = "barterMyInfo", key = "#userDetails.userId", allEntries = true),
            @CacheEvict(cacheNames = "itemInfo", allEntries = true),
//            @CacheEvict(cacheNames = "itemTradeCheckInfo", key = "#userDetails.userId+ '::' + #itemId", allEntries = true)})
            @CacheEvict(cacheNames = "itemTradeCheckInfo", allEntries = true)})
    public BarterTradeCheckDto cancelBarter(Long barterId, UserDetailsImpl userDetails) {
 
해결법 1)
key값을 userId와 ItemId를 파싱하여 키 값을 다중으로 분활한다.
 
 
해결법 2)
캐시와 연관된 요청에대해서 캐시를 비우는 어노테이션을 추가함
 @CachEvict
 
해결법 3)
캐시에 관련된 여러 요청이 중첩하여 사용할 경우 @Caching을 사용하여 캐시를 지울경우
@Caching(evict = {@Caching(), @Caching()})
으로 사용해야된다.

 

코드

더보기

 

거래내역 보기 ( Get요청 )

주어지는 파라미터는 userDtails이고, 안에있는 userId를 key값으로 정했습니다.

// 성훈 - 거래내역서 보기
@Cacheable(cacheNames = "barterMyInfo", key = "#userDetails.userId")
public List<BarterDto> showMyBarter(UserDetailsImpl userDetails) {
    User user = userRepository.findById(userDetails.getUserId()).orElseThrow(
            () -> new CustomException(NOT_FOUND_USER)
    );

    Long userId = userDetails.getUserId();
    // 유저의 거래내역 리스트를 전부 조회한다
    List<Barter> mybarterList = barterRepository.findAllByBuyerIdOrSellerId(userId, userId);
    // 거래내역 리스트를 담기
    return addTotalList(userId, mybarterList);
}

 

거래 완료취소 거래내역에 대해서 (Put)

캐시로 존재하는 거래내역에 변화가 발생하였기 때문에, 업데이트를 위해서 해당key값을 지워준다.

// 엄성훈 - 거래완료취소 유저의 isTrade를 true -> false 업데이트
    @Transactional
    @Caching(evict = {
            @CacheEvict(cacheNames = "barterMyInfo", key = "#userDetails.userId", allEntries = true),
            @CacheEvict(cacheNames = "itemInfo", allEntries = true),
//            @CacheEvict(cacheNames = "itemTradeCheckInfo", key = "#userDetails.userId+ '::' + #itemId", allEntries = true)})
            @CacheEvict(cacheNames = "itemTradeCheckInfo", allEntries = true)})
    public BarterTradeCheckDto cancelBarter(Long barterId, UserDetailsImpl userDetails) {
        User user = userRepository.findById(userDetails.getUserId()).orElseThrow(() -> new CustomException(NOT_FOUND_USER));
        Barter mybarter = barterRepository.findById(barterId).orElseThrow(() -> new CustomException(NOT_FOUND_BARTER));
        BarterTradeCheckDto oppononetTreadeCheck;
        Long userId = user.getId();
        // 거래완료 취소 업데이트
        if (mybarter.getStatus() == 2) {
            oppononetTreadeCheck = getBarterTradeCheckDto(userId, mybarter);
        } else {
            // 거래중인 상태가 아니면 예외처리
            throw new CustomException(NOT_TRADE_BARTER);
        }
        return oppononetTreadeCheck;
    }

 

 

 

새로운 문제

-> 파라미터의 불규칙으로인한 key값 설정이 어려움

더보기

예시 1)

거래내역보기

 

@Cacheable(cacheNames = "barterMyInfo", key = "#userDetails.userId")
public List<BarterDto> showMyBarter(UserDetailsImpl userDetails) {

 

위에서 userId를 key값으로 설정하였는데,

 

// 교환신청 확인 페이지 수락 버튼
@Transactional
@Caching(evict = {
        @CacheEvict(cacheNames = "barterMyInfo", allEntries = true),
        @CacheEvict(cacheNames = "userProfile", allEntries = true),
        @CacheEvict(cacheNames = "itemInfo", allEntries = true),
        @CacheEvict(cacheNames = "itemDetailInfo", allEntries = true),
        @CacheEvict(cacheNames = "itemTradeCheckInfo", allEntries = true)})
public BarterStatusDto acceptTrade(Long barterId) {

 

 다음과 같이 파라미터가 barterId 하나 뿐이라서,

위에서 설정한 키값 userId를 대입할 수 없게 되었습니다.

 

현재는 간단히 캐시의 정보 동시성을 구현하기 위하여 다음과 같이 교환수락, 교환 신청등

각 캐시에 업데이트가 발상하게 되는 경우

 

userId별로, 즉 유저별 개별로 캐시가 업데이트가 되지않고,

1. A, B, C, D 유저에 대한 캐시를 가지고 있으면

2. B가 교환수락, 교환 신청 등을 요청할 경우

3. A, B, C, D 유저 전체에 대한 캐시를 일괄 삭제

 

하는 방법으로 작동 되도록 구현하였습니다.

 

현재 사용자가 적기 때문에 사용에는 큰 문제가 없을 수 있지만,

 

실제 비즈니스 서비스를 운영할 경우

다수의 유저의 캐시를 계속 일괄 삭제하기 때문에 불필요한 삭제요청이 발생하게됩니다. 

 

 

 

적용한 내역

더보기

 

캐시적용)
마이페이지 : userProfile
전체아이템목록(카테고리) : itemInfo
아이템상세정보 : itemDetailInfo
아이템 거래전 정보 : itemTradeCheckInfo
거래내역 목록 : barterMyInfo
 
 
 
<API상에 주어지는 파라미터와 KEY값의 불일치로 인한 캐시 전체 비우기 적용사례>
 
거래완료
itemDetailInfo
 
거래완료 취소
itemTradeCheckInfo
 
교환신청 취소
itemDetailInfo
itemTradeCheckInfo
 
교환신청 확인 페이지 수락 버튼
barterMyInfo / userProfile / itemInfo / itemDetailInfo / itemTradeCheckInfo
 
교환신청 확인페이지 거절버튼
barterMyInfo / itemInfo / itemDetailInfo / itemTradeCheckInfo
 

 

정말로 참고 많이한 링크

'공부 > Cache' 카테고리의 다른 글

카페인 캐시를 적용해보자.  (0) 2022.05.28
캐시를 알아보자 - 2  (0) 2022.05.27
카페인 로컬 캐쉬를 알아보자 -1  (0) 2022.05.27