[Redisson]์ ์ด์ฉํ ๋ถ์ฐ Lock ๊ตฌํ & ๋์์ฑ ๋ฌธ์ ํด๊ฒฐ
๋ด ํ๋ก์ ํธ์ Payment๋ฅผ ๊ฐ๋ฐํ๋ฉด์ ๊ฐ์ฅ ๊ธฐ๋ณธ ์ค์ ๊ธฐ๋ณธ์ด ๋๋ ๋ฌธ์ ๋ฅผ ์ง๋ฉดํ์๋ค. ๊ทธ๊ฒ์ ๋ฐ๋ก ๋์์ฑ ๋ฌธ์ ! ์คํ๋ง๋ถํธ์ ๋ด์ฅ ์๋ฒ๋ ๊ธฐ๋ณธ์ ์ผ๋ก ํฐ์บฃ, ์ธ๋ํ ์ฐ ๋ฑ๋ฑ์ WAS๋ก ๋์๊ฐ๋๋ฐ ์ด
sweeeetgoguma.tistory.com
์ง๋ ํฌ์คํธ์์ Redisson์ ์ด์ฉํ์ฌ ๋์์ฑ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ์ฝ๋๋ฅผ ๊ตฌํํ๋ค.
ํ๋ก์ ํธ ๋ฆฌํฉํ ๋ง์ด ๊ฑฐ์ ๋๋๊ฐ ์กฐํ API๋ฅผ ๊ตฌ์ฒดํํ์ฌ ๋ช ๊ฐ ์ถ๊ฐํ๋ ๋์ค, ์ค๋ ๋ 100๊ฐ์ ๋์ ์์ฒญ์ ์ง์ ์ ์ผ๋ก ๋ฐ๋ ๊ณผ์ ์ ํ์ธํ๊ณ ์ถ์ด์ก๋ค.
๊ทธ๋์ ์คํํด๋ดค๋ค.
๊ฒฐ๊ณผ๋??
์ฒ์ฐธํ๋ค..
๋ฌด์์ด ๋ฌธ์ ์์๊น
ํธ๋์ญ์ ์ฒ๋ฆฌ๊ฐ ์นํ๋ค.
@GetMapping("/test")
public void test() throws InterruptedException {
int threadCount = 100;
ExecutorService executorService = Executors.newFixedThreadPool(100);
CountDownLatch latch = new CountDownLatch(threadCount);
for (int i = 0; i < threadCount; i++) {
int finalI = i;
executorService.submit(() -> {
try {
log.info(finalI +"๋ฒ์งธ ์ผ๊พผ ์ผํ๋ค.");
kakaopayStrategyApplication.test("lala");
} finally {
latch.countDown();
}
});
}
latch.await();
}
์ด ํ ์คํธ๋ฅผ ์ด์ฉํด์ 100๊ฐ์ ์์ฒญ์ ๋์์ ์์ฒญํ๋ฉด,
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void test(String id) {
log.info("์ผํด๋ผ!");
Product product = productRepository.findById(1L).orElseThrow(() -> new RuntimeException("์ํค์ด"));
log.info("์ํ ์ ๊ฐ์:" + product.getQuantity());
product.decreaseItemQuantity(1);
log.info("์ํ ํ ๊ฐ์:" + product.getQuantity());
}
์๋ ์ํ 200๊ฐ์์ 100๊ฐ๊ฐ ๋์ด์ผ ์ ์์ด๋ค.
ํ์ง๋ง, ๊ณ์ ์ด์ํ ์ฌ๊ณ ๋์ด ๋จ์๋ค..
@Transactional(propagation = Requires_New)๋ฅผ ํ๋ฉด ํธ๋์ญ์ ์ ์๋ก์ด ์์์ผ๋ก ์ธํด, AOP ์ด์ฉํ ๊ฒฝ์ฐ ๋ฌธ์ ๊ฐ ์์ ๊ฑฐ๋ผ๊ณ ์๊ฐํ๋ค.
๋ฌธ์ ์ธ์ง
์ด ๋ถ์ ๊ธ์ ์ฝ๊ณ , ๊นจ๋ฌ์๋ค..
temp method์ @Transactional์ ์ฌ์ฉํ๋ฉด ์ํํฉ๋๋ค.
๋ด๋ถ์ ์ผ๋ก AOP๋ฅผ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ unlock์ด ๋ ํ commit์ด ๋๋ฏ๋ก ๋๊ธฐํ๊ฐ ์ ๋๋ก ๋์ง ์์ ์๋ ์์ต๋๋ค.
๊ทธ๋์ redis์ lock์ ์ก๊ณ db์ redis์ transaction ์ฒ๋ฆฌ๋ฅผ ๋ฐ๋ก ํด์ค์ผ ํฉ๋๋ค.
ํก์ฌ ์ ์ ๋ชฉ์๋ฆฌ..
์คํ๋ง์์ ์ ๊ณตํ๋ @Transactional ์ ๋ ธํ ์ด์ ์ ํธ๋์ญ์ ๋ก์ง์ AOP๋ฅผ ํ์ฉํด์ ํ๊ฒ ๋ฉ์๋๋ฅผ ํ๋ก์๋ก ๊ฐ์ผ๋ค.
๊ทธ๋ ๊ฒ ํ๋ฉด ๋น์ฆ๋์ค ๋ก์ง ์ฒ๋ฆฌ๊ฐ ๊น๋ํด์ง๋ ์ด์ ์ด ์๋ค.
๋ด๊ฐ Redisson lock์ ์ด์ฉํ๊ธฐ ์ํด ์ด ๋ํ ๋น์ฆ๋์ค ๋ก์ง์ด ์กฐ๊ธ ์์ฌ ๋ค์ด๊ฐ๋ฏ๋ก, ๋ง์ฐฌ๊ฐ์ง๋ก AOP๋ก ๊ฐ์๋ค.
@Transactional๊ณผ @Redislocked(๋ด๊ฐ ๊ตฌํํ redisson lock ์ ๋ ธํ ์ด์ - AOP ํ์ฉ) ์ ๋์ ์ฌ์ฉ์ผ๋ก ์ธํด AOP๊ฐ ์ ๋๋ก ์์ฐจ์ ์ผ๋ก ๋์ํ์ง ์์ ํธ๋์ญ์ ์ด ์นํ๊ฒ์ด๋ค.
์ ๋ง๋ค.. ์คํ๋ง AOP๋ ํ๋ก์๋ก ๊ฐ์ธ๋ ๋ฐฉ์์ผ๋ก ๋์ํ๋๋ฐ, ๋ด๊ฐ ์ด๊ฑธ ์ ๋์ณค์๊น..
์์๊ฐ ์ค์ํ ๋ฒ์ด๋ค. ์ด๋ฒ ๊ธฐํ์ ๋ค์ ํ๋ฒ ๊ฐ๋ ์ ์ก๊ณ ๊ฐ๋ค.
ํด๊ฒฐ ๋ฐฉ๋ฒ
ํธ๋์ญ์ ๋ก์ง์ ๋ ๋ค๋ฅธ Aspect๋ก ๋ถ๋ฆฌํ๊ธฐ๋ก ๊ฒฐ์ ํ๋ค.
/**
* ํธ๋์ญ์
์ฒ๋ฆฌ aop
*/
@Aspect
@Component
@RequiredArgsConstructor
@Slf4j
@Order(value = 2)
public class TransactionAspect {
private final RedisFunctionProvider redisFunctionProvider;
@Around("@annotation(com.daniel.mychickenbreastshop.global.aspect.annotation.RedisLocked)")
public Object executeWithTransaction(ProceedingJoinPoint joinPoint) {
if (!isTransactional(joinPoint)) {
try {
return joinPoint.proceed();
} catch (Throwable e) {
throw new InternalErrorException(e);
}
}
RTransaction transaction = redisFunctionProvider.startRedisTransacton();
TransactionStatus status = redisFunctionProvider.startDBTransacton();
Object result;
try {
result = joinPoint.proceed();
redisFunctionProvider.commitRedis(transaction);
redisFunctionProvider.commitDB(status);
} catch (Throwable e) {
redisFunctionProvider.rollbackRedis(transaction);
redisFunctionProvider.rollbackDB(status);
throw new InternalErrorException(e);
}
return result;
}
private boolean isTransactional(ProceedingJoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
return method.getAnnotation(RedisLocked.class).transactional();
}
}
ํธ๋์ญ์ ๋ก์ง์ผ๋ก ๊ฐ์ธ๋ AOP ์ถ๊ฐ
@Order๋ก AOP์ ๊ฐ์ธ์ง๋ ์์๋ฅผ ์ง์ ํ์๋ค.
(์ซ์๋ ์๋์ ํฌ๊ธฐ ๋น๊ต, ์ซ์๊ฐ ํด์๋ก ํต์ฌ ๊ด์ฌ ๋ชจ๋์ ๋จผ์ ๊ฐ์ธ์ง)
์คํ
=> ์ด๋ ๊ฒ ๋์ ์์ฒญ ๊ฑด์ ๋ํ Redisson ๋ถ์ฐ๋ฝ์ ์ ํํ๊ฒ ์ ์ฉํ๊ฒ ๋์๋ค. ํธ๋์ญ์ ์ ์ฒ๋ฆฌ๋ ๋ฌด์ฒ์ด๋ ์ค์ํจ์ ๊นจ๋ฌ์๊ณ , AOP๋ฅผ ์ ์ฉํ๋ฉด์ ํ๋ก์ ์๋ฆฌ๋ฅผ ๋ค์ ํ๋ฒ ๊นจ๋ซ๋ ๊ณ๊ธฐ๊ฐ ๋์๋ค.
'๐ Spring Framework > Spring Project' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[์ด์] Pageable test ๊ด๋ จ ์๋ฌ (0) | 2022.11.23 |
---|---|
[Refactor] ํจํค์ง ๊ตฌ์กฐ์ ์์กด์ฑ (2) | 2022.10.14 |
[Redisson]์ ์ด์ฉํ ๋ถ์ฐ Lock ๊ตฌํ & ๋์์ฑ ๋ฌธ์ ํด๊ฒฐ (2) | 2022.09.27 |
๊ฒฐ์ API ๋ฆฌํฉํ ๋ง - [2] (feat. WebClient) (7) | 2022.09.22 |
๊ฒฐ์ API ๋ฆฌํฉํ ๋ง - [1] (feat. ์ ๋ต ํจํด) (2) | 2022.09.20 |