-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
🛠️ [refactor] 강의 오픈시 수강생 정보 Redis에 캐싱하기 #62
Labels
Refactor
리팩토링
Comments
binary-ho
added a commit
that referenced
this issue
Aug 20, 2023
binary-ho
added a commit
that referenced
this issue
Aug 20, 2023
binary-ho
added a commit
that referenced
this issue
Aug 20, 2023
binary-ho
added a commit
that referenced
this issue
Aug 20, 2023
binary-ho
added a commit
that referenced
this issue
Aug 20, 2023
binary-ho
added a commit
that referenced
this issue
Aug 21, 2023
binary-ho
added a commit
that referenced
this issue
Aug 22, 2023
binary-ho
added a commit
that referenced
this issue
Aug 22, 2023
binary-ho
added a commit
that referenced
this issue
Aug 22, 2023
binary-ho
added a commit
that referenced
this issue
Aug 22, 2023
binary-ho
added a commit
that referenced
this issue
Aug 22, 2023
binary-ho
added a commit
that referenced
this issue
Aug 22, 2023
binary-ho
added a commit
that referenced
this issue
Aug 22, 2023
binary-ho
added a commit
that referenced
this issue
Aug 22, 2023
binary-ho
added a commit
that referenced
this issue
Aug 22, 2023
binary-ho
added a commit
that referenced
this issue
Aug 22, 2023
binary-ho
added a commit
that referenced
this issue
Aug 22, 2023
binary-ho
added a commit
that referenced
this issue
Aug 22, 2023
binary-ho
added a commit
that referenced
this issue
Aug 22, 2023
binary-ho
added a commit
that referenced
this issue
Aug 22, 2023
binary-ho
added a commit
that referenced
this issue
Aug 22, 2023
binary-ho
added a commit
that referenced
this issue
Aug 23, 2023
* feat : 현재 열린 강의를 표현하는 DTO OpenLecture와 OpenLectureRepository 구현 (#62) * feat : OpenLecture를 캐싱하는 OpenLectureRedisRepository를 구현하고 OpenLecture 정적 팩터리 메서드 구현 (#62) * chore : OPEN_LECTURE_KEY_PREFIX 추가 (#62) * refactor : AttendanceNumberRepository를 제거하고 AttendanceService에 OpenLectureRepository 적용 (#62) * refactor : OpenLectureFieldKeys를 OpenLectureRedisRepository의 Inner class로 변경 (#62) * test : FakeOpenLectureRepository를 구현해 AttendanceServiceTest에 적용 (#62) * chore : OpenLectureRedisRepository 형변환 부분 변경 (#62) * feat : 수강생을 저장하는 LectureStudentRepository 와 이미 저장된 수강생의 Redis Data Type에 따른 Read/Write 전략 구현 (#62) * feat : RedisTemplate이 @transactional에 포함되도록 설정 (#62) * refactor : Cache 목적의 save를 모두 Cache로 이름을 변경하고, 수강생이란 단어를 LectureStudent에서 Attendee로 이름 변경 (#62) * feat : AttendeeCacheEvent를 이용해 Attendee를 비동기적으로 캐싱하는 AttendanceService 구현 (#62) * refactor : OpenLectureService를 구현하여, AttendanceNumber가 필요할 때, Repository가 아닌 Service로 요청하도록 변경 (#62) * feat : 학생의 수강신청을 승인할 때, 이미 열려있는 강의라면, 학생 정보를 캐싱하는 기능 구현 (#62) * chore : 불필요한 LectureStudentRepository 삭제 (#62) * feat : 강의를 열 때, 강의 정보와 학생 정보를 캐싱하는 기능 구현 (#62) * chore : OpenLecture 생성자 변경 (#62) * refactor : Lecture의 Approved Enrollment를 가져오는 메서드 쿼리 변경 (#62) * feat : 학생이 열린 수업 정보를 가져오기 전에 캐싱된 데이터가 있는지 먼저 확인하고, 있는 경우 캐싱된 결과를 이용하는 기능 구현 (#62) * test : CacheRepository들의 Fake 객체를 구현해 TestContainer에 적용 (#62) * test : 기존 테스트에 OpenLecture와 Attendee의 캐싱을 위해 변경된 내용들을 적용 (#62) * chore : Lecture, OpenLecture, AttendeeCacheEvent를 Lecture Domain 패키지로 이동 (#62) * test : AttendeeCacheService와 OpenLectureService 단순 호출 테스트 작성 (#62) * test : 캐싱을 저장하고 확인하는 캐싱 관련 기능 Test Code 작성 (#62) * chore : OpenLectureService와 AttendanceService의 메서드 이름을 적절하게 변경 (#62) * refactor : AttendeeCacheRedisRepository의 자료형 변경으로 인해 발생하는 예외 catch (#62) * refactor : OpenLectureRedisCacheRepository에서 저장 key를 id를 이용해 만들도록 변경 (#62)
# for free
to join this conversation on GitHub.
Already have an account?
# to comment
🛠️ 리팩토링이 필요한 부분
학생이 출석 시도시, 수강 신청 데이터가 많으면 데이터를 가져오는데에 엄청난 시간이 소요되는 것을 확인했다,
(1000건 동시요청시 10만건에선 아예 600건 이상 타임아웃)
그래서 인덱싱을 통해 해결을 시도하니 약 6.5초만에 전부 성공했다 -> #57
그러나, 6.5초도 여전히 유저 입장에선 여전히 느리다고 생각되어, 강의를 열 때 수강생 정보를 캐싱을 해보기로 했다.
계획
1. 캐싱 대상
2. 개선된 출석 과정
3. 수업 정보는 같은 트랜잭션, 학생 정보는 비동기 자식 트랜잭션 (+Event를 통한 구현)
설계 과정에서 여러가지 방법을 고민했는데, 결국 구현중 Event를 발행해서 캐싱을 따로 처리하기로 결정했다. 그 이유는 다음과 같다
"열린 수업", "수강생"을 저장하는 작업은 수업을 여는 행위를 요청하는 강사 쪽에선 관심사가 아니다.
이 조건을 모두 만족시키는 간단한 방법이 Event를 사용하는 것이라고 생각되었다.
처음엔 Event를 사용하지 않고 단순 서비스로 구현했고,
@Async
와@Transactional(propagation = NESTED
로 해결할 수 있을 줄 알았다.하지만, 테스트 해본 결과 예상과는 다르게 부모 트랜잭션이 실패해도 자식 트랜잭션이 실패하지 않았다.
이벤트를 사용한다면 TransactionalListner의 Phase 설정을 After Commit으로 두면서 편리하게 커밋시에만 저장되면서도 비동기적으로 작동하게 만들 수 있다.
종합하면 내 목표는 아래와 같이 이룰 수 있다.
@Async
를 통해 수업을 여는 행위에 대한 응답을 바로 돌려주고, 캐싱은 비동기적으로 처리4. 유의할 점
1만명의 학생이 있다고 했을 때, 2MB가 최대이다. 그리고 이 1만명의 학생이 동시에 가입한다고 해도, 이메일 데이터가 100 초반대이므로, 2MB에 닿기 어렵다.
결론적으로 5MB의 공간이 있다면, 1만명의 학생이 동시에 가입하면서, 즉시 수업 정보를 캐싱할 수 있다.
현재 1000명 동시 출석이 목표인 시점에서 아주 충분한 값이다. (현재 EC2 스펙은 1GiB)
eviction 정책은 volitle ttl
: 앱에서 다양한 종류의 캐싱을 하지만, 가장 큰 용량을 차지하는 것은 이 수강생 정보이다. 문제는 수강생 정보는 사용되지 않은 데이터 일수록 오히려 사용 확률이 높다는 점이다 이는 기존의 캐싱 정책들과 반대이다왜냐하면 한번 출석한 학생은 오히려 또 출석할 일이 없고, 출석하지 않은 학생이 새로 출석할 가능성이 높기 떄문이다. 그래서 레디스에 이 상황에 100% 맞는 적절한 정책이 없다. (보통은 자주 쓰이는 데이터를 더 살려 놓는다)
그나마 적절해 보이는 것이 volitle-ttl이다. (정책이 아예 없는 경우엔 새로운 저장이 안 된다.) 그래서 volitle-ttl을 선택했다.
문제는 앱에서 캐싱하는 다양한 데이터 중에 캐싱된 데이터가 수강생 데이터가 제일 사라져도 문제가 없는 데이터란 것이고, 다른 데이터들은 사라지는 경우 문제가 된다.
이제까지 사라져선 안 되는 데이터들은 제한 시간이 실제 비즈니스적으로도 존재하는 데이터들이여서 비즈니스적인 제한 시간과 redis exprire time을 똑같이 맞췄다. 이젠, 이 데이터들의 exprire time을 2배로 늘리고, 따로 유효 시간을 저장하는 방식을 고려해봤다.
그러니까 위험을 대비해 저장 용량을 늘리게 되는 것이다.
이 방법은 기존의 일반적인 캐싱과 같은 상황에선 비싼 메모리 자원을 더 소모하는 것임으로 문제가 되겠지만, 우리 서비스에선 이런 방식으로 추가 메모리를 사용해 저장하는 자료가 적음으로 고려할만해 보인다. 만약 용량이 그리 넉넉하지 않았더라면, 유효시간을 대폭 줄이는 방법으로 바꿨을 것이다. -> 또다른 이슈가 필요하다
-> 강사가 학생을 승인했을 때, 강의가 이미 열려있다면 레디스에 캐싱한다.
리팩토링 작업 브랜치
feature/student-caching
☑ Refactoring TODO
The text was updated successfully, but these errors were encountered: