묻고 답해요
160만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결파이썬 동시성 프로그래밍 : 데이터 수집부터 웹 개발까지 (feat. FastAPI, async, await)
6-4 03:57~ hhh 질문입니다!
페이지의 Item ID: hhh에서 hhh는 어떤 파일의 어느 부분에서 입력되는건지 궁금합니다!
-
미해결재고시스템으로 알아보는 동시성이슈 해결방법
수행 시간 비교 관련 질문
안녕하세요 좋은 강의 해주셔서 감사합니다.강의를 전부 듣고 각 방식의 성능이 궁금하여 이를 찍어보았는데 조금 의아한 결과가 나와서 질문 드립니다.동시성 처리 안한 버전 256 mssynchronized 버전 962 ms비관적락 468 ms낙관적락 1441 msNamedLock 807 msLettuceLock 4184 msRedissonLock 1137 ms 몇번씩 테스트해본 결과 대략 위와 같은 정도의 성능이 나옵니다. 처음 생각하기로는 Redis 사용 방식이 비교적 빠를것이고, DB에 락을 거는 방식이 Redis에 비해 느리지 않을까 했는데 오히려 반대로 DB에 락을 거는게 빠르고 Redis를 사용하는 방식이 느린것을 확인할 수 있었습니다. 혹시 이러한 결과가 나오게 된 이유를 여쭤볼 수 있을까요? 감사합니다.
-
해결됨재고시스템으로 알아보는 동시성이슈 해결방법
프록시 객체가 생성될 때 synchronized 없이 메서드가 생성되는 것이 맞을까요?
먼저 좋은 강의 감사드립니다. 프록시 객체에서 이해가 안 가는 부분이 있어 질문드립니다.@Transactional을 사용하면 프록시 방식의 AOP로 동작하는 것은 이해하고 있습니다. 스프링 부트는 CGLIB 방식으로 프록시 객체를 생성하므로, StockService를 상속하는 StockServiceProxy가 만들어질 때 StockServiceProxy.decrease()에도 synchronized 키워드가 붙어있을 것이라고 생각했습니다. 그런데 강사님께서 TransactionStockService 를 예로 드실 때 synchronized 를 안 붙이신 걸 보니 프록시 객체가 생성될 때는 synchronized 가 안 붙는 건가? 라고 생각들었습니다.Q. 프록시 객체가 생성될 때 synchronized 없이 메서드가 생성되는 것이 맞을까요?읽어주셔서 감사합니다 :)
-
미해결재고시스템으로 알아보는 동시성이슈 해결방법
재고 데이터를 Redis에서 관리했을 때 분산락의 필요성
현재 강의에서 재고 데이터를 MySQL에서 관리하고 있는데, 만약에 다중 서버 환경이라고 가정하고, 재고 데이터를 Redis에서 관리한다했을 때에도 분산락이 필요한건가요? 제가 redisson을 이용해서 재고 감소 시키는 로직과 redisson을 이용하지 않고 재고 감소 시키는 로직을 구현했는데, 제가 예상한 바로는 redisson을 이용하지 않고 재고 감소 시킬 때에는 데이터 정합성이 맞지 않고, redisson을 이용해서 재고 감소시키는 로직에선느 데이터 정합성이 맞을 것이다라고 생각했는데, 결과는 둘다 동일하게 데이터 정합성이 맞더라구요. 왜 그런걸까요? 1번째 코드는 구현코드고, 2번째 코드는 테스트 코드입니다. @Repository public class InventoryRepository { private final RedisStringsRepository redisStringsRepository; private final RedissonClient redissonClient; private int waitTimeForAcquiringLock = 1; private int leaseTimeForLock = 1; @Autowired public InventoryCommandRepository( RedisStringsRepository redisStringsRepository, RedissonClient redissonClient ) { this.redisStringsRepository = redisStringsRepository; this.redissonClient = redissonClient; } public void set(String key, int amount) { redisStringsRepository.set(key, String.valueOf(amount)); } public void delete(String key) { redisStringsRepository.delete(key); } // lock 없이 재고 로직 감소 public void decreaseByAmountWithoutLock(String key, int amount) { redisStringsRepository.decreaseByAmount(key, Long.valueOf(amount)); } // lock 하고 재고 로직 감소 public void decreaseByAmount(String key, int amount) { RLock rlock = redissonClient.getLock(key+"lock"); try { boolean available = rlock.tryLock(waitTimeForAcquiringLock, leaseTimeForLock, TimeUnit.SECONDS); if (!available) { System.out.println("lock 획득 실패 "); return; } redisStringsRepository.decreaseByAmount(key, Long.valueOf(amount)); } catch (InterruptedException e) { throw new RuntimeException(e); if (rlock != null && rlock.isLocked()) { rlock.unlock(); } } } } @DisplayName("InventoryRepository") @SpringBootTest public class InventoryRepositoryTest { @Autowired private InventoryRepository inventoryRepository; @Autowired private RedisStringsRepository redisStringsRepository; @Autowired private RedisTemplate<String, String> redisTemplate; String key = "testKey"; int initialAmount = 100; @BeforeEach public void setUp() { redisStringsRepository.set(key, String.valueOf(initialAmount)); } @AfterEach void teardown() { redisStringsRepository.delete(key); } @Nested @DisplayName("decreaseByAmountWithoutLock") class Describe_decreaseByAmountWithoutLock { @Nested @DisplayName("with 1 thread") class Context_With_Single_Thread { @Test @DisplayName("decreases inventory by amount") void It_Decreases_Inventory_By_Amount() throws InterruptedException { int decreaseAmount = 1; inventoryRepository.decreaseByAmountWithoutLock(key, decreaseAmount); String value = redisStringsRepository.get(key); int expectedAmount = initialAmount - decreaseAmount; assertEquals(expectedAmount, Integer.valueOf(value)); } } @Nested @DisplayName("with multi thread") class Context_With_Multi_Thread { @Test @DisplayName("does not decrease inventory by amount") void It_Does_Not_Decrease_Inventory_By_Amount() throws InterruptedException { int threadCount = 100; int decreaseAmount = 1; ExecutorService executorService = Executors.newFixedThreadPool(32); CountDownLatch latch = new CountDownLatch(threadCount); for (int i = 0; i < threadCount; i++) { executorService.submit(() -> { try { // Perform the test inventoryRepository.decreaseByAmountWithoutLock(key, decreaseAmount); } catch (Exception e) { System.out.println(e.getMessage()); } finally { latch.countDown(); } }); } latch.await(); String value = redisStringsRepository.get(key); assertNotEquals(0, Integer.valueOf(value)); // 테스트 통과 안함. } } } @Nested @DisplayName("decreaseByAmount") class Describe_decreaseByAmount { @Nested @DisplayName("with 1 thread") class Context_With_Single_Thread { @Test @DisplayName("decreases inventory by amount") void It_Decreases_Inventory_By_Amount() throws InterruptedException { int decreaseAmount = 1; inventoryRepository.decreaseByAmount(key, decreaseAmount); String value = redisStringsRepository.get(key); int expectedAmount = initialAmount - decreaseAmount; assertEquals(expectedAmount, Integer.valueOf(value)); } } @Nested @DisplayName("with multi thread") class Context_With_Multi_Thread { @Test @DisplayName("decrease inventory by amount") void It_Does_Not_Decrease_Inventory_By_Amount() throws InterruptedException { int threadCount = 100; int decreaseAmount = 1; ExecutorService executorService = Executors.newFixedThreadPool(32); CountDownLatch latch = new CountDownLatch(threadCount); for (int i = 0; i < threadCount; i++) { executorService.submit(() -> { try { // Perform the test inventoryRepository.decreaseByAmount(key, decreaseAmount); } catch (Exception e) { System.out.println(e.getMessage()); } finally { latch.countDown(); // Latch의 숫자가 1개씩 감소 } }); } latch.await(); // Latch의 숫자가 0이 될 때까지 기다리는 코드 String value = redisStringsRepository.get(key); assertEquals(0, Integer.valueOf(value)); } } } }
-
미해결파이썬 동시성 프로그래밍 : 데이터 수집부터 웹 개발까지 (feat. FastAPI, async, await)
await asyncio.gather 메소드 안에서 마지막 delivery 함수 이후에 , 를 추가하는 이유가 뭘까요?
결과 값은 같아 보이는데 아래 이미지에서 마지막에 ,를 추가한 이유가 있을까요?
-
미해결운영체제 공룡책 강의
1.운영체제가 뭐길래 7분 58초 질문이요
1.운영체제가 뭐길래 에서 7분58초에 1Mb를 2의 1024승이라고 말씀하셨는데, 찾아보니 1Kb가 2의 1024승 이던데요... 제가 잘못찾은걸까요?
-
미해결파이썬 동시성 프로그래밍 : 데이터 수집부터 웹 개발까지 (feat. FastAPI, async, await)
코루틴 활용 런타임에러
안녕하세요 코루틴 활용 파트에서코드를 실행해보니raise RuntimeError('Event loop is closed')RuntimeError: Event loop is closed라고 문구가 뜨네요..aiohttp 3.7.3 버전 인스톨하는데 3.7.4.post0으로 다운이 되었구요. 해결책 좀 알려주시면 감사하겠습니다.
-
미해결파이썬 동시성 프로그래밍 : 데이터 수집부터 웹 개발까지 (feat. FastAPI, async, await)
언패킹 관련 질문입니다.
안녕하세요.04-2-coroutine-fetcher.py에서 fetcher 함수에서 url을 언패킹하실 때 *를 사용하셨는데 아래 코드에서 가 어떻게 작동하는건지 알 수 있을까요?result = await asyncio.gather(*[fetcher(session, url) for url in urls])
-
해결됨재고시스템으로 알아보는 동시성이슈 해결방법
다양한 방법 알아보기 문서내용 다름
다양한 방법 알아보기 의 문서내용이 화면에서 나오는 내용과 다르네요. 확인 부탁드립니다.
-
미해결앨런 iOS 앱 개발 (15개의 앱을 만들면서 근본원리부터 배우는 UIKit) - MVVM까지
섹션 15 동기와 비동기의 개념 질문있습니다
강의를 듣던 도중 동기 , 비동기, 직렬, 동시 에 개념에 대해서 질문이 생겼습니다.직렬의 경우 그림으로 표현해 주셨던 것처럼다른 하나의 쓰레드에서 task를 순서에 따라 전부 다 처리한다고 이해했는데,제가 이해한 것이 맞다면, 동기 방식으로 직렬 테스크를 처리했을 때 굳이 다른쓰레드로 테스크를 넘기는 것이 의미가 있나요? 비동기라면 해당 테스크를 직렬로 처리하더라도 동시에 다른 테스크를 진행할 수 있다고 생각하지만 동기처리의 경우 결국 메인쓰레드에서 진행하는 것과 같은 수준의 처리시간이 들고 오히려 쓰레드를 바꾸는데에 대한 리소스만 더 사용하게 되는것은 아닌가요??라는 의문이 들었습니다..!
-
미해결재고시스템으로 알아보는 동시성이슈 해결방법
Redisson import
안녕하세요.Build.gradle에 Redisson을 import하는 과정에서 궁금증이 생겨서 질문합니다.처음에 Redisson을 검색해서 import를 했는데 Facade에서 생성자를 만들때 빨간줄이 뜨고, test를 돌려보니 에러가 나더라구요.importimplementation group: 'org.redisson', name: 'redisson', version: '3.2.0'import한 페이지https://mvnrepository.com/artifact/org.redisson/redisson/3.2.0생성자 경고 test errorjava.lang.IllegalStateException: Failed to load ApplicationContext for [WebMergedContextConfiguration@3f908a10 testClass = com.example.stock.facade.RedissonLockFacadeTest, locations = [], classes = [com.example.stock.StockApplication], contextInitializerClasses = [], activeProfiles = [], propertySourceLocations = [], propertySourceProperties = ["org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true"], contextCustomizers = [org.springframework.boot.test.autoconfigure.actuate.observability.ObservabilityContextCustomizerFactory$DisableObservabilityContextCustomizer@9da1, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@16a0ee18, org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@bd4dc25, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@71def8f8, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@1da2cb77, org.springframework.boot.test.context.SpringBootTestAnnotation@818c3651], resourceBasePath = "src/main/webapp", contextLoader = org.springframework.boot.test.context.SpringBootContextLoader, parent = null] at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:142) at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:127) at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:191) at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:130) at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:241) at org.springframework.test.context.junit.jupiter.SpringExtension.postProcessTestInstance(SpringExtension.java:138) at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$10(ClassBasedTestDescriptor.java:377) at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.executeAndMaskThrowable(ClassBasedTestDescriptor.java:382) at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$11(ClassBasedTestDescriptor.java:377) at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625) at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) at java.base/java.util.stream.StreamSpliterators$WrappingSpliterator.forEachRemaining(StreamSpliterators.java:310) at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:735) at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:734) at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:762) at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeTestInstancePostProcessors(ClassBasedTestDescriptor.java:376) at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$instantiateAndPostProcessTestInstance$6(ClassBasedTestDescriptor.java:289) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateAndPostProcessTestInstance(ClassBasedTestDescriptor.java:288) at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$4(ClassBasedTestDescriptor.java:278) at java.base/java.util.Optional.orElseGet(Optional.java:364) at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$5(ClassBasedTestDescriptor.java:277) at org.junit.jupiter.engine.execution.TestInstancesProvider.getTestInstances(TestInstancesProvider.java:31) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$prepare$0(TestMethodTestDescriptor.java:105) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:104) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:68) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$prepare$2(NodeTestTask.java:123) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.prepare(NodeTestTask.java:123) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:90) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:147) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:127) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:90) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:55) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:102) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:54) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86) at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86) at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53) at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71) at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38) at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11) at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35) at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235) at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54) Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'redissonLockFacade' defined in file [/Users/jialee/inflearn/stock/out/production/classes/com/example/stock/facade/RedissonLockFacade.class]: Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type 'org.redisson.api.RedissonClient' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {} at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:798) 그래서 다시 검색해서 import 하니 생성자쪽에서 빨간줄은 뜨지 않지만, 테스트를 돌리면 동일한 에러가 나더라구요.importimplementation 'org.redisson:redisson-spring-boot-starter:3.17.4'혹시 두 inport의 차이점은 무엇이며, 왜 계속 테스트가 실패하는건지도 문의드립니다. + 추가로 git 주소도 남깁니다.https://github.com/uiop9900/stock.git
-
미해결재고시스템으로 알아보는 동시성이슈 해결방법
섹션 3에서의 모든 테스트 케이스가 동작하지 않는데 문제점을 모르겠습니다.
안녕하세요.섹션 3의 세 가지 락들을 따라하면서 코드를 작성했습니다.그런데 세 가지 모두 테스트 케이스가 동작하지 않습니다.PessimisticLock과 NamedLock 경우 재고가 감소하지 않습니다.. OptimisticLock의 경우는에서 동작하지 않습니다.사용한 자바 버전은 17입니다.소스코드 주소는https://github.com/torissi/synchronism-issue입니다.
-
미해결운영체제 공룡책 강의
데드락 관련 질문입니다.
해당 강의에서 이게 데드락이 아니라고 설명해주셨는데, 이 경우는 데드락이 맞지 않나요?
-
미해결재고시스템으로 알아보는 동시성이슈 해결방법
Redis 를 이용한 분산 락 구현의 성능 관련 질문
[상황 예시]한정판 상품 A의 재고 수량 : 2000개 (1인당 1개씩만 구매 가능)[구매 로직]1. 데이터 베이스에서 상품 A를 조회2. A의 재고 수량 확인3. 재고 수량이 0보다 큰 경우 재고를 1 감소시키고 구매 완료 처리[테스트]2000개 스레드 생성해서 동시에 구매 요청 후 잔여 재고 확인테스트 코드에서 2000개의 스레드가 동작하기 전 System.nanoTime() 과 모두 동작이 끝난 후 System.nanoTime() 을 통해 처리 시간을 계산하여 비교해보고 있습니다.테스트 환경 - h2 database 위와 같은 방식으로 현재 프로젝트를 구현 중에 있습니다. 한정판 상품 구매의 특성 상 충돌이 잦을 것이라고 생각해서 다음과 같은 후보군으로 실험을 하고 있습니다.1. 비관적 락2. Lettuce 를 이용한 분산락3. Redisson 을 이용한 분산락제가 알아본 바나 다른 사례들을 봤을 때 Redis를 거친다고 해서 DB에서 제공해주는 락 기능을 사용하는 것과 속도면에서 차이가 거의 없는 것으로 알고 있었는데 실제 실험 결과가 다음과 같습니다.1. 비관적 락 - 평균 6초2. Lettuce - 평균 34초3. Redisson - 평균 12초Redis를 이용한 분산락 구현 코드는 강사님의 강의를 따라했는데 혹시 이런 결과가 나오는 이유가 무엇일까요?제 추측으로는 Lettuce 를 이용하는 방식에서는 2000개의 스레드가 반복적으로 락 획득 요청을 보냄에 따라 Redis에 부하가 심해서 속도가 느려질 수 있을 것 같은데 Redisson 을 이용한 방식은 왜 느린지 전혀 모르겠습니다.
-
미해결재고시스템으로 알아보는 동시성이슈 해결방법
낙관 락 vs 비관 락 실무에서 구체적인 예시를 들어주실 수 있을까요?
낙관 락과 비관 락을 정확히 언제 사용하는지 궁금한데요, 충돌이 잦을 때는 비관 락을 사용한다고 이해하기엔 막연한 느낌이 있어서요, 혹시 실무에서 구체적인 예시를 들어주실 수 있을까요??비관적 락이 구현이 훨씬 간단할 것 같은데, 실제로 실무에서 비관적 락이 아닌 낙관적 락을 직접 구현해서 사용할 일이 있는지도 궁금합니다.충돌이 빈번하게 일어난다면 비관적 락이 더 적합할 수 있다고 하셨는데 이유가 뭔가요? 어떤 부분에서 성능상 이점이 있는지 궁금합니다. 자세하게 설명해주시면 정말 감사할 것 같습니다. 감사합니다!!
-
미해결재고시스템으로 알아보는 동시성이슈 해결방법
synchronized 와 @Transactional
안녕하세요 재고관리시스템 강의를 복습하며 내용을 정리하는 중 의문이 생겨 질문을 드립니다. 가장 처음에 application code 레벨에서만 동시성을 해결하기 위해 syncrhonized 를 사용할 경우 해당 메서드에는 @Transactional 을 붙여서는 안된다고 설명해 주셨습니다. 실제로 이를 붙일 경우, 동시에 decrease 메서드가 호출되고 해당 로직 내부로 들어가는 것이 가능함을 확인하였습니다. 그런데 여기서 제가 의문이 들었던 것이 있습니다. @Transacitonal 을 사용할 경우 Spring AOP 에 의해 매 번 다른 proxy 인스턴스를 통해 target object 로의 호출을 하게 됩니다. proxy 객체에 대한 lock 은 서로 다른 프록시들 사이에 공유되지 않는다고 하더라도, 내부적으로 호출되는 target 객체에 대한 decrease 메서드는 결국 동일한 객체에 대한 호출을 하기 때문에, 공유되는 lock 에 대한 경쟁이 일어나는 것이 아닌가 생각이 들었습니다. 최종적으로는 target 객체에 대한 synchronized 메서드를 호출하는 것이라면, 단 하나의 스레드만 임계 영역에 들어갈 수 있어야 할 것 같은데, 그렇지 않음을 확인하였습니다. 왜 이런 일이 일어나는 것인지 이해가 잘 되지 않습니다 ㅠㅠ 이와 관련해서 어떤 키워드로 공부해보면 좋을지 추천 가능할까요..?
-
미해결재고시스템으로 알아보는 동시성이슈 해결방법
분산 락 질문드립니다.
안녕하세요 강의 잘 들었습니다!완강하고 나서 몇 가지 궁금증이 생겨 질문드립니다.분산 락을 "분산" 락이라고 부르는 이유가 뭔가요?Redis가 인메모리 DB이다보니 서버마다 Redis를 가지고 있어 여러 서버에서 모두 가지고 있어 분산 락이라고 부르는 걸까요?Redis가 여러 서버에 분산되어 있다보니 서로 싱크를 맞추기가 쉽지 않을 것 같은데 이런 부분은 어떻게 해결할 수 있나요?서로 싱크가 맞지 않는다면 synchronized 키워드의 문제점처럼 여러 프로세스에서 접근할 수 있어 정합성이 보장되지 않을 것 같아서요!Redis는 인메모리 DB라 휘발성인데 서버가 다운될 경우 복구는 어떤식으로 이뤄지는지 궁금합니다!
-
해결됨재고시스템으로 알아보는 동시성이슈 해결방법
쓰레드 카운트를 100으로 설정했는데 newFixedThreadPool을 32로 지정한 이유
쓰레드 카운트를 100으로 설정했는데 newFixedThreadPool을 32로 지정한 이유가 궁금합니다.
-
해결됨파이썬 동시성 프로그래밍 : 데이터 수집부터 웹 개발까지 (feat. FastAPI, async, await)
cpu 연산
안녕하세요. cpu 연산 관련해서 질문드립니다. 동시성과 병렬성 각각 cpu연산이 어떤식으로 나누어서 진행되는 것일까요? 연산이 아닌 네트워크인 경우에는 각 작업별인 것을 이해했는데, 연산일 경우 예시를 들어서 설명해주시면 감사하겠습니다. 그리고 이제 파이썬 웹 개발을 막 완료한 초급 개발자인데, 내용이 너무 어려워서..이해가 잘 안되는데 반복하면 될까요? ㅜㅜ추가적인 공부방법도 알려주시길 부탁드립니다.
-
해결됨파이썬 동시성 프로그래밍 : 데이터 수집부터 웹 개발까지 (feat. FastAPI, async, await)
보너스 강의
보너스 강의는 어디서 볼 수 있나요?