2025.06 ~ 현재:
미국 실리콘밸리 AI Coding Agent 스타트업 창업 (ex. Claude Code, Codex)
2024.05 ~ 2025.05:
미국 실리콘밸리 AI 핀테크 스타트업, 소프트웨어 엔지니어
2023.08 ~ 2024.04:
미국 빅테크(OpenAI, Meta, Apple, etc) 엔지니어 펠로우십 풀스택 소프트웨어 엔지니어 펠로우
~2022.10 @국내 기업 재직(검색포털/핀테크, AI)
강의
로드맵
전체 1수강평
- 고성능 실시간 분산 시스템 RabbitMQ + Kafka + Redis 실전 프로젝트
- 고성능 실시간 분산 시스템 RabbitMQ + Kafka + Redis 실전 프로젝트
- 고성능 실시간 분산 시스템 RabbitMQ + Kafka + Redis 실전 프로젝트
- 고성능 실시간 분산 시스템 RabbitMQ + Kafka + Redis 실전 프로젝트
- 고성능 실시간 분산 시스템 RabbitMQ + Kafka + Redis 실전 프로젝트
게시글
질문&답변
Matching Service의 MQ 필요성, Cassandra의 필요성, Cassandara - RDB 동기화
안녕하세요. 한재현님,먼저 수강해주셔서 감사드리며 좋은 질문을 해주셔서 기쁘네요 Matching Service의 MQ와 /swipe의 matching 응답값 강의에서는 REST API는 지연이 발생할 수 있으므로 MQ를 사용했다고 말씀하셨습니다. 이때 API 명세에 있는 matching 값의 해석이 헷갈립니다. matching은 swipe 시점에서 자신이 상대와 매칭되었는지 알 수 있는 값이라고 생각되는데, 그러면 동기 처리가 필요한 것 아닌가 생각이 듭니다. 즉 Cassandra에서 inverse swipe이 존재하는지를 확인한 뒤에야 API 응답을 보낼 수 있는 것 아닌가요? 강의에서는 /swipe는 빠르게 “접수”만 응답하고, 매칭 확정은 MQ 기반 비동기로 처리하는 것을 목표로 하였습니다. 좀 더 세부적으로 말씀 드리면, /swipe는 20–40ms 내에 “요청을 접수했다(accepted)”고만 돌려주고, 실제 매칭 확정은 MQ(Kafka/SQS)로 흘려 Matching Service가 비동기 처리합니다. 하지만 왜 굳이 비동기를 하였느냐인데, inverse swipe 를 동기로 처리하게 되면 Region 간의 지연 또는 hot partition 이 인기있는 사용자에게 발생할 수 있는 부분 그리고 스와이프는 초당 수십만건의 데이터 쓰기가 발생하는 점을 고려해서 병목, 즉 수십만 건의 쓰기의 부하에 취약할 수 있습니다. 이러한 운영에 안정된 파이프라인을 구성하였습니다. 따라서, /swipe 응답은 20–40ms 내에 accepted만 보장하고, 실제 매칭 여부는 Kafka/SQS로 전달된 이벤트를 Matching Service가 처리해 WebSocket/푸시로 최종 통지합니다.Cassandra의 필요성RDB 조회만으로 inverse swipe 여부를 파악할 수 있을 것 같습니다. 그러면 Cassandra는 캐싱 용도로 사용한 것이라고 보아야 하나요? 원래 설계에서 Cassandra가 자연스럽게 도입된 이유가 궁금합니다.Cassandra 의 경우는 inverse swipe 여부를 사실상 나에게 온 좋아요 리스트 즉, 인접리스트의 구간을 매주 자주 데이터를 읽어야 합니다. 그렇기 때문에 Cassandra 는 부하가 일어나는 swipe 를 싸게 받아서 파티션 키 = 사용자를 기준으로 최근 범위의 데이터 읽기를 빠르게 제공합니다. 물론 RDB 로도 불가능하지 않지만, 대규모에서 샤딩과 인덱스 또는 Race condition 과 같은 비용이 커져 총 비용과 지연이 급증할 수 있습니다. 결국 데이터 접근은 단일 파티션의 최근 범위가 되기 때문에 Cassandra 에 좀 더 적합하다고 할 수 있습니다. 좋은 질문을 해주셨습니다. Cassandra - RDB 동기화 여부swipe 기록을 RDB와 Cassandra에도 모두 저장할 때, 일시적 오류 등으로 한쪽에만 저장될 수도 있을 것 같은데, 이런 상황에 대비해 RDB와 Cassandra 간 동기화가 필요한지 궁금합니다.한쪽만 저장되는 것처럼 보이는 상황은 대부분 Consumer 의 지연 또는 일시적인 실패이기 때문에 재시도로 복구 될 수 있습니다. 별도의 양방향 동기화 트랜잭션은 권장되지 않습니다. 오히려 장애가 일어나는 범위가 늘어나는 것이라 권장되지 않습니다. 훌륭한 질문을 해주셨습니다. 감사합니다. 좋은 하루되세요!
- 0
- 2
- 18
질문&답변
Imgur 이미지 호스팅 서비스 질문
안녕하세요. 장준혁님,먼저 수강해주셔서 감사의 말씀 드립니다.아주 좋은 질문을 해주셔서 기분이 좋아지는 하루입니다. PreSigned URL 을 발급 한 후 클라이언트에서 직접 direct 로 blob storage 즉, AWS S3 를 예시로 들어 해당 blob storage 로 업로드 됩니다. 그 과정에서 청크의 진행상황을 탐지하고 이 진행상황을 key-value storage 즉 nosql 데이터베이스에 업데이트 하는 시스템 구조가 궁금하신 것으로 이해하였습니다. 여기서 클라이언트가 직접 direct 로 AWS S3 에 pre-signed url 로 업로드를 하게 되는데 이 과정에서 Multipart upload api 를 사용하여야 청크가 분할되어 s3 에 업로드 되게 됩니다. 그 후에 Key-value storage 에는 아래와 같이 저장을 합니다. { "id": "ul_xxx", "userId": "u1", "key": "uploads/2025/10/img.png", "uploadId": "XYZ", "partSize": 8388608, "status": "INITIATED", "totalBytes": 123456789, // 알면 저장 "bytesUploaded": 0, "partsDone": [], // [{partNumber, etag, size}] "expiresAt": "...", "lastHeartbeatAt": "..." }그리고나서 클라이언트는 파일을 청크로 분할 해서 s3 에 직접 업로드를 하게 되고 전송된 바이트를 시스템의 목적에 따라 WS(웹소켓)/SSE/HTTP 로 주기적으로 업데이트를 합니다. 각 파트가 업로드 되면 응답헤더의 ETag 를 읽어서 "partsDone": [], // [{partNumber, etag, size}] 에 업데이트해서 bytesUploaded를 갱신하여 근사 % 계산 하는 방식으로 시스템을 설계할 수 있습니다. 그리고 나서 s3 버킷의 Event Notification (SQS, SNS, Lambda) 을 수신해서 status 를 완료 처리하고 후속작업을 할 수 있습니다. 후속작업은 예시로 썸네일, 리사이즈 등이 있습니다. 하지만, 폴링 polling 방식은 폴링은 비용,지연만 늘리고 정확도는 낮아서 권장되지 않습니다. 추가적으로 네트워크 끊김 시 uploadId로 ListParts 조회해서 미완료 청크 부터 재시도 할 수 있습니다. 감사합니다. 좋은 하루 되세요!
- 0
- 2
- 24
질문&답변
쿠폰 문의
안녕하세요 nameunskadms 님, 새로운 쿠폰을 발급해드렸습니다. https://inf.run/1D24g감사합니다.
- 0
- 1
- 34
질문&답변
Redis 랜덤 값 추가 시 메타데이터 저장
안녕하세요 강토토님,좋은 질문을 해주셨습니다.Redis는 내부적으로 각 키에 대한 메타데이터(예: 데이터 타입, 만료 시간, 메모리 위치 등)를 자동으로 관리합니다. 이 메타데이터는 Redis 내부의 in-memory 데이터 구조에 저장되며, 사용자가 별도로 Map이나 딕셔너리 형태로 외부에서 관리해줄 필요는 없습니다. 예를 들어, Redis는 해시 테이블 기반의 dict 구조를 통해 키-값을 저장하고 탐색할 수 있도록 설계되어 있어서 O(1) 시간 복잡도로 키 탐색이 가능합니다. 이 dict 자체가 Redis 내부의 메타데이터를 포함하는 구조이며, Redis가 이를 바탕으로 빠르게 키를 찾을 수 있게 해줍니다. 즉, 질문하신 “메타데이터를 programmatically하게 Map이나 딕셔너리에 저장하는 의미냐”는 질문은 아니오에 가깝고, Redis가 이미 내부적으로 이런 메타데이터 구조를 포함하고 있기 때문에, 사용자가 따로 관리할 필요는 없습니다.감사합니다
- 0
- 1
- 35
질문&답변
자료 다운로드 항목이 비어있어요
안녕하세요 inth 님 먼저 자료 누락에 대해 죄송하다는 말씀 드리며,미국 서부 기준 이번주 내로 자료 누락된 부분에 대해서 복구 하도록 하겠습니다.감사합니다.
- 0
- 2
- 38
질문&답변
Blob Storage에서 파일 업로드에 대한 동시성을 어떻게 제어할 수 있을까요?
안녕하세요. 이정환님, 답변이 늦어 죄송합니다. 좋은 질문 감사드립니다.Blob Storage 또는 AWS S3처럼 객체 저장소에 용량이 큰 파일을 업로드할 때, 동일한 파일이 동시에 여러 번 업로드되는 문제는 실제로 많이 발생합니다. 이를 해결하기 위해 많이 사용하는 방식이 바로 Pre-Signed URL 기반 업로드입니다.Pre-Signed URL + 조건부 요청 조합으로 해결할 수 있습니다. 서버에서 업로드 전에 파일의 해시(SHA-256 등)를 계산합니다.이 해시를 기반으로 S3 또는 Blob Storage에 저장할 파일의 이름(Key)을 정합니다.예: uploads/1a2b3c4d5e...이미 동일한 해시의 파일이 존재하는지 확인합니다.존재할 경우 → 업로드 생략 (중복 방지)존재하지 않을 경우 → Presigned URL을 발급하여 클라이언트에게 전송클라이언트는 해당 URL로 직접 업로드합니다.이때 If-None-Match: 헤더를 사용하면, 동일한 키에 파일이 이미 존재할 경우 업로드가 거부(HTTP 412)되어 중복 업로드가 자동 방지됩니다. 대용량 파일이라면 Multipart Upload + 각 파트별 Pre-signed URL 조합으로 병렬 업로드도 가능합니다.Presigned URL은 짧은 유효시간, 최소 권한 설정으로 보안도 안전하게 유지할 수 있어요. 결론적으로, 해시 기반 파일명 지정 + Pre-signed URL + 조건부 업로드 조합은 Blob Storage 환경에서 동시 업로드 충돌 방지와 중복 업로드 최소화에 효과적인 방식입니다.
- 0
- 2
- 53
질문&답변
관계형 DB에서 비즈니스 요구사항 추가에 대한 대처 방법
좋은 질문입니다. 답변이 늦어졌네요. 요즘 빅테크 한 곳과 이직 인터뷰가 있기도 하고 이사도 하느라 늦어진 점 사과드립니다. 많은 분들이 관계형 DB는 스키마 변경이 어렵다고 알고 계시지만, 실제로 대형 서비스에서는 스키마 변경은 흔하고 자연스러운 과정입니다. 중요한 건 무작정 모든 필드를 처음부터 다 예측해서 설계하려고 하기보다, 변화에 유연하게 대응할 수 있는 구조와 프로세스를 갖추는 거예요. 서비스를 운영하다 보면 비즈니스 요구사항은 계속해서 변합니다. 유저 테이블에 age가 새롭게 필요해졌다면, 그냥 다음처럼 추가하면 됩니다ALTER TABLE user ADD COLUMN age INT;요즘 대부분의 RDBMS 는 이런 단순한 컬럼 추가 작업은 논블로킹 non-blocking 으로 처리하기 때문에, 실시간 서비스 운영 중에도 문제없이 반영할 수 있습니다.또한, MVP 단계에서 모든 필드를 예측해 넣으려다 보면, 과한 스키마 설계로 이어지고,이는 오히려 서비스 속도와 유지보수성을 떨어뜨립니다.그렇기 때문에 중요한 건 완벽한 예측이 아니라, 변화에 대응 가능한 유연한 설계를 하는 것 입니다.실무에서는 핵심 도메인에 집중해 작고 명확한 스키마로 출발하고, 변화에 따라 점진적으로 확장하는 것이 일반적이라고 할 수 있습니다.
- 0
- 2
- 64
질문&답변
AP 시스템이 전자상거래에 적용될 수 있는 이유
안녕하세요 한재현님, 수강 감사드리며, 좋은 포인트를 짚어주셨습니다.전 세계 사용자에게 끊김 없는 경험을 제공하기 위해 전자상거래 사이트는 전 세계에 흩어진 수많은 고객에게 빠른 페이지 응답을 보장해야 합니다. 네트워크 지연이나 일부 서버 장애가 발생해도 “읽기, 쓰기 요청을 계속 받아들이는” AP 계열 데이터베이스, 예를 들어 DynamoDB 같은 시스템은 글로벌 쇼핑몰의 요구사항과 잘 맞습니다. 왜냐하면, 즉시 완벽한 일관성이 아니어도 되는 영역이 많아서 물론 결제나 주문 확정 같은 부분은 강한 일관성이 필요하지만, 상품 상세 조회나 장바구니처럼 “약간의 지연”이 사용자에게 큰 불편을 주지 않는 경우가 많습니다. 예컨대 재고 수량이 실제보다 몇 초 늦게 업데이트돼도, 고객 경험에는 크게 영향을 주지 않죠. 그렇기 때문에, 이런 영역은 AP 모델의 ‘최종 일관성’을 받아들이고, 백그라운드 동기화로 데이터를 맞춰 갈 수 있습니다.중요한 트랜잭션은 보강해서 처리할 수 있다는 점은 DynamoDB에도 트랜잭션 기능이 있어서, 결제나 주문 확정과 같이 “절대 놓칠 수 없는” 작업은 CP처럼 처리하도록 설계할 수 있습니다. 즉, 전체 서비스는 AP로 운영하면서도, 민감한 도메인에서는 트랜잭션을 걸어 강한 일관성을 확보하는 하이브리드 구조를 만드는 것이 가능합니다.감사합니다. 좋은 하루 되세요!
- 0
- 2
- 71
질문&답변
채팅을 영속할 DB로 RDB를 선택한 이유도 궁금합니다
안녕하세요. 목동 개발자님좋은 질문을 해주셨습니다.채팅 데이터를 영속화하는 데 RDB를 선택한 이유는, 채팅 시스템에서 메시지와 사용자, 타임스탬프 같은 데이터가 명확한 구조를 가지기 때문입니다. RDB는 이런 구조화된 데이터를 테이블로 관리하기 쉽고, 메시지 전송 순서나 사용자간의 관계를 정확하게 보장하는 데 유리합니다. 예를 들면, 메시지 ID, 발신자, 수신자, 전송 시간을 하나의 레코드로 저장하면서 데이터 무결성을 유지할 수 있습니다.또한, RDB는 ACID(원자성, 일관성, 격리성, 지속성) 속성을 지원해 메시지 전송 중 오류가 발생해도 데이터가 손상되지 않도록 보장합니다. 예를 들어, 메시지를 보내는 동시에 읽음 상태를 업데이트하는 작업을 트랜잭션으로 묶을 수 있습니다.쿼리 효율성도 중요한데, RDB는 조인(JOIN)을 통해 사용자, 채팅방, 메시지 간 관계를 효율적으로 조회할 수 있습니다. 예를 들어, 특정 그룹의 모든 메시지를 시간순으로 가져오거나 특정 사용자가 받은 메시지만 필터링하는 작업이 용이합니다.실제 사례를 보면, WhatsApp은 초기 아키텍처에서 MySQL 같은 RDB를 사용했으며, Slack도 MySQL을 사용해 데이터 저장을 관리했습니다참고 링크: (https://slack.engineering/scaling-datastores-at-slack-with-vitess/)질문에서 채팅은 강결합 트랜잭션이 불필요해 보인다고 언급해주셨는데, 이는 부분적으로 공감할 수 있습니다. NoSQL은 확장성과 유연성이 뛰어나 대규모 분산 시스템에 강점이 있습니다. 하지만 채팅 시스템에서는 단순히 메시지를 저장하는 것뿐 아니라, 읽음 상태 업데이트, 그룹 채팅 멤버 관리 등 데이터 일관성이 중요한 작업이 있습니다.RDB는 이런 경우 트랜잭션을 통해 안정적으로 처리할 수 있지만, NoSQL은 기본적으로 eventual consistency(최종 일관성)를 제공하는 경우가 많아 실시간성이 중요한 채팅에서 일시적인 데이터 불일치가 발생할 수 있습니다. 예를 들어, 메시지가 한 사용자에게는 표시되었지만 다른 사용자에게는 아직 반영되지 않은 상황이 생길 수 있습니다.또한, RDB는 관계형 데이터 모델을 통해 복잡한 쿼리와 데이터 관계를 효율적으로 처리할 수 있어, 채팅 앱의 초기 설계와 유지보수에서 유리합니다. NoSQL은 대규모 데이터와 비구조화된 데이터에 강하지만, 채팅 데이터의 특성과 초기 설계의 단순함을 고려할 때 RDB가 더 적합할 수 있습니다.실제 사례에서, WhatsApp은 초기에는 RDB를 사용했으며, 이후 규모가 커지면서 Mnesia 같은 분산 데이터베이스를 도입했지만, 이는 RDB의 한계를 보완하기 위한 보조적인 선택이었습니다아래 이미지와 링크를 통해 해당 내용을 참고하실 수 있습니다!(사진)https://www.cometchat.com/blog/whatsapps-architecture-and-system-design좋은 하루 되세요!
- 0
- 2
- 147
질문&답변
URL 단축 서비스에서 redis counter를 사용하는 이유가 무엇인지 궁금합니다.
안녕하세요 방구석효행뜽님, 먼저 수강 해주신 것에 감사드립니다. 아주 좋은 질문을 해주셨습니다. 먼저 Redis Counter를 사용하는 이유는 URL 단축 서비스에서 사용되는 고유한 id 를 생성하기 위함입니다. URL 단축 서비스의 핵심은 긴 URL 을 짧고 고유한 Short URL 로 변환하는 것에 있습니다. 또한 쓰기(URL 생성) 작업에 대한 확장성과 빠른 퍼포먼스를 보여줄 수 있습니다.이 과정에서 중복되지 않는 키를 빠르고 효율적으로 만들어야 하기 때문에 메모리 기반의 고성능 데이터 저장소인 Redis Counter를 기반으로 INCR 명령어를 통해 카운터를 증가 시켜 고유한 id 값을 생성하게 됩니다. 따라서 Redis Counter 가 제공하는 증가되는 숫자 (예시, 1, 2,3 ...) 를 기반으로 Short URL 을 생성하게 되는데 데이터 흐름을 보면 아래와 같습니다. Short URL 생성Redis Counter 증가DB에 저장캐시 업데이트이 과정에서 사용자가 긴 URL(예: https://example.com/very/long/url 을 단축하려고 요청하면, 시스템은 고유한 short URL(예: https://short.url/g8)을 생성해야 합니다.Redis counter는 여기서 고유한 숫자 값을 제공합니다. 예를 들어, INCR counter 명령을 실행하면 현재 값이 1000에서 1001로 증가합니다.이 값(1001)을 기반으로 short URL의 키를 만듭니다. 흔히 Base62 인코딩(0-9, a-z, A-Z를 사용한 62진법)을 사용해 숫자를 짧은 문자열로 변환합니다. 예를 들어, 1001은 g8로 변환될 수 있습니다.Counter 값 1000 → Base62로 변환 → g8 → https://short.url/g8Counter 값 1001 → Base62로 변환 → g9 → https://short.url/g9결과적으로 https://short.url/g8 같은 short URL이 생성됩니다.그리고 질문에서 "Redis counter를 증가시키고 short URL을 생성한다"는 순서가 반대일 수도 있다고 하셨는데, 보통은 counter를 증가시키는 게 먼저고 그 값을 사용해 short URL을 만듭니다. 하지만 시나리오상 순서가 바뀌어도 결과는 동일합니다. 그리고 말씀하신대로 "100억 개 URL limit을 체크하기 위함이 합리적일 것 같다"고 하신 추측도 타당합니다. 예를 들어, counter가 10,000,000,000(100억)에 도달하면 시스템이 더 이상 새로운 URL을 생성하지 않도록 제한할 수 있습니다.하지만 이건 주로 모니터링 목적입니다. 실제 URL 생성 로직 자체는 counter 값이 100억을 넘어도 계속 동작할 수 있고, 100억 제한은 시스템 설계상 의도된 한계일 뿐입니다. 따라서, 100억 URL 제한: Redis counter로 생성된 URL 수를 모니터링해 한도를 체크할 수 있지만, 생성 로직과 DB 저장에는 직접 영향을 주지 않습니다. 감사합니다. 좋은 질문을 해주셔서 감사드리며 좋은 하루 되세요
- 0
- 2
- 144





