-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Feature] - 좋아요 순 여행기 목록 조회 페이징 캐싱 #631
Conversation
Test Results 30 files 30 suites 59s ⏱️ Results for commit 537d2f7. ♻️ This comment has been updated with latest results. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
안녕하세요 클로버와 페어로 해당 PR에 참가한 리비입니다.
해당 PR은 담백하게 여행기 페이지를 캐싱하는 기능만 담았어요.
페이지 캐싱 작업은 해당 PR로만 끝날 예정은 아니고요, 현재 저희가 고려중인 사항들이 다음 PR들로 이어짐을 말씀드립니다.
현재 저희가 고려중인 사항들은 다음과 같은데 혹시 알고 있는 부분이나, 얘기해보고 싶은 부분들이 있으시다면 자유롭게 코멘트 남겨주시면 감사하겠습니다 🙇🏻♂️
- TravelogueResponse 등 캐싱하는 클래스의 명세(속성 구성)를 변경하게 되면 캐시를 무효화 해야 하는데.. 자동화할 수 있는 방법이 없나?
- 캐시를 가져오는 과정에서 예외가 발생하면 (역직렬화 실패) 예외 응답이 클라이언트에게 반환되는데 캐시가 실패하면 캐시 예외가 응답에 전파되지 않도록 하는 방법이 없나?
- @transactional과 @Cacheable을 함께 적용하면서 발생하는 문제 상황은 없나?
- 캐시 기능 동작에 대한 테스트 코드가 필요할까? 필요하다면 어떻게 작성되어야 할까?
- 분산락이 필요한 맥락이 있을까?
public class PageDeserializer extends JsonDeserializer<PageImpl<?>> { | ||
|
||
@Override | ||
public PageImpl<?> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { | ||
List<Object> content = new ArrayList<>(); | ||
int pageNumber = 0; | ||
int pageSize = 0; | ||
long totalElements = 0; | ||
Sort sort = Sort.unsorted(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
회의에서 말씀드린데로 저와 클로버는 Page를 캐싱했습니다.
그런데 캐싱된 페이지를 꺼내오는 과정에서 PageImpl로의 역직렬화가 실패했었는데요, 이는 PageImpl의 기본 생성자가 존재하지 않아 ObjectMapper가 리플렉션하지 못하기 때문이었습니다.
문제를 해결하기 위해서는 다음의 두가지 방법 중 하나를 선택해야 합니다.
- PageImpl을 감싸는 Wrapper Class를 만든다.
- PageImpl 객체 역직렬화를 커스터마이징
저와 클로버는 Wrapper 클래스를 운용하게 되는 경우 어색한 점이 있다고 판단했습니다.
Wrapper 클래스를 운용하게 되면 기존 코드의 수정이 불가피하고 캐싱하는 메서드와 캐싱하지 않는 메서드의 반환타입이 달라지는 부분이 클래스 운용 명세가 숨겨지는 잠재적 위험이라고 생각한 것이 이유에요.
따라서 PageImpl 객체를 커스텀 역직렬화하는 코드를 작성한 것이 해당 코드입니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
저도 래퍼로 감싸서 해당 래퍼 클래스를 직접 사용하는 것은 좋지 못한 구조라 생각합니다.
캐시 도입이 어노테이션을 넘어서 동작하고 있는 서비스 코드에 변경을 주지 않는 것이 좋다고 생각합니다.
좋은 방향으로 역직렬화 문제를 해결해 주셨네요!
public class SortDeserializer extends JsonDeserializer<Sort> { | ||
|
||
@Override | ||
public Sort deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { | ||
List<Sort.Order> orders = new ArrayList<>(); | ||
boolean sorted = false; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
해당 역직렬화 설정은 PageImpl을 생성하기 위해 필요한 Sort 객체의 역직렬화 로직입니다.
Jmeter를 통해서 캐시 도입전과 도입 후의 성능을 로컬에서 비교해보았습니다. 설정
With No CacheWith Cache캐싱을 도입하지 않는 경우 평균 응답속도 85ms, 캐싱을 도입한 경우 평균 응답속도 7ms로 페이징 api는 약 91.76%의 성능 개선이 이루어졌습니다. 그래프를 보시면 캐싱을 진행하는 경우 초기에 캐싱 데이터가 없는 경우 response가 높지만 이후 안정적으로 응답속도가 유지되는 것을 확인하실 수 있습니다. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
역직렬화와 TTL을 30분으로 잡은 부분 이해하였습니다!
속도도 많이 개선되었네요 ㅎㅎ
리비가 말씀해 주신 고민 포인트는 다음 회의 때 같이 이야기해봐도 좋을 것 같습니다!
고생많으셨습니다!!
public class PageDeserializer extends JsonDeserializer<PageImpl<?>> { | ||
|
||
@Override | ||
public PageImpl<?> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { | ||
List<Object> content = new ArrayList<>(); | ||
int pageNumber = 0; | ||
int pageSize = 0; | ||
long totalElements = 0; | ||
Sort sort = Sort.unsorted(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
저도 래퍼로 감싸서 해당 래퍼 클래스를 직접 사용하는 것은 좋지 못한 구조라 생각합니다.
캐시 도입이 어노테이션을 넘어서 동작하고 있는 서비스 코드에 변경을 주지 않는 것이 좋다고 생각합니다.
좋은 방향으로 역직렬화 문제를 해결해 주셨네요!
✅ 작업 내용
Page
객체 역직렬화를 위한 Deserializer 추가🙈 참고 사항
Page
객체는 기본 생성자가 없어 역직렬화가 수행되지 않아 역직렬화 모듈을 만들기 위한 클래스가 두 개 추가됐습니다.리뷰할 때 참고 부탁드려용