Java 멀티스레드 vs Kotlin 코루틴

Java 멀티스레드와 Kotlin 코루틴의 핵심 차이는 스케줄링 주체입니다. OS가 강제로 전환하느냐, 코드가 자발적으로 양보하느냐. OS 레벨 병렬처리 OS 레벨 ├── 멀티 프로세스 (독립 메모리) └── 멀티 스레드 (공유 메모리, OS 스케줄링) 언어 레벨 └── 코루틴 (공유 메모리, 언어 스케줄링) 핵심 차이: 누가 스케줄링하느냐 Java 멀티스레드 OS가 CPU 클럭 단위로 강제 스위칭 → 선점형(Preemptive) 스레드 전환 비용이 큼 (스택, 레지스터 저장/복원) 스레드 1개 = OS 스레드 1개 (~1MB) Kotlin 코루틴 suspend 포인트에서 자발적으로 스레드 반납 → 협력형(Cooperative) 전환 비용이 매우 작음 (힙에 상태 저장, ~수KB) 스레드 몇 개 위에서 코루틴 수천 개 동작 가능 계층 구조 코루틴은 스레드를 대체하는 게 아니라 스레드 위에서 동작합니다. ...

2026년 3월 22일

Primary/Replica DB 분리와 Replication Lag

Primary/Replica DB를 분리하는 이유, Replication Lag 문제, 그리고 해결 전략을 정리합니다. 왜 Primary/Replica를 분리하는가 일반적인 웹 애플리케이션은 읽기 트래픽이 쓰기 트래픽보다 훨씬 많습니다. 하나의 DB가 모든 트래픽을 처리하면 부하가 집중되고, 읽기 쿼리가 쓰기 락에 영향을 받을 수 있습니다. [분리 전] App → 단일 DB (읽기 + 쓰기 모두 처리) [분리 후] ┌─→ Primary DB (쓰기) App ─┤ └─→ Replica DB (읽기) Primary/Replica 분리의 목적은 크게 세 가지입니다. 목적 설명 부하 분산 읽기 트래픽을 Replica로 보내 Primary의 부하를 줄인다 읽기 성능 향상 Replica를 여러 대 두어 읽기 처리량을 수평 확장한다 가용성 Primary 장애 시 Replica를 승격하여 새로운 Primary로 전환(failover)할 수 있다 Replication Lag Primary/Replica 분리에는 근본적인 문제가 따릅니다. Primary에 기록된 데이터가 Replica에서 조회 가능해지기까지 지연이 발생하며, 이를 Replication Lag이라 합니다. ...

2026년 3월 10일

AWS ECS에서 Java + Spring Boot 어플리케이션 메모리 설정

ECS에서 Java 애플리케이션을 운영할 때, JVM Heap을 얼마나 잡아야 하는지 정리합니다. 컨테이너 환경의 메모리 구조 기존 서버 환경에서는 OS가 물리 메모리를 먼저 차지하고, 나머지를 JVM이 사용했습니다. [VM/서버] 물리 메모리 → OS 커널 + 시스템 프로세스 → JVM ECS 컨테이너는 다릅니다. 호스트 OS 커널을 공유하기 때문에, Task에 할당된 메모리를 OS 몫 없이 컨테이너가 사용할 수 있습니다. 사이드카가 있으면 여러 컨테이너가 나눠 쓰지만, 이 문서에서는 메인 컨테이너만 있는 경우를 다룹니다. [ECS Task] Task 메모리 ≈ JVM 전용 “OS 몫을 남겨야 한다"는 상식은 컨테이너 환경에서는 불필요합니다. Fargate든 EC2든 Task 내부의 메모리 설정은 동일합니다. ...

2026년 2월 11일

AWS ECS Task 메모리 설정

ECS에서 메모리 설정은 Task, Container, Application(JVM 등) 3개 레벨로 나뉩니다. 각 레벨이 어떻게 동작하는지 정리합니다. 메모리 설정의 3개 레벨 Task 메모리 (Task에 할당된 전체 메모리) └→ Container 메모리 (프로세스별 할당) └→ Application 메모리 (JVM Heap 등) 레벨 설정 위치 역할 Task 메모리 Task Definition 전체 메모리 한도 Container 메모리 Task Definition > containerDefinitions 컨테이너별 메모리 한도 Application 메모리 JVM 옵션 (-Xmx 등) 애플리케이션 내부 메모리 Application 레벨(JVM 메모리 설정)은 AWS ECS에서 Java + Spring Boot 어플리케이션 메모리 설정 에서 다룹니다. ...

2026년 2월 10일

컨테이너 기초 용어 정리

물리 서버, 가상 머신 (VM), 컨테이너. 서버 환경이 어떻게 변해왔는지, 컨테이너 관련 용어들의 관계를 정리합니다. 서버 환경의 변천 물리 서버 → VM → 컨테이너 물리 서버와 VM은 사용자 입장에서 거의 동일합니다. OS 설치하고, Java 설치하고, jar 배포하고. 차이는 하드웨어를 직접 만지느냐, 콘솔에서 클릭하느냐 정도입니다. 패러다임이 바뀌는 건 VM → 컨테이너 구간입니다. 컨테이너의 구조 기존 서버 환경 (물리 서버 / VM) Application (jar) Java (JDK) OS (Linux) ───────────── 물리 서버 / VM 기존 서버 환경은 각 계층을 하나하나 직접 설치합니다. ...

2026년 2월 9일

데이터 저장소 용어 정리

데이터베이스, 데이터웨어하우스, 데이터레이크, 데이터레이크하우스. 비슷해 보이지만 각각 목적과 특성이 다릅니다. 한눈에 비교 구분 데이터베이스 데이터 웨어하우스 데이터 레이크 데이터 레이크하우스 목적 운영/트랜잭션(OLTP) 분석(OLAP) 원시 데이터 저장 분석 + 저장 통합 데이터 형태 구조화 구조화 비구조화/반구조화 모두 지원 스키마 Schema-on-Write Schema-on-Write Schema-on-Read 둘 다 가능 ACID O O X O 쿼리 패턴 단건 읽기/쓰기 대량 집계/분석 배치 처리 대량 집계/분석 실시간성 실시간 준실시간~배치 배치 준실시간~배치 대표 제품 MySQL, PostgreSQL Snowflake, Redshift, BigQuery S3, HDFS Databricks 용어 유래 Database: Data + Base(기지) → 데이터를 저장하고 관리하는 기본 시스템 Data Warehouse: Data + Warehouse(창고) → 정리된 물건을 체계적으로 보관 Data Lake: Data + Lake(호수) → 모든 물이 흘러드는 호수 Data Lakehouse: Data + Lake + House (Databricks가 2020년 제안한 신조어) “Data Lake Warehouse"가 아닌 이유? 단순히 둘을 붙여 쓰는 게 아니라, 새로운 패러다임임을 강조하기 위해서입니다. ...

2026년 1월 21일

Kotlin의 접근 제어자 설계 철학

Java package-private 클래스를 Kotlin 테스트 코드에서 접근하려니 생성자 호출이 안 되어 reflection을 써야 했습니다. 왜 이런 문제가 발생할까요? Java와 Kotlin 접근 제어자 비교 Java public: 전체 protected: 상속 + 같은 패키지 (default): 같은 패키지 private: 같은 클래스 Kotlin public: 전체 internal: 같은 모듈 protected: 상속 관계만 private: 같은 클래스 (클래스 멤버) / 같은 파일 (최상위 선언) 핵심 차이 Java Kotlin 캡슐화 단위 패키지 모듈 테스트 접근 같은 패키지 필요 같은 모듈이면 OK package-private 있음 없음 (internal로 대체) protected 상속 + 같은 패키지 상속만 Kotlin의 설계 철학 패키지는 캡슐화 경계가 아니다 // 원래 라이브러리 (example-lib.jar) package com.example.core; class InternalClass { // package-private void sensitiveMethod() { } } // 악의적 사용자 코드 (다른 프로젝트) package com.example.core; // 같은 패키지명 사용 public class Hacker { void access() { new InternalClass(); // package-private인데 접근됨 } } 패키지는 코드 조직화 수단일 뿐, 실제 캡슐화는 컴파일/배포 단위인 모듈에서 이루어져야 합니다. ...

2026년 1월 13일

Hugo 댓글 - giscus 적용

Hugo 블로그에 GitHub Discussions 기반 댓글 시스템 giscus를 적용합니다. 사전 준비 GitHub 공개 저장소 준비 해당 공개 저장소에 Discussions 활성화: Settings → General → Features → Discussions giscus 앱 설치 후 저장소 선택 giscus 설정 https://giscus.app 접속 저장소와 원하는 옵션 선택 생성된 스크립트 코드 복사 Hugo 적용 댓글 파일 생성 <!-- layouts/partials/comment.html --> // 스크립트 코드 설정 파일 수정 # hugo.toml [params] comments = true

2025년 12월 3일

블록킹/논블록킹, 동기/비동기 개념 정리

블록킹/논블록킹은 제어권 반환 시점의 차이이고, 동기/비동기는 결과 확인 주체의 차이입니다. 블록킹 vs 논블록킹 구분 기준: 제어권을 바로 돌려주는가? 블록킹: 작업 완료까지 제어권을 돌려주지 않음 논블록킹: 작업 요청 후 바로 제어권 반환 동기 vs 비동기 구분 기준: 결과를 누가 확인하는가? 동기: 요청한 쪽이 결과를 직접 확인 비동기: 결과가 준비되면 콜백으로 알려줌 핵심 구분 구분 질문 블록킹 논블록킹 제어권 기다리는 동안 다른 일 할 수 있어? 못함 (멈춤) 가능 (안 멈춤) 구분 질문 동기 비동기 결과 확인 결과를 내가 확인해? 알려줘? 내가 확인 알려줌 C 디바이스 I/O 예제 블록킹 I/O int fd = open("/dev/device", O_RDONLY); char buf[1024]; // 데이터 올 때까지 멈춤 int result = read(fd, buf, 1024); // 여기 도달 = buf 채워짐 보장 printf("읽음: %s", buf); 동작: ...

2025년 11월 28일

Apache Kafka 기본 개념 정리

Apache Kafka의 핵심 개념과 동작 원리를 정리합니다. 아키텍처 Kafka Cluster (여러 Broker의 집합) │ └─ Broker (카프카 서버, 여러 대 가능) │ └─ Topic (메시지 종류) │ ├─ Partition 0 ──┐ ├─ Partition 1 ──┼── Consumer Group A ─┬─ Consumer 1 └─ Partition 2 ──┘ ├─ Consumer 2 │ └─ Consumer 3 │ └──────────── Consumer Group B ─── Consumer 1 구성 요소 Broker: Kafka 서버 (여러 대로 클러스터 구성) Topic: 메시지 종류별 논리적 그룹 Partition: 토픽 내 병렬 처리 단위 Consumer Group: 동일 group.id로 묶인 컨슈머들 설계 시 고려사항 파티션 수 = 최대 병렬 처리 수 파티션 수 ≥ 컨슈머 수 (컨슈머가 더 많으면 일부는 idle) 용어 정리 ← 여기 동작 일반 메시지 큐 Kafka 메시지 보내기 Publish Produce 보내는 주체 Publisher Producer 토픽 구독 Subscribe Subscribe (동일) 메시지 받기 Push (서버가 보냄) Poll (주기적으로 가져감) 받는 주체 Subscriber Consumer 메시지 흐름 Producer ──produce──▶ Kafka Broker ◀──poll── Consumer │ ▼ consume 처리 로직 동작 방식 Producer가 메시지 전송 Broker가 파티션에 메시지 저장 Consumer가 주기적으로 폴링 새 메시지 있으면 가져와서 처리 메시지 관리 Offset 관리 Offset: 파티션 내 메시지 위치 (0부터 시작) Committed Offset: 처리 완료한 마지막 위치 Latest Offset: 파티션의 마지막 메시지 위치 Consumer Lag: Latest - Committed (처리 지연 정도) Commit 전략 // 자동 커밋 (기본값) enable.auto.commit=true auto.commit.interval.ms=5000 // 수동 커밋 consumer.commitSync(); consumer.commitAsync(); 메시지 전달 보장 At-most-once 처리 전 commit 장점: 중복 없음 단점: 메시지 유실 가능 At-least-once (기본값) 처리 후 commit 장점: 메시지 유실 없음 단점: 중복 처리 가능 중요: 애플리케이션 레벨에서 멱등성 보장 필요 Exactly-once 트랜잭션 사용 장점: 중복도 유실도 없음 단점: 성능 오버헤드 메시지 보관 일반 메시지 큐와 달리 Kafka는 consume 후에도 메시지 보관: ...

2025년 11월 27일