19,800원
다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 미해결재고시스템으로 알아보는 동시성이슈 해결방법
분산 락 질문드립니다.
안녕하세요 강의 잘 들었습니다!완강하고 나서 몇 가지 궁금증이 생겨 질문드립니다.분산 락을 "분산" 락이라고 부르는 이유가 뭔가요?Redis가 인메모리 DB이다보니 서버마다 Redis를 가지고 있어 여러 서버에서 모두 가지고 있어 분산 락이라고 부르는 걸까요?Redis가 여러 서버에 분산되어 있다보니 서로 싱크를 맞추기가 쉽지 않을 것 같은데 이런 부분은 어떻게 해결할 수 있나요?서로 싱크가 맞지 않는다면 synchronized 키워드의 문제점처럼 여러 프로세스에서 접근할 수 있어 정합성이 보장되지 않을 것 같아서요!Redis는 인메모리 DB라 휘발성인데 서버가 다운될 경우 복구는 어떤식으로 이뤄지는지 궁금합니다!
- 해결됨재고시스템으로 알아보는 동시성이슈 해결방법
쓰레드 카운트를 100으로 설정했는데 newFixedThreadPool을 32로 지정한 이유
쓰레드 카운트를 100으로 설정했는데 newFixedThreadPool을 32로 지정한 이유가 궁금합니다.
- 해결됨재고시스템으로 알아보는 동시성이슈 해결방법
Facade 클래스에대 설명이 부족해요 ㅠㅠ
안녕하세요섹션 3. Database 이용해보기 - Optimistic Lock 활용해보기 강좌에 질문이 있습니다.Facade 클래스에서 버전이 달라 업데이트 실패한 경우에 재시도를 한다는건 이해했습니다.그런데 왜 재시도를 퍼사드 클래스를 따로 만들어서 수행하는지 궁금합니다
- 미해결재고시스템으로 알아보는 동시성이슈 해결방법
Access Denied for user ‘root’@’localhost’ (using password: YES)
몇시간동안 삽질해보고 여기 질문글도 뒤져봤는데 답이 없어서 결국 질문 드립니다 😂현재 진행 상황:✔️ 환경 세팅 완료✔️ 재고 감소 테스트 코드 작성전체 애플리케이션을 실행 시키는데, Access Denied for user ‘root’@’localhost’ (using password: YES) 이런 에러가 뜨길래, MySQL 쪽을 계쏙 건드려보았습니다. 그래도 똑같더라고요 ,,제가 시도한 방법들 입니다:https://legend-danger-266.notion.site/Access-Denied-for-user-root-localhost-using-password-YES-e0f3cdec520843ed9767d7fec583b9b1혹시 원하시면 소스 압축해서 보내 드리겠습니다 ,, 🥲 도커 쪽 문제인지 어디인지 모르겠네요 도커 실행시키던 끄던 똑같은 에러가 발생하더라고요
- 해결됨재고시스템으로 알아보는 동시성이슈 해결방법
PESSIMISTIC_WRITE 테스트 시 테스트 클래스 위 @Transactional
@Transactional @SpringBootTest class StockServiceTest { @Autowired private StockService stockService; @Autowired private PessimisticLockService pessimisticLockService; @Autowired private StockRepository stockRepository; @BeforeEach public void before() {안녕하세요 PESSIMISTIC_WRITE 예제처럼 테스트 시에 @Transactional을 붙이면 테스트가 첫 스레드풀 사이즈 만큼의 쿼리만 나가고 계속 대기 중입니다.혹시 원인을 알수 있을까요?
- 해결됨재고시스템으로 알아보는 동시성이슈 해결방법
RedissonLockStockFacade 트랜잭션시 실패 케이스
@Component class RedissonLockStockFacade( private val redissonClient: RedissonClient, private val stockService: StockService ) { @Transactional fun decrease(key: Long, quantity: Long) { val lock = redissonClient.getLock(key.toString()) try { val available = lock.tryLock(10, 1, TimeUnit.SECONDS) if (!available) { println("lock 획득 실패") return } stockService.decrease(key, quantity) } catch (e: Exception) { throw RuntimeException(e) } finally { lock.unlock() } } }RedissonLcokStockFacade 클래스의 decrease 메서드에 트랜잭션을 걸면 동일한 테스트 케이스가 실패하는데 이유를 알 수 있을까요?
- 미해결재고시스템으로 알아보는 동시성이슈 해결방법
redis lock과 mysql lock 성능 질문입니다.
강의를 보면 redis의 redisson과 mysql db lock 중 redisson을 이용한 방식이 더 성능이 좋다고 설명 해주셨는데요.강의의 테스트 코드 수행시간을 보면 mysql의 비관락이 약 2초, redisson을 이용한 방식이 약 5초 정도 걸리는 것을 보아 비관락의 성능이 더 빠른 것처럼 보이는데..이럼에도 불구하고 redisson의 성능이 더 좋다고 하시는 이유가 궁금합니다.
- 미해결재고시스템으로 알아보는 동시성이슈 해결방법
낙관적 락, 비관적 락 말고 항상 분산락을 쓰는게 좋을까요?
공부하다가 의문이 생겼는데요,낙관적 락 - 충돌 잦으면 락 획득 재시도 로직 때문에 성능 안좋음비관적 락 - 충돌 잦으면 낙관적 락보다 성능좋음.분산 락- 스케일 아웃된 DB 환경에서도 사용 가능- Redis 라이브러리마다 다른데 Lettuce는 스핀락으로 구현되서 재시도 많으면 불리 Redisson은 pub-sub 기반이라 재시도 많으면 유리정확하진 않지만 이렇게 알고있습니다.질문은1. 잘못 알고 있나요?2. 제가 공부한게 맞다면, 무조건 비관적 락, 낙관적 락 말고 분산락 + Redis(Lettuce/Redisson) 쓰는게 좋은건가요?
- 미해결재고시스템으로 알아보는 동시성이슈 해결방법
Redis 질문입니다
현재 재고로직 처리하면서 redis를 사용하며다음과 같은 로직으로 구현하려 합니다. 재고는 redis에 넣어둔다.Redis에서 가져올수 없는 경우, rdb에 쿼리한다. 이때, 만약 rdb에서 재고를 가져오는 경우 어떻게 가져올수 있을까요? rdb데이터가 redis와 동기화되어 똑같이 있다면 다시 가져와 redis에 다시 넣어두면 되는데어떻게 동기화시킬수 있나요?? 주문이 끝날때마다 재고 rdb테이블에 insert하거나 update치면 rdb에 가해지는 부하나 재고rdb테이블의 lock으로 인한 성능저하는 redis를 쓰지 않을때와 별반 다르지 않지 않을까요??
- 미해결재고시스템으로 알아보는 동시성이슈 해결방법
안녕하세요 Pessimistic Lock 사용 주의점에 대해 질문이 있습니다 !
안녕하세요 ! 강의 완강하고 문득 든 궁금증이 있어 질문 작성하게 되었습니다. 궁금한 부분은 'Pessimistic Lock 사용 시 스케일 아웃이 어렵다' 라는 부분인데요, 만약 모든 서버가 공유하는 외부 DB 스토리지가 있다고 가정했을 때, 서버 1 에서 1번 row 에 Lock 을 걸었다면 서버 2번에서는 어짜피 같은 DB 를 공유하기 때문에 해당 row 에 접근이 불가한 것이 아닌지 ? 라는 의문이 들었습니다. 제 생각이 어떻게 틀린건지 알려주시면 감사하겠습니다. 좋은 강의 감사합니다 ^^
- 미해결재고시스템으로 알아보는 동시성이슈 해결방법
동시성 이슈 원인에 대해 질문드립니다.
안녕하세요. 강의 잘 듣고 있습니다. 4분 17초부터 동시성 이슈의 원인을 db select, update하는 과정이 순서가 보장되지 않아 생기는 문제라고 설명해주시는데요. 해당 관점에 더해서 "stock을 select하고 와서 quantity 변수를 수정할때도 메모리상에 read,update,write가 이루어질텐데 여기서도 스레드들이 메모리 접근 순서를 보장할수 없기때문에 이와 같은 동시성 이슈가 생긴다" 라는 생각도 맞을까요?답변부탁드립니다.감사합니다.
- 미해결재고시스템으로 알아보는 동시성이슈 해결방법
스프링 부트 2.7.9 native query 에러
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요.혹시 저와 같이 에러가 발생하는 분들이 있을 수도 있을 것 같아서 여기다 글을 적습니다!스프링 부트 2.7.9 버전으로 진행하다 named lock 부분에서 native query를 사용하니 org.springframework.beans.factory.UnsatisfiedDependencyException 이러 에러가 발생하더라구요! 그래서 이런저런 방법을 찾아보다가 혹시나 해서 스프링 부트 2.7.9 를 강의 버전에 맞춰 2.7.0 으로 바꿨더니 해결이 되었습니다.혹시나 저와 같이 오류가 나시는 분들은 참고해주세요!!(근데 오류가 나는 이유까지는 모르겠네요 ㅠㅠ)
- 미해결재고시스템으로 알아보는 동시성이슈 해결방법
lettuce vs reddisson 실무에서 도입 시 고려하는 부분에 대해서 설명할 때 질문있습니다.
lettuce와 같은 경우는 락에 대한 재시도가 필요하지 않아도 사용하고,reddisson는 재시도가 필요한 경우 사용한다고 설명들었습니다.그런데 lettuce는 spinLock 기법으로 lock에 대해서 계속적으로 계속적으로 점유하려고 하는 방식으로 설명들었습니다.재시도가 필요하지 않는 lock이라는게, 제가 이해한 것과는 다른 내용일까요?궁금합니다!
- 해결됨재고시스템으로 알아보는 동시성이슈 해결방법
Spring Boot 3.0.2~ nativeQuery 작성시 에러
안녕하세요 강의듣다가 막혔다 해결한 부분이 있어서 혹여나 동일한 문제를 겪고 있으신 분이 계실까봐 공유드립니다.named lock파트의 native query를 작성하는 부분에서 강의 코드와 동일하게 작성하였음에도 불구하고 스프링 빈을 초기화 하는 과정에서 다음과 같은 에러를 만나게 되었습니다.작성한 코드 @Query("select get_lock(:key, 3000)", nativeQuery = true) fun getLock(key: String) @Query("select release_lock(:key)", nativeQuery = true) fun releaseLock(key: String)발생한 에러Caused by: org.springframework.data.repository.query.QueryCreationException: Could not create query for public abstract void com.waterfogsw.cucurrentsolutions.domain.LockRepository.getLock(java.lang.String); Reason: Cannot invoke "String.contains(java.lang.CharSequence)" because "variable" is null at app//org.springframework.data.repository.query.QueryCreationException.create(QueryCreationException.java:101) at app//org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.lookupQuery(QueryExecutorMethodInterceptor.java:115) at app//org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.mapMethodsToQuery(QueryExecutorMethodInterceptor.java:99) at app//org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.lambda$new$0(QueryExecutorMethodInterceptor.java:88) at java.base@17.0.6/java.util.Optional.map(Optional.java:260) at app//org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.<init>(QueryExecutorMethodInterceptor.java:88) at app//org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:357) at app//org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.lambda$afterPropertiesSet$5(RepositoryFactoryBeanSupport.java:279) at app//org.springframework.data.util.Lazy.getNullable(Lazy.java:245) at app//org.springframework.data.util.Lazy.get(Lazy.java:114) at app//org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:285) at app//org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean.afterPropertiesSet(JpaRepositoryFactoryBean.java:132) at app//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1798) at app//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1748) ... 122 more Caused by: java.lang.NullPointerException: Cannot invoke "String.contains(java.lang.CharSequence)" because "variable" is null at org.springframework.data.jpa.repository.query.QueryUtils.createCountQueryFor(QueryUtils.java:620) at org.springframework.data.jpa.repository.query.DefaultQueryEnhancer.createCountQueryFor(DefaultQueryEnhancer.java:49) at org.springframework.data.jpa.repository.query.StringQuery.deriveCountQuery(StringQuery.java:111) at org.springframework.data.jpa.repository.query.AbstractStringBasedJpaQuery.<init>(AbstractStringBasedJpaQuery.java:82) at org.springframework.data.jpa.repository.query.NativeJpaQuery.<init>(NativeJpaQuery.java:58) at org.springframework.data.jpa.repository.query.JpaQueryFactory.fromMethodWithQueryString(JpaQueryFactory.java:53) at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$DeclaredQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:170) at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateIfNotFoundQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:252) at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$AbstractQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:95) at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.lookupQuery(QueryExecutorMethodInterceptor.java:111) ... 134 more 동일한 강의를 수강중이던 지인분과 함께 비교해본 결과 스프링 부트 버전 문제임을 확인하였습니다.지인분은 data jpa 3.0.1 버전을 사용중이셨고, 저는 data jpa 3.0.3버전을 사용하였는데 3.0.2 이상 버전에서 nativeQuery=true 사용시 NullPointerException이 발생하는 이슈가 있음을 알려드립니다.저는 부트버전을 3.0.1로 다운그레이드하여 정상적으로 실습 진행할 수 있었습니다 :)https://github.com/spring-projects/spring-data-jpa/issues/2812
- 미해결재고시스템으로 알아보는 동시성이슈 해결방법
PessimisticLock 질문
강력한 데이터 정합성을 보장한다는 Pessimistic Lock이 데이터 자체에 Lock을 거는 방식이라고 한다면 여기서 적용되는 락 기능의 범위가 조회를 통해 얻은 Stock 엔티티 자체를 말하는 건가요 아니면 Stock 테이블 내 모든 값들을 접근하는데 있어 lock이 필요하다는 건가요~~?
- 미해결재고시스템으로 알아보는 동시성이슈 해결방법
추가로 동시성 해결하는 방법
이번 강의에서 나온 방법말고도 자바에서 동시성을 해결하는 방법 중에 쓰레드 로컬을 사용하는 방법도 있는 것으로 압니다. 근데 이번 재고감소 로직에서 적용해보려고 하니까 코드작성이 잘 안되더라구요. 이번 강의예제에서와 같이 계속 변수값이 변하는 상황에서는 쓰레드 로컬을 적용하기 어려운건가요?
- 미해결재고시스템으로 알아보는 동시성이슈 해결방법
Transactional 주석 처리에 대한 질문과, 강의 도중 여러 질문
안녕하세요, 강의 잘 듣고 있습니다. 지금까지 발생한 질문들에 대해서 문의드리려 합니다. Transactional 을 주석처리해도 해당 StockService 와 Repository 인터페이스가 잘 동작하는 모습을 확인할 수 있습니다. (듣다가도 당연히 오류날줄 알았습니다)Data Jpa 를 활요하지 않고 일반적인 Jpa Repository 를 직접 만들어서 (em을 사용하는) 시도를 해봤는데 Transactional 이 없으니 예상했던 오류가 그대로 발생하는 것 같았습니다. JpaRepository 인터페이스에 들어가보니, @NoRepositoryBean 이라는 어노테이션만이 붙어 있고, 그냥 다른 Repo를 만들지 못하도록 달아져 있는 것이라는 것을 확인하였습니다. 작동하는 이유가 Data Jpa 가 제공해주는 Repository interface 를 사용해서 인 것 같은데, 어떤 원리로 작동이 가능한건지 알 수 있을까요? Synchronize 를 사용해도 우선 동작을 하는 이유는 @Transactional 의 동작 방식 때문이라고 설명해주시며, 예시 클래스를 짜서 보여주셨습니다. public void decrease(){ startTransaction(); myStockService.decrease(); endTransaction(); }트랜젝션이란 DB와의 통신을 위해 연결을 짓는 행위로 알고 있는데, DB는 공유 자원인 만큼 당연히 동시성 제어가 되어 있어야 하는 것이 아닌가 생각이 들었습니다. 가령, 위에서 startTx, endTx 를 하는 부분에서 세마포어 처리 등을 해서 교착상태가 발생하지 않도록 설계가 되어 있어야 하지 않나 싶은 생각이 들었는데, @Transactional 에서 그런 것을 처리 하지 않아서 이와 같은 상황이 발생하는게 맞을까요? (강사님한테 문의드리는게 좀 이상한 부분일 수도 있지만, 왜 그런 처리를 안해놨을지 궁금.. 합니다) 감사합니다.
- 해결됨재고시스템으로 알아보는 동시성이슈 해결방법
stockservice 함수의 saveandflush 질문이 있습니다
stockservice 클래스의 decrease의 saveandflush를 synchronized를 위해 사용한 것은 이해가 갔습니다.근데 jpa를 사용할 때 값을 update할 때 더티체킹에 의해서 update가 확인이 되어 repository를 통해 save를 하지 않아도 되는걸로 알고 있는데 실무에선 save나 saveandflush를 사용하지 않고 decrease 메서드만 사용해도 될까요?
- 미해결재고시스템으로 알아보는 동시성이슈 해결방법
Facade를 controller 에서의 사용
안녕하세요 동시성 관련된 수업을 너무 잘 들었습니다. 위와 같이 만들어진 facade의 decrease 메서드를 controller에서 바로 사용하면 동시성 문제가 해결되는걸까요?
- 미해결재고시스템으로 알아보는 동시성이슈 해결방법
redisson 질문입니다.
public void decreaseStock(Long key, Long quantity){ RLock lock = redissonClient.getLock(key.toString()); try{ boolean available = lock.tryLock(60, 1, TimeUnit.SECONDS); if(!available){ System.out.println("lock 획득 실패"); return; } stockService.decreaseStock(key, quantity); }catch (InterruptedException e){ throw new RuntimeException(e); }finally { lock.unlock(); } }안녕하세요 redisson 활용에 질문있어서 드립니다.tryLock()부분의 waitTime 부분이 강의에서는 5로 설정하셨는데, 제가 강사님과 동일하게 5로 설정하면 테스트가 실패했습니다. expected: <0> but was: <41>이와 같이 실패가 떠서 timewait값을 조금씩 늘려주면서 테스트하니까 60에서는 안정적으로 성공하는걸 확인했습니다. 이부분에 대해서 질문이있는데, timewait값에 따라 성공,실패가 달라지는건 서버 환경에 따라 달라지는걸로 보면 되는걸까요?