본문 바로가기

백엔드 개발/Spring

[spring] redis로 caching해서 dbms의 부하 줄이기 - 2

반응형


1. 필요한 기능 테스트 코드로 작성

EventCacheService라는 객체를 이용해서 캐싱과 관련된 기능들을 구현한다.

우선 test를 작성해서 필요한 메소드들을 명세해보자


컨텐츠를 조회하는 work flow


1. 사용자는 서버에 컨텐츠 요청(페이징과 검색 조건 있습니다.)

2. 검색조건으로 조합한 키로 레디스에 관련 컨텐츠가 캐싱되어 있는지 확인(exist()에 해당)

(레디스에 키가 없는 경우)

3. 값이 없는 경우 mariadb에서 입력받은 검색조건으로 모든 컨텐츠 조회하고 redis에 저장(save()에 해당)

4. key에 대해서 expire 속성을 넣어준다.(다음 크롤링할 떄 까지로(최소 일주일 가량 될 것)

5. 이제 사용자에게 컨텐츠를 리턴해줌

(레디스에 키가 있는 경우)

3. 레디스에서 해당하는 컨텐츠를 페이징해서 사용자에게 리턴해줌

사용자는 레디스 서버의 존재의 유무와 상관없이 데이터를 조회할 수 있어야함함.


2. 검색 조건으로 키를 생성하는 메소드를 생성

키는 SearchVO라는 객체를 이용해 생성할 것 이고 [region]::[kindOf]::[startDate]::[endDate] 형식으로 생성한다.

테스트 코드는 아래와 같다.


실행했는데 아래와 같은 메시지를 보여주면서 실패한다.

java.lang.AssertionError: expected:<서울::Mu::2018-11-22T20:58:30.789::2018-11-23T20:58:30.790> but was:<null>

당연하다 getKey() 메소드에서는 null을 리턴하고 있다.


getKey()를 구현하고 테스트 코드를 실행하면 test가 성공한다.


3. 키의 존재유무를 확인하는 테스트 코드를 작성

 아래와 같은 코드를 작성하고 실행해보면 redisTemplate.hasKey()라는 메소드가 정상적으로 작동함을 알 수 있다.


※ leftPush(..) 부분을 주석처리해 테스트가 실패하도록 유도해서도 실행해보자.

   키가 없는 경우의 테스트케이스를 따로 작성하는 것도 좋겠다.

4. 키의 유효기간을 설정하는 기능을 테스트하자

레디스에는 EXPIREAT, EXPIRE 같이 키의 유효기간을 설정할 수 있는 기능이 있다.

우리가 필요한 기능은 EXPIREAT이다. spring-data-redis에서 해당 메소드를 제공하므로 테스트해보자.


일단 성공한다. 그런데 키가 애초에 안 들어갔는지 모르겠다 브레이크 포인트를 잡아서 잠깐 정지시키고 redis-cli로 들어가서 key와 expire 속성이 제대로 들어갔는지 확인해보자.




정상적으로 key가 들어가고 만료되는 것을 확인할 수 있다.

TTL key

Returns the remaining time to live of a key that has a timeout. This introspection capability allows a Redis client to check how many seconds a given key will continue to be part of the dataset.


키의 남은 시간을 실시간으로 확인할 수 있다고 한다.

출처: https://redis.io/commands/ttl


5. db에서 데이터를 불러와서 redis에 저장하는 로직에서 난관에 봉착

위와 같은 코드를 작성했다. interparkService라는 건 mariadb에 저장된 데이터를 불러오는 service이다.

그런데 searchEvent()라는 메소드의 반환타입이 EventResponse이다.

EventResponse는 컨트롤러에서 반환해주는 타입으로 http 통신에 관한(상태 코드) 정보를 가지고 있다.

우리가 searchEvent()라는 메소드를 사용하면 http response를 받아서 거기서 event와 관련된 객체 리스트만 따로 뽑아와서 사용해야하는 것이다..전혀 바람직하지 않다.


사실 항상 고민하던 부분이었다. controller에서는 메소드를 호출만해주는 역할을 해야한다고 생각해서 service에서 컨트롤러의 response 타입까지 함께 리턴해주는 버릇이 생겼었는데.

(첫번째 회사의 코드도 이와 같은 방식이라 별로 위화감을 못 느껴왔다.)

최근들어서 단일 책임 원칙에는 벗어나는 일이 아닌가라고 생각해서 찝찝하긴 했었다.     
이번에 코딩하면서도 searchEvent()를 컨트롤러말고 다른 곳에서 사용하리라곤 별로 생각하지 못했던 것 같다.


결론은 service에서 controller의 반환 타입 따위 알 필요가 없다.

단순한 애플리케이션에서는 별로 문제 없을지 모르지만 db를 두가지 이상 사용한다면 문제가 될 수 있다.

(애플리케이션을 확장하는데 애로사항이 생긴다.)

리팩토링이 필요한 부분이다.


반응형