콘텐츠 타입
Notes
오래 참고할 수 있도록 정리한 기술 노트와 해설 글입니다.
- Datadog 대안 10선을 전부 꽂아 봤다: 셋은 떴고 넷은 키만 남았고 둘은 축이 달랐다
- 빈 화면의 원인은 매번 달랐다: APM 여섯 개를 띄우며 막힌 자리들
- 빅테크는 APM을 사지 않고 만들었다: Dapper에서 OpenTelemetry 졸업까지
- APM 도구 여섯 개를 직접 붙여 봤다: 에이전트 비용은 날마다 9%와 19% 사이였다
- APM 용어 정리: Observability, Telemetry부터 Span, Exemplar까지
- APM 도구 비교: Datadog부터 Pinpoint, OpenTelemetry까지
- Valkey - Redis 라이선스 변경에서 갈라진 포크와 그 뒤의 2년
- 섬유 공장에 API를 붙이면: 제조를 클라우드처럼 쓰는 구상
- 모두의 창업 로컬트랙 지원기: 1라운드 통과와 2차 요건검토 준비
- ParityPay로 검증하는 결제 정합성 12 - 실험 41종이 못 밟는 경로를 모델 검사가 5단계 만에 찾았다
- ParityPay로 검증하는 결제 정합성 11 - 지터는 언제 값을 하는가: 봉우리를 만들어야 보이는 것
- ParityPay로 검증하는 결제 정합성 10 - 락 lease가 트랜잭션보다 먼저 끝나면 정말 정합성이 깨지는가: SETNX 락, Watchdog, fencing token, 그리고 락 없는 구조의 실측
- 무너지는 Spring 서버 1 - CPU는 놀고 있는데 API가 느리다: 업스트림 하나가 무관한 엔드포인트를 죽이는 과정을 thread dump 세 장으로 읽기
- ParityPay로 검증하는 결제 정합성 9 - 느린 기관 앞에서 결제 서버를 지키기: 타임아웃, 재시도, 차단기, 리미터, 벌크헤드가 각각 무엇을 막는가
- ParityPay로 검증하는 결제 정합성 8 - Kafka에서 중복·유실·순서 역전을 직접 만들어 보기: 멱등 소비자와 Outbox가 막는 것과 못 막는 것
- ParityPay로 검증하는 결제 정합성 7 - 애플리케이션 코드를 믿지 않는 원장: 이중부기를 계정 체계, DB 제약, 속성 테스트로 강제하기
- ParityPay로 검증하는 결제 정합성 6 - 대사: "기관에 물어보지 못했다"와 "기관에 기록이 없다"는 다른 상태다
- CDC의 원리와 한계 - 로그 기반 변경 포착, 초기 스냅샷, 스키마 변경
- ProofU 초기 설계 - 근거를 추적하는 지원 문서 시스템과 기술 선택의 이유
- ParityPay로 검증하는 결제 정합성 5 - DB 커밋과 Kafka 발행 사이: Transactional Outbox와 at-least-once 소비자
- ParityPay로 검증하는 결제 정합성 4 - 실험 27종이 찾아낸 결함 12건: 문서와 코드를 읽어서 나온 것은 하나도 없었다
- ParityPay로 검증하는 결제 정합성 3 - 외부 승인 응답이 사라졌을 때: 타임아웃은 실패가 아니다
- ParityPay로 검증하는 결제 정합성 2 - 잠금을 필요 이상으로 오래 쥐고 있었다: 추론을 측정으로 바꾼 기록
- TLS 핸드셰이크의 비용 - 세션 재개와 0-RTT의 대가
- ParityPay로 검증하는 결제 정합성 1 - 장애가 나도 지켜야 할 금융 불변조건 여섯 가지
- NIO와 이벤트 루프 - 셀렉터, 다이렉트 버퍼, Netty가 대신 해주는 일
- ParityPay 초기 설계 - 돈의 규칙은 PostgreSQL에 두고, 나머지 기술은 그 규칙을 돕는 자리에 두기
- CodeDrill 초기 설계 - 판정을 신뢰 경계 밖으로 떼어 낸 온라인 저지와 그 스택을 고른 이유
- 타임아웃, 재시도, 백오프 - 증폭과 지터, 그리고 데드라인 전파
- 커넥션과 세션 - 커넥션 풀이 실제로 아끼는 것
- SysDrill 초기 설계 - 실제 인프라 없이 장애 대응을 훈련시키는 백엔드의 첫 구조
- HTTP/1.1, 2, 3 - HOL 블로킹은 어디로 옮겨갔는가
- 클래스 로딩과 기동 시간 - 리플렉션의 비용과 AOT가 바꾸는 것
- Claude Code를 개인 워크벤치처럼 쓰는 방법
- 큐잉 이론 한 조각 - 도착률과 서비스율로 파라미터를 정하기
- spring-internals-lab로 다시 읽는 Spring 1 - 이 프로젝트는 무엇을 검증하려는가
- spring-internals-lab로 다시 읽는 Spring 7 - @Transactional의 실체
- spring-internals-lab로 다시 읽는 Spring 9 - Spring Boot는 무엇을 자동으로 조립하는가
- spring-internals-lab로 다시 읽는 Spring 3 - refresh()와 Bean 생성 파이프라인
- spring-internals-lab로 다시 읽는 Spring 6 - 프록시와 AOP
- spring-internals-lab로 다시 읽는 Spring 8 - DispatcherServlet과 MVC 요청 흐름
- spring-internals-lab로 다시 읽는 Spring 4 - 의존성 주입과 후보 선택
- spring-internals-lab로 다시 읽는 Spring 5 - Bean lifecycle과 후처리기
- spring-internals-lab로 다시 읽는 Spring 2 - BeanDefinition과 등록 단계
- 파티셔닝과 샤딩 - 기준 선택, 로컬과 글로벌 인덱스, 재분배 비용
- 순서와 격리는 같은 자원을 반대로 당긴다 - 핫 키가 워커 하나를 넘는 순간 세 설계가 갈라지는 지점
- API 버저닝과 호환성 - 스키마 진화 규칙
- 혼잡 제어와 지연 - BDP, 버퍼블로트, 처리량과 지연의 교환
- 리액티브와 백프레셔 - WebFlux가 해결하는 것과 옮기는 것
- 직접 만든 마이크로벤치마크는 얼마나 틀리는가 - 결함 넷을 하나씩 재봤다
- iterview 초기 설계 - 이력서 기반 면접 훈련 플랫폼의 구조와 기술 선택
- JIT 컴파일 - 계층 컴파일, 인라이닝, 역최적화
- CPU 프로파일러가 1순위로 지목한 코드를 고쳤더니 아무 일도 없었다
- 분산 트랜잭션 - 2PC와 Saga, 보상 트랜잭션이 실패하는 방식
- WAL과 체크포인트 - 커밋은 언제 디스크에 닿는가
- spring-lite로 이해하는 Spring 구현 5 - MiniSpringApplication과 자동 설정 조립 방식
- spring-lite로 이해하는 Spring 구현 4 - DispatcherServlet과 MVC 요청 처리 파이프라인
- 모듈러 모놀리스 - 경계를 코드로 강제하는 방법
- spring-lite로 이해하는 Spring 구현 3 - ProxyFactory, @Transactional, JdbcTemplate 연결
- spring-lite로 이해하는 Spring 구현 2 - AnnotationConfigApplicationContext로 보는 IoC와 생명주기
- spring-lite로 이해하는 Spring 구현 1 - 프로젝트 구조와 설계 범위
- 시크릿 관리 - 로테이션과 주입 경로
- 가상 스레드를 켜서 37배 느려진 엔드포인트 - 핀닝과 상한 없는 admission을 재다
- 트레이스 샘플링 - 헤드와 테일 샘플링의 선택 기준
- TCP 연결 수립과 큐 - SYN 백로그, accept 큐, TIME_WAIT
- Security 필터 체인 - 인증과 인가는 실제로 어디에 꽂히는가
- G1과 ZGC가 p99에 남기는 차이 - 300배 짧은 pause가 꼬리의 11%를 가져갔다
- GC 알고리즘 비교 - G1, ZGC, Shenandoah가 각자 무엇을 포기하는가
- 로그 컴팩션과 보존 - 상태 토픽이 보장하는 것과 하지 않는 것
- 멱등성 설계 - 키의 단위와 저장 위치, 만료와 재시도 계약
- 락의 종류와 대기 - row, gap, next-key, intention과 데드락 탐지
- 이벤트 소싱과 CQRS - 언제 비용이 이익을 넘는가
- CORS와 CSRF - 브라우저가 막는 것과 서버가 막아야 하는 것
- RED와 USE - 어디에 무엇을 붙이는가
- epoll - select, poll과의 차이와 edge, level 트리거
- Spring Batch의 구조 - 청크, 파티셔닝, 재시작과 메타데이터
- 가상 스레드의 내부 - 스케줄러와 캐리어, 핀닝, 그리고 쓰지 않아야 할 때
- Redis 단일 스레드가 멈추는 순간 - SCAN이 3.7배 오래 걸리면서 아무도 막지 않고, 120ms 멈춤이 p99에 안 잡히는 이유
- 전달 보장 - at-most-once, at-least-once, exactly-once가 각각 무엇을 약속하는가
- 시간과 순서 - 물리 시계의 한계, 논리 시계, 하이브리드 시계
- 실행 계획을 읽는 법 - 연산자, 비용 모델, 카디널리티 추정이 틀어지는 지점
- 주니어 백엔드 개발자가 실무에서 자주 부딪히는 질문들
- GitHub 블로그를 에이전틱 AI와 함께 운영하기
- REST, gRPC, GraphQL - 선택 기준과 각자가 내는 비용
- 비밀번호 저장 - bcrypt와 argon2의 파라미터를 정하는 기준
- 캐시 스탬피드와 single flight - 200명 중 125명이 원본까지 갔고, 예외를 삼키자 실패가 가장 빠른 요청이 됐다
- RESP, Reactor, Command Registry로 보는 Redis 요청 처리 흐름
- redis-lite-java로 이해하는 Redis 아키텍처 개요
- MemoryDb, TTL, Hash 구조로 보는 Redis keyspace 설계
- MULTI, Pub/Sub, Lua로 보는 Redis 확장 기능과 구현 과정
- 백분위 통계 - 평균이 거짓말하는 이유와 히스토그램의 집계 오류
- 페이지 캐시와 파일 IO - buffered와 direct, fsync가 실제로 하는 일
- 프록시의 한계 - self-invocation, final, JDK와 CGLIB의 선택
- 동시성 도구의 비용 - synchronized, ReentrantLock, CAS가 경쟁에서 갈리는 지점
- Postgres 커넥션 하나의 비용 - 풀을 키우면 대기가 사라지는 게 아니라 볼 수 없는 곳으로 옮겨간다
- 컨슈머 그룹과 리밸런스 - eager, cooperative, static membership
- Netty
- 합의 알고리즘 - Raft를 상태 기계로 읽기
- B+Tree 인덱스의 내부 - 노드 분할, 클러스터드와 논클러스터드, 커버링이 아끼는 것
- 멱등한 API 설계 - HTTP 메서드의 의미와 재시도 계약
- 인덱스가 선택되지 않는 순간 - 컬럼에 캐스팅 하나가 3,000배, 그리고 추정이 31.7배 틀려도 계획이 안 바뀌는 경우
- 대용량 파일 업로드를 위한 Presigned URL
- JWT의 구조와 검증 - 서명 알고리즘, 만료, 그리고 폐기의 한계
- 2021년의 결제대행 API 연동을 2026년의 질문으로 다시 보기
- 메트릭, 로그, 트레이스 - 무엇을 어디에 남기고 카디널리티는 어디서 터지는가
- 컨텍스트 스위칭과 스케줄링 - CFS, cgroup CPU 제한, 그리고 스로틀링
- 트랜잭션 전파 7종 - 각 옵션이 커넥션과 롤백에 남기는 결과
- 키 생성 병목을 추적해 구조를 바꾼 기록: Part 3 - 채번을 INSERT 시점으로 옮기고 범위 단위로 받기
- 격리 수준의 이상 현상을 직접 만들기 - 같은 REPEATABLE READ에서 PostgreSQL은 중단시키고 MySQL은 조용히 덮어썼다
- 자바 메모리 모델 - happens-before, volatile, 그리고 final의 안전 공개
- Kafka의 저장 구조 - 세그먼트와 오프셋, 페이지 캐시와 zero-copy
- 키 생성 병목을 추적해 구조를 바꾼 기록: Part 2 - SELECT 안에서 UPDATE가 일어나고 있었다
- 일관성 모델 - 선형화, 순차, 최종 일관성, 그리고 CAP를 설정값의 언어로
- 격리 수준과 이상 현상 - 표준이 정의한 것과 MySQL·PostgreSQL이 실제로 하는 것
- 키 생성 병목을 추적해 구조를 바꾼 기록: Part 1 - 2분짜리 계약 생성과 SELECT 한 줄
- 대량 배치 안정성을 높이기 위한 구조 개선: Part 5 - 배타적 락과 조건부 해제로 순서를 보장하기
- 대량 배치 안정성을 높이기 위한 구조 개선: Part 4 - 분산 락이 있어도 레이스가 발생한 이유
- 대량 배치 안정성을 높이기 위한 구조 개선: Part 3 - 청크 분할과 병렬 처리로 등록 파이프라인 재설계하기
- 대량 배치 안정성을 높이기 위한 구조 개선: Part 2 - 전체 삭제 후 전체 등록 구조의 위험성
- 대량 배치 안정성을 높이기 위한 구조 개선: Part 1 - 시스템을 압박하기 시작한 배치
- 실행하지 않은 재설계: 권리이관 시스템의 요청 모델을 3계층으로 나누자는 제안
- 위반 480건 위에 아키텍처 규칙을 도입하기: 신규 코드는 100% 강제, 레거시는 점진 정리
- 대량 배치 안정성을 높이기 위한 구조 개선: Part 0 - 왜 이 배치는 가끔 터질까?
- Creator-Producer 매핑 장애 대응: DML 대신 애플리케이션 흐름으로 복구한 이유와 확정하지 못한 원인
- Heap Dump가 가리킨 곳은 데이터가 아니라 영속성 컨텍스트였다: Tasklet에서 Chunk로, XSSF에서 SXSSF로
- refresh 이후에도 옛 access token이 통과하던 문제: TTL과 폐기는 다른 문제다
- Shadow Release로 조회를 옮기기: MyBatis 결과와 QueryDSL 결과를 나란히 비교하며 전환한 기록
- 감사 로그 표준화와 ISMS 대응: MDC와 ELK로 누가, 언제, 무엇을 했는지 추적하기
- Bulkhead Pattern
- 모든 도메인이 100% 정합성을 요구하지는 않는다: Post-Commit 이벤트와 재시도 3회 정책을 정한 기준
- 유통사가 늘 때마다 복사되던 File Observer 구현체 정리: 제네릭을 걷어낸 Base 클래스와 DB 기반 권리사 ID
- 엑셀로 처리하던 계약 갱신과 라이선스 변경을 Spring Batch와 Jenkins로 옮긴 기록
- 폴링 배치를 SQS 이벤트 파이프라인으로 바꾼 이유: 재시도, DLQ, 메시지 ID 멱등
- 같은 음원이 여러 유통사에서 들어올 때: 콘텐츠 유니피케이션 시스템을 운영하며 정리한 구조
- 정산이 진행되는 동안 기준 데이터 수정을 막는 방법: 상태 플래그와 AOP로 만든 경량 락
- Map 기반 입력을 DTO와 3단계 검증으로 바꾸기: Bean Validation, 매핑, 도메인 규칙
- 화면 단위 API를 도메인 책임 단위로 다시 나누기: 응답 1.5초에서 300ms까지
- 8천만 곡 규모 음원 데이터와 온프레미스에서 AWS로의 점진 전환: 참여자로 본 것
- 단위 테스트와 통합 테스트를 어떻게 구분해야 할까
- 테스트 코드는 왜 작성해야 할까?
- Single Flight
- Error Handling in HTTP APIs
- Redis Sentinel Replication
- Redis Cache Best Practices
- Redo Log와 Undo Log를 어떻게 구분해야 하는가
- 데이터베이스 리플리케이션 기본 정리
- 데이터베이스 트랜잭션을 어떻게 봐야 하는가
- ACID를 실무적으로 이해하기
- Preventing Cache Write Amplification under High Concurrency
- Resolve Git Conflicts
- Problem Details for HTTP APIs
- @RestController는 무엇을 의미하는가
- @SpringBootApplication은 실제로 무엇을 하는가
- Spring Boot DevTools를 언제 써야 하는가
- MVCC를 어떻게 이해해야 하는가
- Gap Lock
- Evolution of Java: Version-by-Version Breakdown
- Understanding HTTP Versions: From 0.9 to 3.0
- Process and Thread
- Multiplexing
- Multithreading
- Inside ArrayList: Capacity Expansion Mechanism
- Java의 Garbage Collection을 어떻게 이해해야 할까
- Stateless(무상태)가 Idempotent(멱등성)을 의미하는가?
- State in REST API
- Microservice Architecture
- Spring Bean Lifecycle 정리
- Floating Point
- 부동소수점 오차는 왜 발생하는가
- Java에서 static은 무엇을 의미하는가
- equals()와 hashCode()를 함께 오버라이드해야 하는 이유
- Stateful vs Stateless
- Function Signature
- WEB 3.0
- WEB 3.0 지갑
- What is NFT?
- 민주주의 = 탈중앙화라고 볼 수 있는가?
- 대용량 지분율 데이터 처리 성능 개선과 동시성 제어 전략
- 무거운 엑셀 다운로드 요청을 사전에 판별하는 방법
- 대용량 엑셀 다운로드 요청을 안정적으로 처리하는 방법
- 대량 엑셀 다운로드를 메시지 큐와 S3 사전 생성으로 나누는 설계
- 테이블과 데이터만 남은 외주 시스템을 리뉴얼한 과정: 음원 유통 시스템(MDS)
- ISMS 대응을 위한 로그 수집 체계 개선
- 백엔드 시스템 로깅 베스트 프랙티스
- MCP 전면 개편기: 판단 로직의 자리를 정하고 ArchUnit으로 지키기
- MCP 전면 개편기: 화면 단위 API를 도메인 책임 API로 옮기기
- MCP 전면 개편기: MyBatis와 JPA 공존 환경의 데이터 정합성 전략
- MCP 전면 개편기: 계약 코드 채번의 락 경합을 줄여 2분을 10초로
- MCP 전면 개편기: Map 입력을 DTO와 3단계 검증으로 바꾸기
- 크리에이터 스튜디오 개요: 외부 연동 분리, 감사 로그, 토큰 세션, 매핑 장애에서 내린 판단
- 조건 기반 예측 캐싱: 고속 엑셀 다운로드 처리 구조 설계
- Load Balancing Algorithms
- @TransactionalEventListener 빠른 체크 노트
- 헬퍼 클래스는 안티패턴일까?
- 콜백(callback)
- 백엔드 개발자: 데이터 흐름의 설계자
- Spring에서 이해해야 할 JPA 아키텍처
- 데이터베이스 페이징 성능을 어떻게 봐야 하는가
- 캐시 스탬피드(Cache Stampede)
- CPU부터 CDN까지: 모든 계층에서의 캐싱
- 응집도와 결합도에 관하여: About Cohesion and Coupling
- Java 진화의 두 축 JEP vs JSR
- Jakarta EE 기업용 Java의 진화
- 왜 이벤트가 안 먹히지? @TransactionalEventListener가 무시되는 이유와 해결법
- Spring에서 Java 21을 도입할 때 체크할 것
- Java 21 Features
- The Hidden Evolution of Java Strings
- Integer.toString(int) vs String.valueOf(int) vs "" + int
- ADR(Architecture Decision Record) - 결정의 맥락을 결정과 함께 남기기
- JMX와 MBean, 그리고 Micrometer가 지표를 얻는 길 - MBean이 없으면 지표는 0이 아니라 없다
- 세마포어와 permit - 동시에 몇 개까지 들일지를 세는 도구, 그리고 벌크헤드
- thread dump 읽는 법 - 스레드 상태와 스택 프레임, 그리고 RUNNABLE이 CPU를 쓴다는 뜻이 아닌 이유
- 모델 검사 입문 - TLA+, TLC, 상태 공간, 불변조건, 반례
- Lock-Free와 CAS - 락 없이 공유 변수를 바꾸는 방법과 그 한계
- 프로세스는 왜 멈추는가 - GC, 페이지 폴트, CPU 경합, SIGSTOP, VM 정지와 스스로 알 수 없는 멈춤
- 읽기 수리, 쓰기 수리, 비동기 수리 - 최종 일관성은 누가 언제 맞추는가
- 사용자 공간과 커널 공간 - 시스템 콜, 복사, sendfile과 kTLS
- TLS 키 교환과 암호 스위트 - key share, forward secrecy, PSK, AES-NI
- 다이렉트 메모리와 Cleaner - 힙 밖의 버퍼는 누가 언제 해제하는가
- MIME(Multipurpose Internet Mail Extensions)
- Reverse Proxy
- HikariCP
- Apache vs Tomcat
- ELB vs ALB vs NLB
- Network Load Balancers(NLB)
- Keep-Alive
- Single Sign-On
- Session and JWT
- Preflight Request
- OpenID Connect
- Log4j Vulnerability
- Log4j vs Logback vs Log4j2
- Log Level
- Large List Rendering Issue
- JWT vs Opaque Token
- GraphQL
- GraphQL with Spring Boot
- Connection Pool
- Microservice Architecture
- Querydsl을 사용하는 이유와 기본 패턴
- Spring 애플리케이션에서 페이지네이션을 설계하는 방법
- Spring의 IoC와 DI를 어떻게 이해할 것인가
- Spring과 JPA에서 Race Condition을 다루는 방법
- Filter, Interceptor, AOP의 차이와 선택 기준
- Spring 애플리케이션에서 예외를 설계하는 방법
- Spring 예외 처리 전략 정리
- Spring Data JPA에서 동적 쿼리를 다루는 방법
- @ControllerAdvice와 @RestControllerAdvice 정리
- Spring AOP 핵심 정리
- Statement와 PreparedStatement는 무엇이 다른가
- JVM은 무엇을 하는가
- 점 이력과 선분 이력 모델링
- 데이터베이스 인덱스를 어떻게 이해해야 하는가
- Token Authentication
- Thread Local
- Synchronous, Asynchronous, Blocking, Non-Blocking
- Serialization and Deserialization
- Pure Function
- Programming Paradigm
- Object-Oriented Programming(OOP) and Functional Programming(FP)
- Lambda
- JavaScript setTimeout()
- Higher-order Function
- Garbage Collectors
- Garbage Collection(GC)
- Choosing the Best Garbage Collector: G1GC vs ZGC
- Exception Handling
- Java Concurrency
- Closure
- SSL/TLS
- Apache Zookeeper
- Spring AMQP
- Shell Script
- Reverse Proxy
- RabbitMQ
- RabbitMQ with Spring Boot
- RabbitMQ Installation
- Message Queue
- Circuit Braker
- Transaction
- System Structure & Program Execution
- MultiThreading and Thread Scheduling
- JANDI와 AWS CodeCommit 연동
- Increasing System Performance in MultiProcessing
- Concurrency Control
- AWS Code Commit
- Apache POI SXSSF vs XSSF vs HSSF
- Introduction to Operating System
- Redis Cluster vs Sentinel
- Authorization
- Authentication
- Facade
- Microservices Architecture
- Unique ID Generation Strategy in Distributed Systems
- Spring Boot에서 외부 API 연동을 설계할 때 보는 것
- 배열을 데이터베이스에 저장할 때 무엇을 먼저 판단해야 하는가
- SOLID 원칙을 실무적으로 어떻게 이해해야 하는가
- Java에서 this와 super는 언제 어떻게 써야 하는가
- 객체, 클래스, 인스턴스는 어떻게 구분해야 하는가
- 상속과 다형성은 어떻게 연결되는가
- Java에서 객체 비교를 어떻게 해야 하는가
- 빅 오(Big-O)와 시간복잡도를 어떻게 봐야 하는가
- 단일, 이중, 환형 연결 리스트는 어떻게 다른가
- LinkedList로 Queue를 구현할 때 핵심은 무엇인가
- LinkedList로 Deque를 구현할 때 알아야 할 것
- 배열과 연결 리스트는 언제 차이가 커지는가
- Java에서 배열과 리스트를 어떻게 구분해야 하는가
- Git
- Maven Dependencies를 가져오지 못할 때 어디부터 봐야 하는가
- Git의 기본을 어떻게 이해해야 하는가
- C++의 vector를 어떻게 이해해야 하는가
- 순열(Permutation)
- 동적 계획법(Dynamic Programming)
- 재귀(Recursion)
- 그래프(Graph)
- 깊이 우선 탐색(DFS)
- 연결 요소(Connected Component)
- 너비 우선 탐색(BFS)