안녕하세요 강사님! 2-6강(18번째 강의) 관련 질문입니다. 3분 20초쯤에 파킹 페이지와 대기열 큐를 앞에 두어 유입되는 사용자를 줄인다고 말씀하셨는데, 이 부분에 대해 궁금한 점이 있습니다. 1. 어떻게 구현하셨나요? 직접 만드셨는지, 기성 솔루션을 쓰셨는지도 궁금합니다. 2. 대기열은 어디에 있나요? 레이트 리미터처럼 WAS 앞단(게이트웨이나 별도 서버)에 있는지, WAS 안에서 필터 같은 형태로 처리하는지 궁금합니다. 3. 앞서 입장한 사용자가 나가야 다음 사람이 들어가는 구조라면, 사용자가 나간 것(결제 완료나 창 닫기 등)은 어떻게 감지하셨나요? 아니면 동시 접속 인원과 상관없이 초당 몇 명씩 입장시키는 방식이었나요? 감사합니다!
457 장표의 사진이 이해가 잘 안갑니다. 우선 트랜잭션을 열고 트랜잭션1에서 update를 하는 순간 lock 을 획득, 그 후 실제 version을 하나 올린 후 동일 트랜잭션이 commit하기 전까지 락을 잡고 있는걸로 알고 있습니다. 근데 이미지 순서로 따지자면 트랜잭션 2에서 트랜잭션1의 commit 전단계에서 update를 수행하게 되는데 이러면 격리수준에 따라 달라지겠지만 READ COMMITTED에서는 여전히 version=1로 존재하기때문에 정상적으로 update 처리 되는거 아닌가요? 실제로는 트랜잭션 1에서 lock을 계속 가지고 있어서 트랜잭션 2에서 update에 진입도 못하겠지만 이미지가 잘 이해가 안되네요 특히 왜 갱신실패응답으로 떨어지는지도 이해가 안갑니다.
무한 depth 댓글의 path 생성 방식에 대해 궁금한 점이 있습니다. 강의에서는 각 depth마다 00000 , 00001 같은 별도의 순차값을 부여해서 예를 들면 댓글1 → 00000 댓글2 → 00000 00000 댓글6 → 00000 00000 00000 댓글4 → 00000 00001 처럼 path를 구성하는 것으로 이해했습니다. 그런데 기존의 comment_id 가 이미 댓글 생성 순서를 보장한다면, 굳이 각 depth마다 새로운 순차값을 다시 부여하지 않고 comment_id 를 고정 길이 문자열로 변환해서 댓글1(id=1) → 00001 댓글2(id=2) → 00001 00002 댓글6(id=6) → 00001 00002 00006 댓글4(id=4) → 00001 00004 처럼 path를 만들어도 ORDER BY path ASC 시 동일하게 트리 순서가 보장될 것 같은데, 강의에서 별도의 순차값을 사용하는 이유가 있을까요?
안녕하세요 강의 잘 듣고있습니다. Service쪽 코드에 movablePageCount는 10L로 상수를 넣고 pageSize는 변수로 넣었는데 서비스적으로 볼때는 이 2개 전부 상수로 봐야하는거 아닌가 해서 질문 남깁니다. 페이지 하나당 몇개의 게시글을 보여줄 것인지, 현재 한 묶음당 몇개의 페이지씩 노출시킬건지는 모두 기획 단계에서 정해지므로 상수값으로 생각되어지는데 둘다 상수 혹은 둘 다 변수로 두지 않고 movablePageCount는 상수로 , pageSize는 변수로 파라미터에게 넘겨주는 이유가 궁금합니다
안녕하세요 강의 잘 듣고 있습니다. 취준생이라 실무 경험이 없어 좀 붕뜬 질문 인점 양해 부탁드립니다. 우선 쿼리를 통해 최적화 해야된다면 JPA에서 자동으로 만들어주는 쿼리는 최적화가 안되어있기에 이런식으로 네이티브 쿼리를 날리는거 자체는 이해했습니다. 하지만 결국 이렇게 JPA 안에서 네이티브 쿼리를 날리면 단순 mybatis 쓰는거랑 뭐가 다른가 하는 의문이 들더라구요. 이럴때는 이런 최적화 부분 말고 이외의 부분은 충분히 JPA에서 만들어주는 기본 쿼리로 가능하기때문에 부분적으로만 최적화된 네이티브 쿼리를 직접 날림으로서 보일러플레이트를 대신할 수 있다 뭐 이런식으로 이해하면 될까요?
docker실행하여 mySql 컨테이너 생성까지 성공했습니다. 하지만 마지막 부분의 어플리케이션 실행 부분에서 에러가 나오고 있습니다. org.hibernate.exception.AuthException: Unable to obtain isolated JDBC connection [Access denied for user 'coupon'@'localhost' (using password: YES)] [n/a] Caused by: java.sql.SQLException: Access denied for user 'coupon'@'localhost' (using password: YES) org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/hibernate/autoconfigure/HibernateJpaConfiguration.class]: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment] due to: Unable to determine Dialect without JDBC metadata (please set 'jakarta.persistence.jdbc.url' for common cases or 'hibernate.dialect' when a custom Dialect implementation must be provided) Caused by: org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment] due to: Unable to determine Dialect without JDBC metadata (please set 'jakarta.persistence.jdbc.url' for common cases or 'hibernate.dialect' when a custom Dialect implementation must be provided) Caused by: org.hibernate.HibernateException: Unable to determine Dialect without JDBC metadata (please set 'jakarta.persistence.jdbc.url' for common cases or 'hibernate.dialect' when a custom Dialect implementation must be provided) 어떻게 대응해야 할까요?
안녕하세요. 강사님, 강의 잘 보고 있습니다. 강의를 보면서 궁금증이 생겨서 질문 남겨봅니다! 강의를 진행하시는 방식이 제공해 주신 스켈레톤 코드 베이스로 설명을 하시다가 구현되어 있는 것을 가져다가 붙여넣기 하시는 방식 같은데요! 이럴 때 수강생들의 입장에서는 강사님의 구현을 손으로 구현해 보는 게 좋을까요? 아니면 AI로 구현을 진행해서 강사님의 구현과 비교해 보는 게 좋을까요? 수강생들이 어떻게 강의를 들었으면 좋겠다는 생각을 하시는지 궁금합니다.
선생님이 설명해주신 코드를 의사코드로 짜봤는데.. search(keyword){ db <- `UPSERT list SET count = count+1 WHERE keyword={keyword}` } getTop10(){ return db <- `SELECT * FROM list ORDER BY DESC LIMIT 10` } 대충 이렇게 되면 DB 속도때문에 느리니까 search(keyword){ redis <- `ZINCREBY ranking_list 1 {keyword}` } getTop100(){ redis <- `ZRANGE ranking_list 0 9 REV` } 이렇게 처리하자는 느낌인거 같아서요! 우려스러운건 그럼 DB에는 어떻게 언제 저장해야하나요?
LPUSH + LTRIM을 통해 최근 N개 데이터 표현을 한다 하셨는데. [101, 102, 103, 104, 105] 가 있을 때 LPUSH 103 후 LTRIM 0 4 를 한다 가정하면 [103, 101, 102, 103, 104] 이 되는거 같은데 이 경우 N개가 아니라 중복이 생겨서 실무에선 push전 값이 들어올때 마다 LREM으로 해당 값을 지우고 push를 하는건지 아니면 다른 방식이 있는지 궁금합니다.
안녕하세요 이번 강의에서 @Modifying 이라는 어노테이션을 사용하고 있는데 이 @Modifying을 사용하는 상황이 발생하면 영속성 컨텍스트에 있는 데이터와 차이가 발생하게 되는 것을 알게 되었습니다. 이를 해결하기 위해 clearAutomatically = true, flushAutomatically = true 이런 옵션들이 있는 것으로 알고있는데, 현업에서는 이러한 옵션들을 어떻게 사용하는지 궁금합니다. Modifying을 쓰면 영속성 컨텍스트와 차이가 발생한다는 것을 인지하기 때문에 저런 옵션들을 따로 설정을 안하는지, 아니면 저런 옵션들을 사용하는지 궁금합니다!
안녕하세요. 강의를 들으며 issuance 테이블에 status, coupon_id로 각각 인덱스를 생성하시면서 조회성능을 향상시키기 위함이라 설명하셨는데요. 특히 status를 이용한 인덱스가 꼭 필요한지 궁금합니다. 현재 status는 3가지 타입으로 (추후에도 늘어날 value가 제한적) 선택도가 약 33% 정도로 보입니다. 이렇게 가짓수가 적은 경우에는 인덱스의 효율을 잘 활용하기 어려워 인덱스를 생성하는 것이 비효율적이라고 학습한적이 있는데 지금과는 다른 상황인가요??
강의에서는 부하 테스트 시 시나리오 작성을 아래와 같이 5000 rps 정도로 부하를 가했을 때와, 1000 rps 수정해서 부하를 가했을 때의 latency(p50, 90, 99) 차이가 있는데, 실무에서는 보통 어떤 기준을 가지고 rps 를 정하는지 궁금합니다! scenarios: { burst: { ... rate: 5000, timeUnit: '1s', duration: '30s', // 1000 req/s × 30s = 총 30,000 요청 }, },
강의 내용에 보면 클라이언트 수만큼 pub/sub 연결을 하면 안된다. redis 구독을 소수의 연결로 유지하고 클라이언트들에게 브로드캐스트 하는 구조로 사용한다. 애플리케션 시작 시 생성하고 서버 종료될 때 구독을 해제한다. 이렇게 설명을 주시는데 이해가 잘 되지 않아 질문을 드립니다. 1번 2번에 대해 대부분 채팅과 관련하여 메시지가 소실되도 무방한 구조에서 pub/sub의 브로드캐스팅 방법을 사용하는 것으로 알고 있습니다. 이전에 언급하신 Redis Lock에서 사용하는 경우는 애초 접근하는 서버가 수십~ 수백대일 가능성이 있습니다. 채팅의 경우도 유투브 라이브의 경우 수천 수만명의 접속일 가능성이 있습니다. 서버의 가용 능력에 따라 분산 설계가 있을 수 있겠지만 기본적으로 이러한 요구에서는 1:N이 됩니다. 어떤 목적과 이유로 1번과 관련하여 말씀을 하신건지 알고 싶습니다. 하나의 pub/sub 연결을 여러 채널이 공유해서 사용하는 것이기에 pool에 대한 이야기는 아닐 것이라 생각 합니다. 혹시 예제는 스웨거에서 요청할 때마다 pub/sub을 생성해서 사용하는 것이기에 애초에 하나의 pub/sub 연결로 사용하는 방안으로 코드를 설계해야 한다는 의미일까요? 하지만 그럼에도 클라이언트 수나 구독을 소수로 유지해야 하는 의미는 pool을 의미하시는 건지 서버 자원 때문인지 어떤 이유에서인지에 대한 이해가 잘 되지 않습니다. 3. 3번에서 하는 말이 하나의 pub/sub 연결을 시작시 생성하여 모든 채널에 대해 공유 사용하고 종료시 구독을 해제하도록 하라는 의미로 보면 될런지요
질문이라기 보다는 저같이 몇시간 버리시는 분 계실까 내용 공유드립니다. 도커 데스크탑 업데이트로 testcontainers 의존성 버전이 안맞은게 문제였습니다. 감사하게도 같은 문제로 다른분이 포스팅을 적어두셨더라구요. build.gradle 파일에서 testcontainers 의존성 -- 아래 처럼 변경 testImplementation 'org.testcontainers:testcontainers:2.0.5' testImplementation 'org.testcontainers:testcontainers-junit-jupiter:2.0.5' testImplementation 'org.testcontainers:testcontainers-mysql:2.0.5' ※ 최신버전은 Maven Rep 참고해주세요. 참고한 포스팅입니다. 도커 업데이트 이후 Testcontainers 테스트 실패 이슈 해결 기록 이슈 해결 외에도, 도커 버전에 따라 최소 API 버전 확인 할 수 있는 방법도 같이 기재되어있어 참고하기 좋은 것 같습니다.
K6 부하 테스트 터미널 창에서 WARN[0000] Request Failed error="Post \" http://localhost:8080/likes/redis\ ": dial tcp 127.0.0.1:8080: connectex: No connection could be made because the target machine actively refused it." 상기 에러가 계속 나옵니다. -- 테스트 결과 -- 이전 테스트 보다 20배정도 처리속도가 개선된건 확인했으나 실패율이 계속 뜨는건 OS차원의 문제일까요? (OS는 Windows 입니다) -- Redis 적용 이전 -- -- Redis 적용 이후 --
학습 관련 질문을 최대한 상세히 남겨주세요! 고민 과정도 같이 나열해주셔도 좋습니다. 먼저 유사한 질문이 있었는지 검색해보세요. 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요. 안녕하세요. 64강 17분쯤 ArticleReadService의 count 메서드 구현하신 코드를 보면 아래 코드블럭과 같이 작성하셨습니다. private long count(Long boardId) { Long result = boardArticleCountRepository.read(boardId); if (result != null) { return result; } long count = articleClient.count(boardId); boardArticleCountRepository.createOrUpdate(boardId, count); return count; } 그런데 BoardArticleCountRepository의 count 메서드는 아래와 같이 작성하셨는데 이 경우 boardArticleCountRepository.count(boardId);는 Redis에서 데이터가 조회되지 않은 경우 0L를 반환하여 ArticleReadService의 count 메서드에서는 항상 client에서 조회하는 케이스가 발생하지 않을거 같습니다. public Long read(Long boardId) { String result = redisTemplate.opsForValue().get(generateKey(boardId)); return result == null ? 0L : Long.valueOf(result); }