(Spring/Redis/@Cacheable) Spring Cacheable로 캐싱기능 적용기
(Spring/Redis/@Cacheable) Spring Cacheable로 캐싱기능 적용기
자사 웹 메인 페이지의 일부입니다.
여기에 어떻게 캐시가 적용되어 있을까요?
먼저 캐시적용에 Spring에서 제공하는 @Cacheable 인터페이스를 사용하였습니다. (자세한 설정방법은 생략)
@Override @Cacheable(value = "GoodsBaseService.getMainGoodsRecommend", keyGenerator = "customKeyGenerator", cacheManager = "cacheManager10Minute") public List getMainGoodsRecommend(Locale locale, int size) throws IOException, DataNotFoundException { final Call request = goodsBaseRetrofitService.getMainGoodsRecommend(locale, size); Response response = requestExecute(request); return ApiUtils.listToObjectsAvoidNull((List) response.body().getData(), GoodsBase.class); }
: 위 설정으로 추천상품 리스트에 파라메터 별로 10분 캐시가 적용되었습니다. (다른 리스트들도 위처럼 적용)
파라메터를 기반으로 캐시 key를 생성하는 클래스 구현
public class CustomKeyGenerator implements KeyGenerator { @Override public Object generate(Object target, Method method, Object... params) { return target.getClass().getSimpleName() + "_" + method.getName() + "_" + StringUtils .arrayToDelimitedString(params,"_"); } }
: 키 생성에 타깃 오브젝트 이름, 메소드이름, 파라메터가 사용됩니다.
따라서 같은 메소드라도 파라메터가 다르면 캐싱이 따로 적용되도록 하였습니다.
이 부분이 중요한 이유가 있습니다. 예를 들어 한국지역에서 처음 조회가 되어 캐싱이 되어있다고 가정하고
그다음 다른 유저가 지역을 미국에서 들어와서 모두 영어 번역본으로 데이터가 제공되어야 한다고 할 때,
locale이 다른 값으로 들어올 것입니다. 하지만 파라메터 기반으로 키가 만들어지지 않고 메소드명만 사용한다면
key가 같으니 캐시 hit로 판단하여 이전에 캐싱된 한국어로 된 데이터들이 보이게 되겠지요!
캐시를 적용하고 난 후, 평균 응답속도가 매우 빨라짐을 느낄수 있습니다. (캐시 적용 전 3~4초 -> 적용 후 0.5초 미만)
서버간 / DB간 통신 과정, 로직수행시간 등이 생략되어 속도가 향상 된 것이지요.
하지만!
캐시를 적용할 때 고려할 사항이 몇가지 있습니다.
1. 캐시 히트율이 적으면 오히려 더 성능이 나쁠 수있음
: 캐시를 확인하고, 저장하는 과정이 더 추가되기 때문에 캐시 히트가 되지 않았을 때는 적용되지 않은 것보다 더 비용이 많이 듭니다.
2. 동기화 문제 발생 가능
: 캐시가 만료되지 않았을 경우 캐시에서 응답은 기존 데이터로 계속 응답하게 됩니다.
만약 상품 1에 캐시가 적용되어 있다고 가정하였을 때, 상품 1의 가격이 바뀌어도
조회했을 때 캐시가 남아있으면 기존 가격으로 보이게 될것입니다.
위 두가지 사항 모두 잘 고려되어야 하는 상황이 이번에 딱 발생했습니다.
최근 코로나 이슈로 자사에 트래픽이 엄청나게 감소한 것인데요.. ( 슬프네요ㅠㅠ)
페이지에 접속자가 많이 없다보니 캐시 히트율이 급격하게 떨어져 페이지 응답속도가 느려지는 이슈가 발생하였습니다.
따라서, 캐시 만료시간을 늘리기로 결정 하였습니다. (10분 -> ??시간)
캐시 만료시간을 늘리게 되면, 만료시간안에 다시 요청될 확률이 늘어나니 히트율이 높아지게 되겠지요.
하지만, 가격이 바뀌거나 댓글이 달려서 상품의 댓글수가 바뀌었을 때
캐시 만료시간이 끝날 때까지 데이터가 갱신되지 않는 문제점이 있었습니다.
이 문제를 해결하기 위해 Spring이 제공하는 @CacheEvict 인터페이스를 활용하여 해당 상품의 캐시 데이터를 지우는 기능울 만들고
상품 관련 데이터에 변동이 있을 경우, 위 기능을 호출하도록 하였습니다.
예시)
@Override @CacheEvict(value = "GoodsBaseService.getInternalGoodCard", keyGenerator = "customKeyGenerator", cacheManager = "cacheManager3Hour") public GoodCard getInternalGoodCard(SaleType saleType, Language language, Currency currency, Long goodsId, APIType internal, String countryCode, ZoneId of) throws IOException, DataNotFoundException { return null; }
이제 캐시를 시간단위로 늘려도 갱신이 되지 않거나 하는 일은 없어졌고,
캐시 히트율이 늘어 응답속도가 향상 되었습니다.
주의할점: 위 상황은 상품 관련 데이터가 변동이 적다는 가정하에 진행한 것이고,
계속 캐시가 갱신된다면 오히려 성능이 더 나빠질 것입니다.
읽어주셔서 감사합니다.
By. Ryankim
from http://lion-king.tistory.com/55 by ccl(A) rewrite - 2020-03-21 18:20:29
댓글
댓글 쓰기