Debugging False Sharing

이 글은 넷플릭스 테크 블로그의 Seeing through hardware counters: a journey to threefold performance increase를 제가 이해한 대로 요약하고, 관련 배경 지식을 나름대로 정리해 덧붙인 글입니다. 원문이 정확한 출처이니, 구체적인 수치나 세부 사항이 궁금하시다면 반드시 원문을 확인해주세요. 문제 발생 넷플릭스가 운영하던 어떤 서비스가 CPU 부족을 겪어서, 노드 스펙을 3배로 늘리는 scale-up을 진행했습니다. CPU-intensive한 워크로드였으니 처리량도 그에 비례해서 늘어날 거라 기대했지만, 실제로 개선된 폭은 25% 남짓이었습니다. 심지어 tail latency는 오히려 더 나빠졌습니다. ...

2025년 12월 12일 · 4 분 · Donghyung Ko

Spinlock vs Mutex

락을 구현하는 방식은 크게 두 갈래로 나뉩니다. 유저 공간에서 CPU 명령어만으로 도는 Spinlock과, 커널의 도움을 받는 Mutex입니다. 둘 다 결국 상호 배제(mutual exclusion)를 보장한다는 목적은 같지만, 내부 동작 방식이 다르기 때문에 적합한 워크로드도 갈립니다. Spinlock Spinlock은 유저 공간(userspace)에서 구현되는 락입니다. 동작 방식은 단순합니다. CAS(Compare-And-Swap) 연산이 성공할 때까지 무한히 반복합니다. while (!CAS(lock, 0, 1)) 대부분의 CPU는 이런 CAS 연산을 위한 전용 명령어를 갖고 있습니다. x86이라면 LOCK CMPXCHG가 여기에 해당합니다. 문제는 이 CAS 연산이 성공하려면 해당 캐시 라인에 대한 독점적인 쓰기 권한이 필요하다는 점입니다. 이 권한을 얻는 과정에서 CPU 코어 사이에 캐시 일관성 프로토콜이 개입하고, 캐시 라인의 소유권을 주고받는 과정에서 잦은 invalidation, 이른바 캐시 라인 바운싱이 발생합니다. 이 과정은 보통 40~80ns 정도 걸립니다. ...

2025년 12월 12일 · 4 분 · Donghyung Ko
Visualization used in the SwissTable explanation

Inside Google’s Swiss Table: A High-Performance Hash Table Explained EN

Swiss Tables: A Modern, High-Performance Hash Table Swiss Table is a high-performance hash table design introduced by Google engineers in 2017. It has since inspired many standard-library implementations across languages, including: Go 1.24 ships its map with this design (up to 60% faster) Rust’s standard HashMap has also moved from Robin Hood hashing to a Swiss Table-inspired layout. Datadog reported as much as 70% memory savings after migrating to Swiss Table Open Addressing, Briefly An open addressing hash table is one of the implementation methods for hash tables. Unlike separate chaining, which uses external data structures such as linked lists or trees, open addressing implements the entire hash table as a single contiguous array. ...

2025년 12월 10일 · 3 분 · Donghyung Ko

Accidental Quadratic Hashmap Iteration

이 글은 Rust hash iteration+reinsertion 글과 관련 Rust 이슈/PR을 제가 이해한 대로 정리한 글입니다. 원문이 정확한 소스이니, 정확한 내용은 원문을 확인해주세요. Rust의 HashMap에서 발생했던 흥미로운 버그를 하나 소개하려고 합니다. 겉보기에는 지극히 평범한 코드인데, 특정 조건이 갖춰지면 O(n)이어야 할 연산이 O(n²)으로 폭발합니다. 버그 재현 다음 코드를 보겠습니다. 첫 번째 해시맵(one)에 1부터 5,000,000까지의 값을 삽입한 뒤(T1), 그 해시맵을 순회하면서 두 번째 해시맵(two)에 값을 그대로 재삽입(T2)하는 것이 전부입니다. use std::collections::hash_set::HashSet; fn main() { println!("inserting..."); let mut one = HashSet::new(); for i in 1..5000000 { one.insert(i); } println!("reinserting..."); let mut two = HashSet::new(); for v in one { two.insert(v); } } T1과 T2 모두 원소를 하나씩 삽입하는 동작이니, 둘 다 O(n)이어야 할 것 같습니다. 그런데 실제로 실행해보면 T1은 예상대로 O(n)에 끝나지만, T2는 O(n²)에 가까운 시간이 걸립니다. 같은 일을 하는 코드인데 왜 이런 차이가 발생할까요? ...

2025년 12월 8일 · 4 분 · Donghyung Ko

SIMA: A Generalist AI Agent for 3D Virtual Environments

딥마인드가 2024년 발표한 SIMA(Scalable Instructable Multiworld Agent)는 3D 가상 환경 전용 범용 에이전트입니다. 화면 입력과 간단한 자연어 지시만 주어지면, 사람과 거의 같은 방식으로 3D 게임을 플레이합니다. 하나의 게임이 아니라 여러 게임을 SIMA가 흥미로운 지점은 특정 게임 하나에 특화된 봇이 아니라는 것입니다. 8개의 게임 스튜디오와 협업해 외계 행성을 탐사하는 No Man’s Sky, 자동화 공장을 짓는 Satisfactory, 북유럽 신화 기반 생존 크래프팅 게임 Valheim 등 9개 게임을 대상으로 학습했고, 처음 보는 게임에서도 사람의 지시를 이해하고 플레이할 수 있습니다. ...

2025년 11월 16일 · 3 분 · Donghyung Ko

Kubernetes Topology Aware Routing

EKS의 기본 서비스 라우팅은 클러스터 안에 있는 Pod들에게 트래픽을 무작위로, 혹은 라운드로빈 방식으로 분배합니다. 그러다 보니 요청이 다른 가용 영역(AZ)에 있는 Pod로 자주 전달되는데, AWS VPC에서는 AZ 간 데이터 전송에 과금이 붙기 때문에 이런 cross-AZ 트래픽은 비용 증가와 지연 시간 증가로 곧장 이어집니다. Kubernetes 1.24에서 도입된 Topology Aware Routing(TAR)은 바로 이 문제를 해결하기 위해 만들어진 기능입니다. Pod 간 통신이 발생할 때, 가능하다면 같은 AZ에 있는 Pod를 우선적으로 호출하도록 네트워크 정책을 조정합니다. ...

2025년 11월 14일 · 4 분 · Donghyung Ko

[KIP-932] Queues for Kafka

카프카의 파티션은 오랫동안 한 번에 하나의 컨슈머만 처리할 수 있다는 제약을 갖고 있었습니다. 그 결과 파티션 개수와 컨슈머 개수가 강하게 묶여 있었고, 처리량을 늘리려면 필요 이상으로 파티션을 쪼개야 하는 경우가 잦았습니다. 여러 컨슈머가 하나의 파티션을 나눠 처리하는 큐(queue) 스타일이 더 어울리는 워크로드도 분명 있는데, 기존 구조로는 그것을 흉내 내기가 어려웠습니다. KIP-932: Queues for Kafka는 공유 그룹(Share Group)이라는 새로운 그룹 유형을 도입해서 이 제약을 풀어냅니다. Share Group 공유 그룹은 기존 컨슈머 그룹의 대안으로 등장한 그룹 유형(share)입니다. 가장 큰 차이는 여러 컨슈머가 하나의 파티션을 동시에 공유할 수 있다는 점입니다. 그룹 안의 컨슈머 수가 토픽의 전체 파티션 개수를 넘어설 수도 있고, ack는 레코드 단위로 이루어지며, 메시지가 전달된 횟수도 함께 기록됩니다. ...

2025년 11월 13일 · 5 분 · Donghyung Ko

[KIP-848] The Next Generation of the Consumer Rebalance Protocol

카프카 4.0에서 GA된 KIP-848: The Next Generation of the Consumer Rebalance Protocol을 정리해봅니다. 컨슈머 그룹 멤버가 바뀌어도 downtime을 거의 없애는 것, 그리고 리밸런싱의 주요 책임을 클라이언트에서 브로커로 옮기는 것이 이 KIP의 핵심 목표입니다. 배경 도입된 지 8년이 지난 기존 컨슈머 그룹 리밸런싱 프로토콜은 몇 가지 구조적인 한계에 부딪힌 상태였습니다. 가장 큰 문제는 클라이언트에 지나치게 많은 역할을 부여한(thick client) 설계였습니다. 컨슈머 그룹 리밸런싱에 버그가 있으면 그 수정이 클라이언트 쪽에서 이뤄져야 하는데, 클라우드 서비스를 운영하는 입장에서는 사용자의 클라이언트를 강제로 고칠 수 없으니 이는 매우 까다로운 제약입니다. 대부분의 로직이 클라이언트에서 실행되다 보니, 문제가 생겨도 서버 쪽 로그만으로는 원인을 진단하기 어렵다는 점 또한 문제를 더 어렵게 만들었습니다. ...

2025년 11월 13일 · 5 분 · Donghyung Ko
Benchmark chart showing SIMD-accelerated JSON parsing performance

SIMD JSON: Unlocking Maximum Performance for JSON Deserialization EN

Limitations of Traditional Scalar State Machine Parsers The JSON parsing algorithms we commonly use are based on scalar state machine parsers. Scalar parsers read the input string byte by byte, parsing it through state transitions within the state machine. For example: When encountering a quotation mark ("), it indicates the start of a string. When encountering a colon (:), it indicates that a value is expected next. Below is a simplified pseudo-code representation of how a scalar parser works: ...

2025년 9월 22일 · 7 분 · Donghyung Ko
가상 메모리 주소를 물리 메모리 주소로 매핑하는 Page Table 구조

Linux Transparent Huge Pages

요약 대형 페이지(Huge Page) 기능을 활용하여 TLB 미스로 인한 오버헤드를 최소화할 수 있습니다. 워킹셋 크기가 크고(수십 MB 이상), 메모리 접근이 매우 빈번한 워크로드에서 유용한 최적화 기법입니다. 주로 데이터베이스 시스템과 관련된 레퍼런스(Oracle, Postgres, AWS RDS)가 많습니다. 대형 JVM 애플리케이션 하이퍼바이저(KVM/QEMU) 대규모 분석·검색 시스템(예: ClickHouse) CPU 및 I/O 바운드가 지배적인 워크로드에서는 별다른 효용이 없을 수 있습니다. 배경 모든 프로세스는 가상 메모리 주소 공간을 할당받습니다. 프로세스에서 가상 메모리 주소에 접근하면 CPU는 이를 실제 물리 메모리 주소로 치환하여 처리합니다. OS는 가상 메모리 주소를 물리 메모리 주소로 매핑하기 위한 Page Table을 관리합니다. ...

2025년 9월 16일 · 4 분 · Donghyung Ko