Commit f7316a9
authored
feat: Redis 기반 동시성 제어 및 큐 기반 수강신청·취소 비동기 처리 구현 (#176)
* test: 현재 동시성 문제가 발생하는지 확인하기 위한 테스트 추가
- 동시에 100명이 신청했을 경우 최대 수강 인원이 30명인 강좌에 몇명이 등록되는지 확인
- 수강신청 내역이 30개가 아닌 100개가 생성되고있음
- 강의 정보에 현재 수강인원이 제대로 갱신되고 있지 않음
- 30명이 채워져야하지만 11, 12명 등 이상한 값으로 채워지고 있음
# Conflicts:
# backend/src/main/java/com/WEB4_5_GPT_BE/unihub/domain/enrollment/repository/EnrollmentRepository.java
* feat: 수강신청 로그를 추가하여 수강인원이 제대로 증가하지 않는 문제점 파악
- 동시에 수강신청을 보내고 인원을 변경하기 때문에 해당 강좌의 현재수강신청 인원 수가 제대로 증가하지 않고 오히려 적게 나타나는 문제였음
```
수강 신청이 완료되었습니다. 학생: 25020004, 강좌: 0
수강 신청이 완료되었습니다. 학생: 25020010, 강좌: 0
수강 신청이 완료되었습니다. 학생: 25020002, 강좌: 0
수강 신청이 완료되었습니다. 학생: 25020005, 강좌: 0
수강 신청이 완료되었습니다. 학생: 25020006, 강좌: 0
수강 신청이 완료되었습니다. 학생: 25020003, 강좌: 0
수강 신청이 완료되었습니다. 학생: 25020001, 강좌: 0
수강 신청이 완료되었습니다. 학생: 25020009, 강좌: 0
수강 신청이 완료되었습니다. 학생: 25020008, 강좌: 0
수강 신청이 완료되었습니다. 학생: 25020007, 강좌: 0
현재 수강인원 변경이 완료되었습니다. 학생: 25020001, 강좌: 1
현재 수강인원 변경이 완료되었습니다. 학생: 25020006, 강좌: 1
현재 수강인원 변경이 완료되었습니다. 학생: 25020004, 강좌: 1
현재 수강인원 변경이 완료되었습니다. 학생: 25020005, 강좌: 1
현재 수강인원 변경이 완료되었습니다. 학생: 25020002, 강좌: 1
현재 수강인원 변경이 완료되었습니다. 학생: 25020007, 강좌: 1
현재 수강인원 변경이 완료되었습니다. 학생: 25020010, 강좌: 1
현재 수강인원 변경이 완료되었습니다. 학생: 25020003, 강좌: 1
현재 수강인원 변경이 완료되었습니다. 학생: 25020008, 강좌: 1
현재 수강인원 변경이 완료되었습니다. 학생: 25020009, 강좌: 1
```
* refactor : 변경된 회원 도메인에 맞게 테스트 코드 수정
* feat: Redisson을 통한 수강신청 동시성 제어 구현
- 코드별 주석으로 상세 설명
* feat: 동시성 테스트는 프로젝트 테스트에서 진행하지 않도록 @Profile("!test") 수정
- 현재 동시성 로직은 별도의 트랜잭션을 생성하기 때문에 test 코드 상에 transational 을 붙여줄 수 없음
- test 코드에서 @transational 을 붙이지 않으면 테스트 과정에서 수정된 데이터가 롤백되지 못해 다른 테스트에 영향을 줄 수 있음
- 또한 동시성 관련 테스트는 생성해야 하는 회원 데이터 등이 많아 테스트에 부하가 많이 걸림
- 프로젝트 테스트에서 동시성을 검증하지 않고 별도의 툴 (jmeter) 을 통해 외부에서 테스트 할 예정
* feat: 동시성 테스트용 데이터 (4학년 학생 100명 및 신청용 강좌) 생성
# Conflicts:
# backend/src/main/java/com/WEB4_5_GPT_BE/unihub/global/init/InitDevData.java
* feat: 동시성 문제 해결을 위해 redis의 원자성이 보장되는 AtomicLong 적용 및 Queue를 통한 수강신청 비동기 처리 구현
- Redis RAtomicLong 을 이용해 capacity 및 enrolled 카운터를 원자적으로 관리하고, 수강신청 시 increment하여 동시성 보장
- 수강신청 요청 시 DB 트랜잭션 대신에 Redis 카운터만 업데이트하여 빠른 응답을 제공
- EnrollmentCommand DTO 를 통해 수강신청 정보를 큐(RBlockingQueue<EnrollmentCommand>)에 저장
- EnrollmentCommandConsumer 가 큐에서 명령을 순차적으로 꺼내 EnrollmentCommandHandler 에게 위임
* feat: Redisson을 활용하여 강의 생성 시 강의 수강 인원 및 수용 인원 정보를 Redis에 저장하는 기능 추가
* docs: k6를 활용한 수강신청 동시성 테스트 (100명 동시 신청 시 30명 정상 등록 완료) 파일 추가
- local 테스트
* test: 변경된 로직에 맞게 테스트 코드 수정
* refactor: 잘못 적용되어있는 ConcurrencyGuard 제거
* feat: EnrollmentDuplicateChecker를 구현하여 중복 queue 삽입 (동일 학생이 연속으로 신청하는 경우 (따닥)) 방지
- k6 테스트 스크립트 추가 (한 학생이 동일강좌에 5번 동시에 신청)
* docs : 주석 추가
* refactor: EnrollmentAlreadyQueuedException 예외처리를 공용으로 사용할 수 있도록 수정
* feat: 강의 취소의 경우에도 순차적으로 queue를 통해 처리될 수 있도록 수강 신청 로직과 동일하게 구현
* docs: 30명 동시 수강신청 및 동시 수강 취소 k6 테스트 스크립트 추가
* refactor : 수강신청 api 주석 수정 및 수강신청 queue 처리 후 flag를 제거하도록 추가
* refactor : 테스트용 대기열 설정 제거
* test : 테스트 코드 수정
* refactor: 패키지 이동
* feat: 강의 등록, 수정 시 redis에 저장된 Enrolled와 Capacity를 업데이트하도록 추가
* feat: 강의 삭제 시 redis에 저장된 Enrolled와 Capacity를 삭제하도록 구현
* feat: redis counter 관련 로직을 별도의 service로 분리
* feat: 프로젝트 재부팅 시 redis에 저장된 counter 값을 현재 강의 정보와 동기화 하도록 구현
* test: 변경된 로직에 맞게 테스트 코드 수정
* feat: initData 과정에서 강의 생성 시 counter를 redis에 저장하도록 추가
* refactor: 필요없는 주석 제거1 parent 333e448 commit f7316a9
39 files changed
Lines changed: 1918 additions & 195 deletions
File tree
- backend
- k6
- src
- main
- java/com/WEB4_5_GPT_BE/unihub
- domain
- course
- repository
- service
- enrollment
- controller
- exception
- repository
- service
- async
- cancel
- enroll
- global
- concurrent
- exception
- config/redisson
- init
- redis
- resources
- test/java/com/WEB4_5_GPT_BE/unihub/domain
- course/service
- enrollment
- controller
- service
- member/controller
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
39 | 39 | | |
40 | 40 | | |
41 | 41 | | |
| 42 | + | |
42 | 43 | | |
43 | 44 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
87 | 87 | | |
88 | 88 | | |
89 | 89 | | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
90 | 93 | | |
91 | 94 | | |
92 | 95 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
0 commit comments