-
Notifications
You must be signed in to change notification settings - Fork 16
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
좋아요 수 및 좋아요 변경 이력 캐싱 #752
좋아요 수 및 좋아요 변경 이력 캐싱 #752
Changes from 1 commit
51bd229
4fc0442
c931afa
392c5f8
b8499f7
9db56c3
ca1aed5
45d1168
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package hanglog.like.domain; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
import org.springframework.data.annotation.Id; | ||
import org.springframework.data.redis.core.RedisHash; | ||
|
||
@Getter | ||
@AllArgsConstructor | ||
@RedisHash(value = "likeCount") | ||
public class LikeCount { | ||
|
||
@Id | ||
private Long tripId; | ||
|
||
private Long count; | ||
} |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package hanglog.like.dto; | ||
|
||
import lombok.Getter; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
@Getter | ||
@RequiredArgsConstructor | ||
public class TripLikeCount { | ||
|
||
private final long tripId; | ||
private final long count; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package hanglog.like.repository; | ||
|
||
import hanglog.like.domain.LikeCount; | ||
import java.util.List; | ||
import org.springframework.data.repository.CrudRepository; | ||
|
||
public interface LikeCountRepository extends CrudRepository<LikeCount, Long> { | ||
|
||
List<LikeCount> findLikeCountsByTripIdIn(final List<Long> tripIds); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,21 @@ | ||
package hanglog.like.service; | ||
|
||
import hanglog.like.domain.LikeCount; | ||
import hanglog.like.domain.Likes; | ||
import hanglog.like.domain.MemberLike; | ||
import hanglog.like.dto.MemberLikeCacheEvent; | ||
import hanglog.like.dto.TripLikeCount; | ||
import hanglog.like.dto.request.LikeRequest; | ||
import hanglog.like.repository.CustomLikeRepository; | ||
import hanglog.like.repository.LikeCountRepository; | ||
import hanglog.like.repository.LikeRepository; | ||
import hanglog.like.repository.MemberLikeRepository; | ||
import hanglog.member.domain.repository.MemberRepository; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Optional; | ||
import java.util.stream.Stream; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.context.ApplicationEventPublisher; | ||
import org.springframework.scheduling.annotation.Scheduled; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
@@ -18,8 +25,11 @@ | |
@Transactional | ||
public class LikeService { | ||
|
||
private final LikeRepository likeRepository; | ||
private final MemberLikeRepository memberLikeRepository; | ||
private final ApplicationEventPublisher publisher; | ||
private final LikeCountRepository likeCountRepository; | ||
private final MemberRepository memberRepository; | ||
private final CustomLikeRepository customLikeRepository; | ||
|
||
public void update(final Long memberId, final Long tripId, final LikeRequest likeRequest) { | ||
Map<Long, Boolean> tripLikeStatusMap = new HashMap<>(); | ||
|
@@ -39,8 +49,24 @@ public boolean check(final Long memberId, final Long tripId) { | |
return false; | ||
} | ||
|
||
@Scheduled(fixedRate = 3600000) | ||
@Scheduled(cron = "0 0 * * * *") | ||
public void writeBackMemberLikeCache() { | ||
publisher.publishEvent(new MemberLikeCacheEvent()); | ||
final List<Likes> likes = memberRepository.findAll().stream() | ||
.flatMap(member -> memberLikeRepository.findById(member.getId()) | ||
.map(memberLike -> memberLike.getTripLikeStatusMap() | ||
.entrySet().stream() | ||
.filter(Map.Entry::getValue) | ||
.map(entry -> new Likes(entry.getKey(), member.getId()))) | ||
.orElseGet(Stream::empty)) | ||
.toList(); | ||
customLikeRepository.saveAll(likes); | ||
} | ||
|
||
@Scheduled(cron = "0 0 0 * * *") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 굉장합니다!!!!!!!!신기합니다!!! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 홍고가 만들어 놓은 일일 환율 저장 로직 참고한건데요!!!!! 본인 칭찬인가요!!!!!!!! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 아니ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ 요 스케줄링 아래 캐싱로직말한거였는데 제가 이상한 포인트에서 댓글을 달았군요 ㅋ ㅋ ㅋ |
||
public void cacheLikeCount() { | ||
final List<TripLikeCount> tripLikeCounts = likeRepository.findCountByAllTrips(); | ||
for (final TripLikeCount tripLikeCount : tripLikeCounts) { | ||
likeCountRepository.save(new LikeCount(tripLikeCount.getTripId(), tripLikeCount.getCount())); | ||
} | ||
} | ||
} |
This file was deleted.
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.
memberLikeRepository에서 멤버의 모든 좋아요 상태(tripLikeStatusMap)을 가져올 필요없이 타겟인 tripId의 상태만 알아오면 되는거죠?!
memberLikeRepository.findByMemberIdAndTripId()
같은거는 만들기 힘든가요?! redis는 오히려 저렇게 전부 조회해오는게 성능이 더 좋은가요? 궁금해서 여쭤봅니다!!!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.
아하?!!! 혹시
getCommunityTripsByPage()
에서는 mysql의Likes
테이블에서 멤버의 isLike정보를 불러오고, 이getTripDetail()
에서는 redis의MemberLike
에서 멤버의 isLike정보를 불러오는 거 맞나요?!1시간마다 redis에서 mysql로 동기화를 하는데, 그럼 커뮤니티 전체 페이지에서는 멤버의 좋아요 표시가 안보이고, 디테일 페이지에서는 멤버의 좋아요 표시가 보이는 일이 생길까요?
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.
아아 이부분 논의하고 싶었는데 깜빡했네요.
지금 단건 조회인 getTripDetail()의 경우
Redis의 MemberLike에서 게시물 좋아요 이력(isLike) 확인 -> 없으면 DB에서 조회
의 로직인데요.
현재 게시물 리스트 조회의 경우 likeRepository.findLikeCountAndIsLikeByTripIds()를 통해 한 번의 쿼리로 모든 좋아요 이력을 조회해오고 있어요.!
이걸 getTripDetail에 사용한 로직처럼 바꾸면 결국 trip 하나하나당 Redis에 isLike가 있는지 확인하고, 없으면 DB에서 조회
이런 식으로 진행되서 결국 성능이 더 안좋아지는 상황이 생길 수 있을거 같아서 어떻게 해야할 지 의견을 들어보고 싶었습니다.!
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.
아 근데 생각해보니까 리스트 조회도 그냥
레디스에서 해당 멤버에 해당하는 Map 가져옴 -> 조회할 trip 리스트가 key에 존재하는지 확인하고 없는 Id는 따로 리스트 만들어 놓음 -> 해당 Id 리스트로 findLikeCountAndIsLikeByTripIds() 호출 -> 캐시에 있던 여행과 없던 여행 하나로 합쳐서 반환
의 로직으로 하면 최대 쿼리 수 1번으로 끝낼 수 있겠네요..!
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.
굉장합니다!!!!!!!!!!!!!