티스토리 뷰
작업내용
매일 한정된 수의 사용자를 접속시점 무작위로 당첨시켜 사용자 정보를 적재 및 즉석으로 확인 가능한 기능
현재 상황
작업환경
- 2대 이상의 다중 서버 환경
- messageQueue 용도 서버 도입 불가
- oracle DB RAC 환경
최초로직
쿠폰을 지급하기 전 현재까지 당첨된 사용자의 수를 조회하여 한정된 수치에 도달하지 않은 경우 당첨자 정보를 DB에 적재하는 방법
최초로직 문제점
예를들어 100개 한정된 수량의 쿠폰을 지급 시 다중서버 및 동시응모에 의한 100명을 초과하는 당첨자가 발생하는 경우를 확인
(이때 테스트는 junit을 통하여 멀티스레드 환경으로 진행)
최초로직 원인
A트랜잭션과 B트랜잭션이 거의 동시에 진행된 경우
A트랜잭션 조회 시점에 당첨자 수 99명
당첨자 적재 100명
커밋
B트랜잭션 조회 시점에 당첨자 수 99명
당첨자 적재 101명
커밋
만약 서버 수와 동시진행 숫자에 따라서 초과한 숫자는 더 커질 수 있다.
최초로직 개선
가능한 비즈니스 로직으로 풀어보려 당첨자 적재 후 일일 한정된 수치를 초과한 경우 해당 당첨자를 낙첨으로 업데이트하려고 하였으나 이 방법 역시 동일한 원인으로 동일한 문제점이 발생하였다.
개선로직 1
당첨자 적재하는 메서드에 @Transactional 격리레벨을 변경하는 방법
개선로직 1.1
적재 메서드에 @Transactional(isolation=Isolation.READ_UNCOMMITTED) 격리레벨을 적용하여 적재시점에 커밋되지 않은 내용까지 조회 후 한정 수치 초과 여부를 판단 후 당첨자 적재하는 방법
org.springframework.transaction.CannotCreateTransactionException: Could not open JDBC Connection for transaction; nested exception is java.sql.SQLException:
READ_COMMITTED와 SERIALIZABLE만이 적합한 트랜잭션 레벨입니다
오라클 DB는 해당 격리레벨을 지원하지 않기 때문이다.
개선로직 1.2
적재 메서드에 @Transactional(isolation=Isolation.SERIALIZABLE) 격리레벨을 적용하여 현재 총 당첨자 수를 저장하는 레코드를 동시에 수정할 수 없도록 하는 방법
해당 격리레벨을 적용하였을 때 테스트 환경임에도 성능이 감소되어 운영환경에 적용 시 성능저하 및 장애발생 우려되어 보류.
개선로직 2(성공)
oracle 시퀀스를 활용하여 당첨일련번호 발급하는 방법
DB서버가 1대 이상인 RAC환경이지만 시퀀스 옵션을 조정하여 WAS서버의 대수와 동시응모와 상관없이 시퀀스를 순차적으로 증가할 수 있도록 하는 방법
당첨자일련번호 용도의 오라클 시퀀스를 생성
CREATE SEQUENCE 당첨일련번호_시퀀스
START WITH 1
MAXVALUE 999999
MINVALUE 0
NOCYCLE
NOCACHE
ORDER;
NOCACHE와 ORDER 옵션을 선언하여 어떤 DB서버가 여러 대인 경우에도 일련번호를 순차적으로 발급받을 수 있다.
시퀀스를 활용하여 작성한 주요 로직은 아래와 같다.
if(당첨자인 경우){
int 당첨자일련번호 = 적재하기 전 시퀀스를 통하여 당첨자일련번호 채번;
if(당첨자일련번호 > 일일 당첨자한정수치){
당첨되었지만 동시응모 후순위 상황으로 낙첨 처리
} else {
당첨정보와 함께 당첨자일련번호 적재
}
}
오라클 시퀀스를 활용하여 동시성 문제는 해결하였으나 당첨인원의 수를 대량으로 늘리거나
로직상 시퀀스 증가를 계속해서 하는 경우라면 DB에도 부하가 발생할 수 있으나 현재 상황에서
작업 공수를 최소화 한 방법이다.
추후 messageQueue를 사용하여 동시성 문제를 해결하는 로직을 개인 프로젝트에 적용을 고려해보려 한다.
'설계' 카테고리의 다른 글
다중 서버인 환경에서 DB를 사용한 각 서버 작업 진행 (0) | 2021.12.29 |
---|
- Total
- Today
- Yesterday
- Eclipse
- IMAGE
- 이벤트발생
- html
- mybatis
- 깨짐
- TLS
- web
- SSL
- jaxen
- btye
- JSON
- JPA
- jQuery
- gradle
- Oracle
- WAS
- Linux
- spring
- Git
- 날짜
- React
- Java
- docker
- parse
- vscode
- 컨테이너
- SQL
- SpringBoot
- Windows
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |