안녕하세요.
IT 서비스 대기업 개발자로 근무하며, 대규모 시스템을 지탱하기 위해 다양한 기술을 활용해보고 있습니다.
실무 관점의 개발 지식을 공유하고자 개설하였고, 많은 도움이 되었으면 좋겠습니다.
문의 : kukekyakya@gmail.com
안녕하세요. 쿠케입니다.
IT 서비스 대기업에서 백엔드 개발자로 재직 중이며, 대규모 트래픽을 지탱하는 서버 애플리케이션을 개발합니다.
현재 인프런에서 대규모 시스템 강의들을 개설 및 운영하고 있습니다.
다양한 도메인의 서비스를 개발 및 운영하고 있으며, 대규모 레거시 프로젝트 뿐만 아니라 신규 프로젝트도 여러 번 경험을 해왔습니다.
주력 기술로는 Java, Spring Boot, RDB, NoSQL, Redis, Kafka 등의 안정적이고 주요한 기술을 다루고 있습니다.
MSA, DDD, EDA 등의 방법론을 활용한 분산 시스템 아키텍처를 직접 밑바닥부터 구성 및 운영해온 경험이 있고,
알고리즘 문제 풀이 및 CS 공부도 간간히 즐겨하고 있습니다.
개발 관련하여 이것저것 궁금한 점 나누는 시간으로 만들어보고자 합니다.
설계에 대한 논의 또는 자문, 개발 방법론 관점이나 생각 공유, 구현 방식에 관한 논의, 공부 방법, 코드 리뷰, 포트폴리오 리뷰 등..
무엇이든 좋습니다.
물론, 저도 모르는 주제가 있을 수 있으므로, 신청서에 멘토링 필요한 내용도 미리 공유 주시면 감사하겠습니다.
일정은 조율될 수 있고, 온라인 화상(마이크/화면 ON)으로 진행합니다.
별도 문의는 프로필에 기입된 메일로 먼저 주셔도 됩니다.
감사합니다.
강의
수강평
- 스프링부트로 직접 만들면서 배우는 대규모 시스템 설계 - 게시판
- 스프링부트로 직접 만들면서 배우는 대규모 시스템 설계 - 게시판
- 스프링부트로 직접 만들면서 배우는 대규모 시스템 설계 - 게시판
- 스프링부트로 직접 만들면서 배우는 대규모 시스템 설계 - 게시판
게시글
질문&답변
무한 depth 구현 설계에서 질문이 있습니다.
fb1014님, 안녕하세요! 00a0z 00a0z 00000 00a0z 00001 00a0z 00001 00000 00a0z 00002위와 같은 상황을 말씀하신 것이겠죠?그렇다면 말씀하신 내용 모두 맞습니다!00a0z의 descendantsTopPath는 00a0z 00002가 되고,childrenTopPath도 00a0z 00002로 동일합니다. 00a0z 00001 0000000a0z 00002두 데이터는 사전순 정렬에 의해 후자가 더 큰 것도 맞습니다! 혹시 더 궁금한 점 있으시면 편히 문의 주세요!
- 0
- 2
- 33
질문&답변
락 처리
wnsqud70님, 안녕하세요! redisson은 레디스 클라이언트 라이브러리일 뿐이고, 결국 레디스를 이용한 분산락을 말씀하신 것 같습니다.분산 시스템에서 락을 잡고자 한다면 언제든 사용해도 됩니다!다만, 강의에서 진행하는 좋아요 수 데이터는 메인 데이터베이스로 MySQL을 사용하고,MySQL의 트랜잭션과 로우락을 이용하여 문제를 해결하고 있습니다.이미 MySQL에서 해결책을 제시하고 있는 상황인데, 타 DB를 도입하는 것은 시스템 복잡성과 운영 비용을 높일 수 있습니다.하지만 로우락 잡는 것 자체도 DB에 더 큰 부담을 주는 것이고, 메인 DB의 리소스는 가장 중요할 수 있으므로,락에 대한 처리를 레디스와 같은 타 DB로 이관하는 것도 가능한 선택지 중에 하나입니다.인메모리 기반이라 더욱 빠르고, 메인 DB 부담을 줄여준다는 장점이 있겠네요.문제 없는 범위에서는 복잡성/운영 비용/성능 등 고려하여 다양한 도구를 활용할 수 있을 것 같습니다.타 DB 연동할때 고려할만한 부분은,트랜잭션이 시작됨에 따라 MySQL 커넥션을 물고 있을텐데, Redis 장애로 인해 지연이 발생하면, MySQL 리소스가 낭비될 수 있는 등 여러 문제 사항에 대해서 검토가 필요할 것 같습니다. 관련해서 개발 비용이 높아질 수 있다는 점도 같이 고려 대상이 될 수 있겠네요.그리고 분산락은 이후 강의 진행하다보면 사용하게 됩니다! 혹시 더 궁금한 점 있으시면 편히 문의 주세요!
- 0
- 2
- 49
질문&답변
rowLock
wnsqud70님, 안녕하세요! 질문 이해를 잘 못하였는데, 아래 내용 물어보신게 맞을까요?! 현재 강의에서 사용한 mysql 버전의 디폴트 격리 레벨에서는 커밋된 데이터만 읽을 수 있습니다.그래서 타 트랜잭션에서 변경을 하였더라도, 커밋되지 않은 변경 사항이라면 현 트랜잭션에서 읽을 수 없습니다.이미 커밋된 과거 데이터만 조회되는 것입니다.동시 요청이 조회해온 과거 데이터는 동일할 것이고, 이에 대해 증가 처리를 수행하면 데이터가 유실될 수 있으므로, 동시성 이슈가 발생한다고 볼 수 있습니다. 근데 만약 조회 시점에 로우락을 걸어버리면(select for update 등으로),타 트랜잭션의 새로운 데이터 변경 사항 커밋이 완료될 때까지 현 트랜잭션의 조회가 지연되므로,이 경우에는 동시성 이슈가 해결된다고 볼 수 있습니다. 혹시 더 궁금한 점 있으시면 편히 문의 주세요!
- 0
- 2
- 30
질문&답변
카프카에 담긴 이벤트 순서가 올바르지 않을 가능성 관련 질문
chlghksdyd31님, 안녕하세요!꼼꼼하게 복습도 하고 계시는군요, 훌륭한 자세입니다! 말씀주신 내용의 해결 방법은 아주 다양할 수 있을 것 같네요.프로듀서/컨슈머에 따라 달라질 수도 있고, 상황에 따라, 도메인에 따라 달라질 수도 있습니다.그렇다고 꼭 정답이 있는건 아니고, 트레이드오프 감안해서 적절히 채택하는 과정이 필요할 것 같습니다.예시로 몇 가지 말씀 드려보겠습니다! 컨슈머 측에서 최신에 처리한 이벤트보다 과거 이벤트가 수신된다면 무시말씀주신대로, 가장 최신에 처리한 이벤트보다 과거의 이벤트가 수신된다면 무시할 수도 있습니다.이벤트를 세분화하고 타입으로 구분할 수 있다면, 타입별로 최신 이벤트를 관리할 수도 있겠네요.또는, 각 이벤트 타입에서 더 세분화해서 구분할 수도 있고요. (예를 들어, 게시글 ID 단위로 최신 이벤트 관리)최신/과거라는 기준은 반드시 타임스탬프를 사용하지 않더라도, 프로듀서 측에서 시퀀스를 채번할 수도 있습니다.컴퓨터가 생성해주는 시간은 엄밀히 따지면 과거로 되돌아갈수도 있기 때문에(clock drift) 가볍게 언급드려봅니다.다만, 무시되는 이벤트가 반드시 처리되어야 했다면, 유실될 수 있다는 위험성이 있네요. 컨슈머 측에서 논리적인 관계를 이용이벤트 간에 논리적 관계를 이용할 수도 있습니다.예를 들어, 게시글 삭제 이벤트를 수신했다면, 게시글 생성 이벤트는 반드시 이미 수신된 상태여야 합니다.하지만 게시글 생성 이벤트를 아직 컨슈머가 수신하지 못했을 수도 있습니다.삭제 이벤트를 임시 버퍼에 저장해두고, 생성 이벤트가 수신될 때까지 처리를 지연할 수도 있습니다.임시 버퍼는 DB를 활용해도 되지만, 별도의 재처리 큐를 활용할 수도 있을 것 같네요.(카프카의 dead letter queue 기능 등) 컨슈머 측 DB에 이벤트 적재 후 주기적으로 폴링해서 사용컨슈머 측 DB에 이벤트를 저장하고, 과거 이벤트도 충분히 다 수신했을 시점이 온다면,주기적으로 오래된 이벤트부터 폴링해서 처리할 수도 있을 것 같습니다. 프로듀서가 After Commit 이후에 즉시 전송하지 않고, 이벤트를 db에 넣고 순서대로 처리지금 강의에서는 트랜잭션에 묶어서 이벤트를 rdb에 저장하고 있는데요,rdb에 저장이 완료된 이벤트에 대해서 오래된 이벤트를 순차적으로 전송할 수도 있습니다.확실하게 전송이 완료되었을 때에만 다음 이벤트를 전송하는 것입니다.다만, 이러면 비동기에 대한 지연이나 폴링 비용은 더욱 커질 수 있겠네요. CDC를 사용할 수도 있습니다.강의에서는 outbox 패턴으로 직접 구현했지만, CDC로 운영하는게 더욱 쉬울 수도 있습니다.트랜잭션 로그 기반으로 처리하기 때문에, 데이터베이스 삽입된 순서대로 알아서 잘 처리해줄 것 같네요. 순서 보장이 반드시 필요한 도메인이라면 분산 시스템을 구축하지 않는 것도 방법입니다.분산 시스템에서 트랜잭션/순서보장을 완벽하게 구축하는건 쉽지 않고 큰 비용이 듭니다.이벤트가 유실되고 잘못된 데이터가 들어가는게 엄청나게 큰 문제로 다가올 수 있다면,이러한 상황을 감안할 바에야 그냥 모놀리틱한 시스템을 구축하는게 편할 수도 있습니다.항상 모든 상황에 분산 시스템으로 만들어야하는 것도 아니고, 장비 성능도 생각보다 좋습니다.특히 금융처럼 돈이 걸려있으면 데이터 깨지는 것 보다 시스템 운영 비용을 더 들여서라도 신뢰성을 보장하는게 더 좋은 선택일 것 같네요. 정말로 엄격한 순서 보장이 필요한지 고민해봐도 좋습니다.순서가 엄격하게 보장되어야하는 도메인이라면, 당연히 해결책이 필요합니다.그런데 대부분의 도메인에서 순서 보장이 그렇게 엄격하게 필요하지 않을 수 있습니다.예시로, 게시글의 실제 댓글 수와 댓글수 데이터가 다르다고 해서, 이게 얼마나 문제가 될 수 있을까요?말씀주신 내용은 아주 극단적인 예외 상황일때 발생할 수 있는 문제지만, 이를 해결하기 위한 시스템 구축 비용은 이점에 비해 훨씬 클 수 있습니다.충분히 감안할 수 있는 상황이라면, 사용자 문의가 들어올 때에나 수동 대응하는게 오히려 유리할 수 있을 것 같네요. 꼭 한 가지 방법을 채택할 필요는 없고, 각 방법들을 적절히 혼용할 수도 있습니다.혹시 더 궁금한 점 있으면 편히 문의 주세요!
- 0
- 2
- 63
질문&답변
질문 하나 있습니다!
리나님, 안녕하세요! 이번 강의도 정말 잘 들어주셨는데, 다음 강의도 기다려주시다니 너무 감사하네요 ㅎㅎㅎ말씀하신대로 다음 강의는 캐시 전략으로 준비중입니다!전략은 전략일 뿐이라 꼭 Redis를 사용할 필요는 없지만, Redis가 이점이 많아서 이를 활용하게 되네요!제목은 "스프링부트로 직접 만들면서 배우는 대규모 시스템 설계 - 캐시 전략"이 될 것 같고요.단순히 @Cacheable을 사용했을 때에 문제 상황을 살펴보면서 해결 전략들을 학습하게 됩니다.(본 강의에서도 한번 다룬 Request Collapsing / 리스트 캐시 전략도 일부에 포함됩니다.)현재 대략적인 커리큘럼은 정리된 상황인데, 그림이나 부족한 설명 보충을 계속 진행하고 있습니다.사실 정말 대규모 트래픽을 해결하기 위한 전략들이라 대부분의 서비스에서 이 정도까지 필요할지 싶기는 한데..(수강생 분들에게 잘 와닿을 수 있을지!?)이해해두면 응용할 수 있는 영역도 많고 한번쯤 풀어내보면 좋을 주제라고 생각되어서 진행하게 되었네요.다만, 요즘 본업이 너무 바쁘다보니 시간 내기가 쉽지 않네요 ㅠㅠ 주말마다 정말 열심히 진행하고 있습니다.얼른 잘 준비해서 여름~가을 쯤에는 오픈할 수 있도록 준비해보겠습니다!기다려주셔서 감사합니다!!
- 0
- 1
- 40
질문&답변
게시글 목록 최적화 전략 구현 - 테스트 에서 오류가 발생합니다
woo님, 안녕하세요! "019169492674337349632"를 보면 Long 범위를 넘어가는 숫자인 것 같은데요,레디스에 직접 잘못된 데이터를 넣으신 적이 있거나 식별자를 변환해서 삽입하는 코드가 잘못 들어가있는걸까요?강의에서 Snowflake로 자동 생성되는 식별자는 Long으로 articleId를 생성하기 때문에,"019169492674337349632"라는 숫자가 안 만들어져야 할텐데 이상하네요..!올려주신 테스트 코드는 페이지 번호만 다를 뿐이라,테스트 코드 자체의 문제는 아닌 것 같은데,잘못된 데이터 들어간 원인을 찾아보시거나 제거해보시겠어요?
- 0
- 2
- 47
질문&답변
ArticlePageResponse 클래스 질문
동관님, 안녕하세요! ArticleResponse 리스트를 상속으로 표현한다는 것이 어떤 구조인지 잘 이해를 못했습니다!게시글 목록을 상속으로 만들 수가 있는걸까요?의도한 응답을 만들 수 있으면, 구성/상속 어떠한 것으로 만들든 상관 없지만,굳이 복잡한 구조로 풀어낼 필요는 없을 것 같습니다. 또, 개인적으로는 상속 구조를 선호하진 않습니다.코드 추적이나 이해가 어려워지고, 클래스 간에 코드가 강결합되기 때문에 재사용이나 유연하게 다루기도 어렵고, 다중 상속도 안돼서 제한되는 부분 등의 단점이 있는데, 인터넷 찾아봐도 많이 나오고 직접 경험해봐야 와닿는 부분이라 가볍게 언급 드려봅니다.그래서 가능하다면 구성으로 푸는 것을 선호하는 편입니다!
- 0
- 2
- 40
질문&답변
Comment 최상위 entity에서 parentCommentId를 자기 자신의 id를 두는 이유가 궁금합니다.
자기개발하고싶어요님, 안녕하세요! 일단 구현 방식은 다양할 수 있다는 점 가볍게 먼저 언급드려봅니다!꼭 강의의 구현 방식을 따라올 필요는 없고, 더 나은 구현 방식이 있다면 그것을 택해도 됩니다. 말씀하신대로 공간 절약을 위해 parentCommentId를 null로 설정할 수 있지만, 디스크는 저렴하기 때문에 현 수준에서 크게 유의미한 차이는 아닐 것 같습니다.디스크 공간 일부 절약하는 것보다 개발/유지보수 등의 관점에서 이점을 얻는게 더 유리할 때가 있습니다.parentCommentId를 null이 아닌 값으로 했을 때에 다음과 같은 장점이 있을 것 같네요.구현의 일관적인 측면에서 장점이 있을 것 같습니다. null 처리를 항상 따로 하지 않아도 된다는 것인데요, 코드에서도 null 검사를 직접 안해도 되고 쿼리에서도 null 쿼리를 구분하지 않아도 됩니다. null 처리의 복잡성을 없앨 수 있겠네요.데이터베이스마다 null 처리 방식이 다를 수 있습니다. 예를 들어, 인덱스 트리에서 null 값이 가장 작은 값으로 판단될 수도 있고, 가장 큰 값으로 판단될 수 있습니다. 이 경우 값을 명시하는게 명확하고 유리할 수 있겠네요.현재 설정된 인덱스는 parentCommentId ASC, commentId ASC 입니다. 루트 댓글 사이에서도 parentCommentId로 순서를 제어하는 상황인 것입니다. null이면 이러한 순서가 명확하지 않을 수 있습니다. 혹시 더 궁금한 점 있으시면 편히 문의주세요!
- 0
- 2
- 63
질문&답변
강의 인덱스 접근 관련 문의드립니다.
자기개발하고싶어요님, 안녕하세요! 사실 언급 주신 부분은 저도 명확한 답변을 드리기는 어려운 상황입니다..!https://inf.run/98UQR이전에 다른 분이 유사한 질문을 주신게 있어서, 위 내용을 참고해보시면 좋을 것 같습니다!
- 0
- 2
- 68
질문&답변
24시간 이내의 최신글 API 설계 관련 질문
soap님, 안녕하세요! 일단 프론트는, “최신글이 레디스에 저장되었다”라는 사실을 알 필요가 없습니다.프론트는 그저 서버에 데이터를 요청할 뿐이고, 서버는 요청 받은 데이터를 응답해주는 것입니다.이 관점에 대해서 짧게 먼저 언급 드려봅니다. 1. 사이트의 메인 페이지 일부 화면에 특정 게시판의 최신글을 뿌려주는 요구사항이 존재2. 서버의 최신글 API를 호출하여 각 게시판 종류마다 최신글을 뿌려줌맞습니다. 게시글 목록 API에서 불러올 수도 있고(생성순 정렬이면 상위 N개면 어차피 최신글임), 최신글 API를 따로 만들 수도 있습니다.서버는 요구사항에 알맞은 데이터만 뿌려주면 됩니다!
- 0
- 2
- 45