Skip to content
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

[2단계 - DB 복제와 캐시] 프린(남기범) 미션 제출합니다. #93

Merged
merged 16 commits into from
Nov 1, 2024

Conversation

GIVEN53
Copy link
Member

@GIVEN53 GIVEN53 commented Oct 26, 2024

안녕하세요 알파카 🦙🦙
1단계에서 WAS 이중화를 가정했기 때문에 Redis를 캐시 서버로 사용하고, 캐시에 데이터가 없으면 DB를 조회하는 Look Aside 전략을 선택했습니다

  1. 캐시 서버에 데이터가 있는지 확인 (cache hit)
  2. 캐시 서버에 없으면 DB에서 데이터 조회 (cache miss)
  3. DB에서 조회한 데이터를 캐시 서버에 업데이트

쿠폰을 생성할 때는 캐시에 저장하지 않기 때문에 캐시 쓰기 전략은 고려하지 않았어요

캐시된 데이터의 TTL은 30분입니다
쿠폰 중에서도 자주 조회되는 쿠폰(ex. BBQ와 같은 프랜차이즈 가게)과 자주 조회되지 않는 쿠폰(ex. 개인 자영업자 가게)이 있을 것이라고 생각했고, 자주 조회되지 않는 쿠폰이 불필요하게 메모리를 점유하지 않도록 하기 위함이에요
자주 조회되는 쿠폰은 TTL이 지속적으로 갱신되기 때문에 TTL을 30분으로 잡더라도 cache miss가 자주 발생하지 않을 것 같고, 더 적절한 TTL 값은 cache miss를 모니터링하면서 찾아보지 않을까 싶어요

Redis는 TTL 이전에 데이터를 읽거나 업데이트했을 때 TTL 값을 다시 초기화하는 TTI(Time To Idle)를 지원하지 않아요
하지만 Spring Data Redis에서는 TTI 활성화 기능을 제공해서 TTL을 초기화할 수 있습니다
reference: https://docs.spring.io/spring-data/redis/reference/redis/redis-cache.html#redis:support:cache-abstraction:expiration:tti2

3단계는 진행하지 않을 예정이라서 2단계가 마지막이 될 것 같습니다 이번 리뷰도 감사합니다 👍🏻

@GIVEN53 GIVEN53 self-assigned this Oct 26, 2024
@slimsha2dy slimsha2dy self-requested a review October 29, 2024 06:55
Copy link
Member

@slimsha2dy slimsha2dy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

안녕하세요 프린. 정말 마지막의 마지막 미션의 마지막 단계네요.
이번 미션의 요구사항 전부 잘 반영하신 것 확인했습니다!
딱 요구사항에 맞춰서 깔끔하게 구현하신 것 같습니다.
리뷰는 많진 않지만 전반적으로 궁금한 점 위주로 남겼습니다.
확인해주시고 편하실 때 답변 남겨주시면 감사하겠습니다~!

Comment on lines +36 to +37
@Column(nullable = false)
private Long memberId;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

쿠폰은 저장소 분리로 인해 연관관계를 끊은 것으로 이해했는데 멤버도 저장소 분리를 고려해서 연관관계를 끊으신 걸까요?

Copy link
Member Author

@GIVEN53 GIVEN53 Oct 31, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵 멤버도 db를 분리하지 않을까 싶어서 끊었어요!

@Transactional
public void issue(Long memberId, Long couponId) {
Member member = getMember(memberId);
Coupon coupon = couponService.getCoupon(couponId);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

서비스 계층이 서비스를 의존하는 건 유지보수성, 확장성, 예측하기 힘든 구조 등의 여러 이유로 지양해야 한다고 생각하긴 하는데요. 그럼에도 이번 과제에서 간단 명료한 구조를 유지하면서 해결하기엔 쉽지 않을 것 같아 고민이 많았습니다.. 그리고 이런 이유로 기능 계층과 구현 게층을 분리하는 이유를 요즘 알 것 같기도 해요 😢
프린은 어떤 이유로 같은 계층 간 의존관계를 허용하게 되었나요?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

캐시를 적용해서 서비스 계층끼리 의존하게 되었어요
지금은 구현 크기가 작아서 허용하고 넘어갔지만 어느 정도 크기가 커지면 미리 분리해볼 것 같아요 땅콩에서는 서비스 계층 위에 파사드 서비스 계층을 하나 더 두어서 해결했었습니다!

Comment on lines +12 to +24
@ExtendWith(DatabaseCleanerExtension.class)
@SpringBootTest(webEnvironment = WebEnvironment.NONE)
public abstract class BaseServiceTest {

@Autowired
protected CouponRepository couponRepository;

@Autowired
protected MemberRepository memberRepository;

@Autowired
protected MemberCouponRepository memberCouponRepository;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 이런건 처음보는데 신기하고 깔꼼하네요 👍

void setUp() {
member = memberRepository.save(new Member("alpaca"));
coupon = couponRepository.save(
new Coupon("알파카 털뭉치 할인", 1_000, 5_000, LocalDate.now(), LocalDate.now(), Category.FOOD));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저한텐 소중한 건데 할인을..

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

하하하 싸게 주세요

import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;

@ExtendWith(DatabaseCleanerExtension.class)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거도 처음 보는데 굉장히 스킬풀하네요
하나 배워갑니다 ㅎㅎ

Copy link
Member

@slimsha2dy slimsha2dy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

답변 달아주신 것 확인했습니다!
구현 너무 잘 해주신 것 같아 머지하도록 하겠습니다.
테스트도 전부 정상 동작하는 것 확인했습니다.
그동안 미션 진행하시느라 수고 많으셨습니다!

@slimsha2dy slimsha2dy merged commit 95ec688 into woowacourse:given53 Nov 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants