이 문서는 Apex Core 프레임워크의 핵심 컴포넌트 성능을 측정하고, 아키텍처 선택(Per-Core vs Shared, SPSC vs MPSC, 커스텀 할당기 vs malloc, zero-copy vs memcpy 등)의 방법론적 성능 차이를 20코어 환경에서 수치로 증명하는 벤치마크 보고서이다.

1
System Information
CPU
Intel Core i7-14700 (Raptor Lake Hybrid)
Cores
8 P-Core (Raptor Cove) + 12 E-Core (Gracemont) = 20C/28T
Clock
Base 2.1 GHz · P-Core Boost 5.4 GHz · E-Core Boost 4.0 GHz
Cache
L1D 48 KB · L2 2 MB (per-core) · L3 33 MB (shared)
RAM
64 GB
Version
v0.6.1
Date
2026-03-24
Compiler
MSVC, C++23, Release
Benchmark Lib
Google Benchmark v1.9.4
Benchmarks
14 files
테스트 환경: Intel Core i7-14700 — Raptor Lake 하이브리드 아키텍처. 8개의 Performance Core와 12개의 Efficiency Core로 구성된 20물리/28논리 코어 프로세서다.

하이브리드 아키텍처의 의미: P-Core와 E-Core의 IPC 차이로 인해, 멀티코어 벤치마크에서 워커 수가 8(P-Core 수)을 초과하면 OS가 E-Core에 스레드를 배정하기 시작한다. 이로 인해 처리량 그래프에 나타나는 변곡점은 소프트웨어 병목이 아닌 하드웨어 비대칭성을 반영하며, 균일 코어 서버 CPU에서는 해당 변곡점이 발생하지 않는다.
2
Architecture Comparison — Per-Core vs Shared io_context

Throughput Scaling (1–28 Workers)

Data

WorkersPer-Core (msg/s)Shared 64-shard (msg/s)Lock-Free Shared (msg/s)Per-Core / Shared
11.97M2.04M2.05M0.97x
23.28M1.91M1.95M1.71x
34.83M2.18M2.21M2.22x
45.76M2.34M2.33M2.46x
87.65M2.10M1.61M3.64x
166.52M1.41M1.06M4.62x
206.19M1.24M1.12M5.00x
285.98M1.13M936K5.29x
Shared-nothing Per-Core 아키텍처의 핵심 주장은 "코어를 추가하면 처리량이 비례 증가한다"이며, 이번 20코어 환경 벤치마크가 이를 실증한다. 1워커 1.97M msg/s에서 8워커 7.65M msg/s — P-Core 수에 도달할 때까지 처리량이 꾸준히 상승하며, 소프트웨어 구조적 한계점은 관측되지 않았다.

이 그래프에서 Per-Core가 꺾이는 지점과 Shared가 꺾이는 지점의 원인이 근본적으로 다르다. Shared 모델은 업계 표준 최적화(64-shard mutex 파티셔닝)를 적용했음에도 4워커(2.34M)에서 피크를 찍고 하락한다. Lock contention이 코어 추가 이득을 삼키는 소프트웨어 병목이다. Per-Core는 소프트웨어 병목이 전혀 없으므로, 하드웨어의 물리적 한계(P-Core 8개 소진, E-Core 지각생 효과)에서야 비로소 완만한 하락이 시작된다.

Lock-Free Shared가 Shared보다 오히려 나쁘다는 점도 주목할 만하다. 8워커 이상에서 CAS 기반 Lock-Free의 처리량이 mutex 기반보다 낮아진다 — 28워커에서 936K vs 1.13M. CAS 루프의 실패-재시도가 고코어 환경에서 mutex의 OS-level 대기보다 더 많은 CPU 사이클을 소모한다는 반직관적 결과로, lock-free가 곧 확장성 해결책이라는 통념을 정면으로 반박한다.

Per-Core 아키텍처는 소프트웨어가 낼 수 있는 병목을 원천 제거한 설계다. 28코어 전체를 사용해도 Per-Core(5.98M)는 Shared 피크(2.34M)의 2.56배이며, Shared 28코어(1.13M) 대비 5.29배다. 균일 코어 서버 CPU(Xeon, EPYC)에서는 P/E 비대칭이 없으므로 선형 확장이 코어 수 한계까지 지속될 것으로 예측되며, CPU Affinity 고정과 비대칭 워크로드 분배를 적용하면 현재 하이브리드 CPU에서도 E-Core 구간의 효율을 끌어올릴 수 있다.
3
Queue Performance — SPSC & MPSC

SPSC Queue (Wait-free)

BenchmarkCPU TimeReal TimeIterationsThroughput
SpscQueue_Throughput/10243.5 ns3.5 ns203,636,364290M items/s
SpscQueue_Throughput/40963.5 ns3.5 ns203,636,364290M items/s
SpscQueue_Throughput/327683.4 ns3.4 ns213,333,333297M items/s
SpscQueue_Throughput/655363.4 ns3.4 ns213,333,333291M items/s
SpscQueue_Latency1.9 ns1.9 ns373,333,333531M items/s
SpscQueue_Backpressure1.5 ns1.5 ns497,777,778-
SpscQueue_ConcurrentThroughput53.1 ns55.3 ns10,000,00018.8M items/s

MPSC Queue (Lock-free)

BenchmarkCPU TimeReal TimeIterationsThroughput
MpscQueue_1P1C/10246.5 ns6.5 ns89,600,000155M items/s
MpscQueue_1P1C/40966.6 ns6.6 ns112,000,000153M items/s
MpscQueue_1P1C/327686.5 ns6.5 ns89,600,000155M items/s
MpscQueue_1P1C/655366.6 ns6.6 ns112,000,000153M items/s
MpscQueue_2P1C161.8 ns163.1 ns5,600,00022.7M items/s
MpscQueue_Backpressure1.5 ns1.5 ns448,000,000-

SPSC vs MPSC Methodology

SPSC 큐는 Apex Core의 코어 간 통신 근간이다. N코어 환경에서 N×(N-1)개의 전용 SPSC 채널이 메시를 구성하며, 각 채널은 단일 생산자-단일 소비자만 접근하므로 atomic 연산 자체가 불필요한 wait-free 경로를 보장한다. 단방향 레이턴시 1.89ns(531M ops/s)는 L1 캐시 접근에 근접하는 수치로, 큐 연산 자체가 사실상 메모리 접근 비용 수준까지 최적화되었음을 뜻한다.

큐 용량(1K~64K)에 따른 성능 차이가 전혀 없다는 점이 설계 품질을 보여준다. head/tail 인덱스만으로 동작하는 구조 덕분에 큐 크기가 캐시 적중률에 영향을 주지 않으며, 워크로드 특성에 따라 큐 용량을 자유롭게 조정해도 성능 페널티가 없다.

MPSC와의 비교가 SPSC mesh 채택의 근거다. 동일한 1P1C 시나리오에서 MPSC(6.5ns)는 SPSC(3.5ns)보다 1.9배 느리다 — CAS 루프의 구조적 오버헤드가 경합이 없는 상황에서도 비용을 발생시킨다. MPSC에 생산자가 1명 추가되면(2P1C) 레이턴시가 163ns로 25배 폭등하며, 이는 CAS 실패-재시도 비용이 생산자 수에 기하급수적으로 증가하기 때문이다. SPSC mesh는 이 경합을 구조적으로 원천 차단한다.

Concurrent Throughput(55ns, 18.8M ops/s)은 실제 코어 간 통신 비용의 하한선이다. 단일 스레드 벤치마크(3.5ns)와의 차이 ~52ns가 곧 크로스 코어 캐시 동기화 + 스레드 스케줄링 비용이며, 이는 하드웨어가 부과하는 물리적 비용이므로 소프트웨어로 줄일 수 없는 영역이다.
4
Memory Allocators — Slab, Bump, Arena, malloc, make_shared
BenchmarkCPU TimeReal TimeIterationsThroughput
SlabAllocator/643.75 ns3.79 ns179,200,000267M items/s
SlabAllocator/2563.75 ns3.77 ns179,200,000267M items/s
SlabAllocator/10243.77 ns3.77 ns186,666,667265M items/s
BumpAllocator/64/16K3.53 ns3.49 ns203,636,364283M items/s
BumpAllocator/256/256K3.45 ns3.47 ns203,636,364290M items/s
ArenaAllocator/64/16K4.08 ns4.10 ns172,307,692245M items/s
ArenaAllocator/1024/1K7.67 ns7.93 ns89,600,000130M items/s
Malloc/6422.2 ns22.5 ns34,461,53845.0M items/s
Malloc/256161.1 ns160.9 ns4,072,7276.2M items/s
Malloc/102420.5 ns20.7 ns32,000,00048.8M items/s
MakeShared31.5 ns31.5 ns21,333,33331.8M items/s
BumpAllocator_RequestCycle/16K34.5 ns34.3 ns20,363,63629.0M cycles/s

Allocator Comparison (CPU Time ns)

Slab과 Bump 할당기는 3.5~3.8ns에서 완벽한 플랫 라인을 그린다. 64B든 1KB든 성능이 동일하다. Slab은 freelist pop/push, Bump는 포인터 증가(bump) — 둘 다 할당 크기와 무관한 O(1) 연산이므로 이론적 기대와 정확히 일치하는 결과다. Arena는 블록 체이닝 오버헤드로 오브젝트 크기가 커질수록 느려지지만, 그래도 malloc 대비 압도적이다.

malloc의 256B 이상치(161ns)가 눈에 띈다. 64B(22ns)와 1KB(21ns)는 비슷한데 256B만 7배 느리다. MSVC CRT 힙의 내부 버킷 경계에서 발생하는 할당 경로 분기로 추정되며, 시스템 할당기의 성능이 크기에 따라 예측 불가능하게 변동한다는 점이 커스텀 할당기의 필요성을 역설한다.

실전에서의 의미는 Bump RequestCycle이 보여준다. 요청 하나를 처리하며 10개 오브젝트를 할당하고 일괄 해제(reset)하는 패턴이 34ns — 오브젝트당 3.4ns에 불과하다. malloc으로 같은 패턴을 수행하면 최소 220ns(22ns×10)이며, 해제 비용까지 합산하면 격차는 더 벌어진다. Per-request Bump 할당은 Apex Core가 요청당 힙 접근을 제로로 만드는 핵심 기법이다.
5
Frame Processing — FrameCodec
BenchmarkCPU TimeReal TimeIterationsThroughput
FrameCodec_Encode/6415.3 ns15.4 ns44,800,0004.95 GB/s
FrameCodec_Encode/51216.7 ns16.8 ns44,800,00031.3 GB/s
FrameCodec_Encode/409632.1 ns32.2 ns22,400,000128 GB/s
FrameCodec_Encode/16384210 ns210 ns3,200,00078.1 GB/s
FrameCodec_Decode/6432.2 ns32.6 ns20,363,6362.36 GB/s
FrameCodec_Decode/51235.3 ns35.2 ns20,363,63614.8 GB/s
FrameCodec_Decode/409657.8 ns56.3 ns10,000,00071.1 GB/s
FrameCodec_Decode/16384258 ns260 ns2,240,00063.5 GB/s

Encode vs Decode Throughput Scaling

FrameCodec은 페이로드 크기에 비례하여 처리량이 급상승하는 특성을 보인다. 64B에서 4.95 GB/s → 4KB에서 128 GB/s로 약 26배 증가한다. 소형 메시지에서는 헤더 구성·CRC 계산 등 고정 비용이 지배적이지만, 페이로드가 커지면 memcpy 대역폭이 주도하면서 메모리 버스 속도에 수렴한다.

Encode가 Decode보다 일관되게 빠르다 — 4KB 기준 128 GB/s vs 71.1 GB/s(1.8배 차이). Decode에는 헤더 필드 검증, 길이 범위 체크, CRC 무결성 확인 등 방어적 파싱이 추가되기 때문이다. 이 비대칭은 의도된 설계 트레이드오프로, 수신 경로의 안전성을 성능보다 우선한 결과다.

실 서비스 기준에서 중요한 수치는 512B(평균 메시지 크기) 구간이다. Encode 31.3 GB/s, Decode 14.8 GB/s — 100Gbps NIC의 이론 대역폭(12.5 GB/s)을 Encode는 2.5배, Decode는 1.2배 상회한다. 네트워크 I/O가 포화되기 전에 FrameCodec이 병목이 될 가능성은 사실상 없다.

16KB에서 처리량이 4KB보다 감소하는 것은 L2 캐시(2MB) 내에서의 작업 세트 크기 변화 때문이다. 16KB 프레임은 인코딩 과정에서 L1 캐시(48KB)를 상당 부분 점유하며, 캐시 미스 비율이 올라가면서 memcpy 효율이 떨어진다. 그럼에도 78 GB/s는 충분히 높은 수치다.
6
Serialization — FlatBuffers vs Heap
BenchmarkCPU TimeReal TimeIterationsThroughput
FlatBuffers_Build/6481.6 ns86.1 ns7,466,667784 MB/s
FlatBuffers_Build/51287.2 ns88.7 ns8,960,0005.87 GB/s
FlatBuffers_Build/4096125.6 ns126.3 ns4,977,77832.6 GB/s
HeapAlloc_Build/6449.6 ns49.6 ns15,448,2761.29 GB/s
HeapAlloc_Build/51256.3 ns56.7 ns10,000,0009.10 GB/s
HeapAlloc_Build/4096100.4 ns100.6 ns7,466,66740.8 GB/s
FlatBuffers_Read/644.76 ns4.91 ns144,516,12913.5 GB/s
FlatBuffers_Read/5125.16 ns5.37 ns100,000,00099.3 GB/s
FlatBuffers_Read/40964.71 ns4.73 ns149,333,333870 GB/s
HeapAlloc_Read/6450.0 ns50.2 ns10,000,0001.28 GB/s
HeapAlloc_Read/51257.2 ns70.7 ns11,200,0008.95 GB/s
HeapAlloc_Read/409698.4 ns104.6 ns7,466,66741.6 GB/s

Build vs Read Comparison

FlatBuffers의 가치는 빌드가 아니라 읽기에 있다. 빌드 성능에서 HeapAlloc이 1.3~1.6배 빠르다 — FlatBuffers는 vtable 구성, 필드 정렬, 빌더 내부 버퍼 관리 비용이 추가되기 때문이다. 그러나 읽기 측에서 상황이 역전된다.

FlatBuffers Read 4KB: 870 GB/s. 이 수치는 L1 캐시 대역폭에 근접하며, HeapAlloc Read(41.6 GB/s) 대비 21배 빠르다. zero-copy 역직렬화의 본질 — 수신된 바이트 배열을 그대로 포인터 캐스팅하여 필드에 접근하므로, 실제 "읽기" 연산은 오프셋 계산뿐이다. 페이로드가 커질수록 이 이점은 극대화되며, 64B에서도 10배 차이(4.76ns vs 50ns)가 발생한다.

서버 프레임워크에서 메시지는 1회 빌드되고 N회 읽힌다. 라우팅 경로에서 메시지 타입 확인, 디스패처에서 핸들러 매칭, 핸들러 내부에서 필드 접근 — 수신 측의 읽기 빈도가 압도적이다. 빌드 비용 26ns의 추가 투자(4KB 기준)로 매 읽기마다 93ns를 절약하는 구조이므로, 2회 이상 읽기만 발생해도 FlatBuffers가 총비용에서 유리하다.
7
Hash Map — flat_map vs std::unordered_map

Handler Dispatch & Session Lookup

BenchmarkCPU TimeReal TimeIterationsThroughput
Dispatcher_Lookup/102.46 ns2.49 ns280,000,000407M items/s
Dispatcher_Lookup/1002.51 ns2.48 ns298,666,667398M items/s
Dispatcher_Lookup/10002.34 ns2.45 ns280,000,000427M items/s
FlatMap_SessionLookup/1002.04 ns2.06 ns344,615,385490M items/s
FlatMap_SessionLookup/1K2.04 ns2.04 ns344,615,385490M items/s
FlatMap_SessionLookup/10K2.04 ns2.05 ns344,615,385490M items/s
FlatMap_SessionLookup/100K2.04 ns2.05 ns344,615,385490M items/s
StdMap_SessionLookup/1001.73 ns1.73 ns407,272,727579M items/s
StdMap_SessionLookup/1K1.76 ns1.74 ns407,272,727567M items/s
StdMap_SessionLookup/10K1.69 ns1.72 ns407,272,727592M items/s
StdMap_SessionLookup/100K1.76 ns1.74 ns373,333,333569M items/s

Session Iterate (Full Scan)

BenchmarkCPU TimeReal TimeIterationsThroughput
FlatMap_Iterate/10073.2 ns74.1 ns8,960,0001.37B elem/s
FlatMap_Iterate/1,0001.10 µs1.11 µs640,000910M elem/s
FlatMap_Iterate/10,00010.99 µs11.09 µs64,000910M elem/s
StdMap_Iterate/100102.5 ns101.7 ns7,466,667975M elem/s
StdMap_Iterate/1,0002.59 µs2.59 µs560,000385M elem/s
StdMap_Iterate/10,00051.6 µs53.2 µs10,000194M elem/s

flat_map vs std::unordered_map — Iteration Throughput

MessageDispatcher의 핸들러 조회는 핸들러 수에 무관하게 2.3~2.5ns를 유지한다. 10개든 1,000개든 동일 — 해시 테이블 기반 O(1) 조회가 실측으로 확인되었으며, 서비스 규모 확장에 따른 디스패치 성능 저하는 발생하지 않는다.

세션 맵의 단건 조회에서는 std::unordered_map(1.7ns)이 flat_map(2.0ns)보다 약간 빠르다. uint64 키의 해시 계산이 단순하여 node-based 구조의 포인터 역참조 비용이 미미하기 때문이다. 그러나 전체 순회에서 격차가 극적으로 벌어진다 — 10K 세션에서 flat_map이 4.7배 빠르다(11.1μs vs 53.2μs).

이 차이는 메모리 레이아웃에서 온다. flat_map은 open addressing으로 데이터가 연속 메모리에 저장되어 CPU 프리페처가 효과적으로 동작한다. std::unordered_map은 노드 기반 체이닝으로 각 원소가 개별 힙 할당되므로, 순회 시 포인터를 따라 메모리 전역을 뛰어다니며 캐시 미스가 누적된다. 세션 수가 늘수록 캐시 미스 비율이 기하급수적으로 증가하여 격차가 벌어진다.

Apex Core는 SessionManager, CrossCoreDispatcher, KafkaHandlerMap 등에서 flat_map을 사용한다. 세션 전체 브로드캐스트, 타임아웃 스캔, 상태 점검 등 순회 빈도가 높은 연산에서 이 4.7배 차이가 실질적 성능 영향을 미친다.
8
Session & Timer

intrusive_ptr vs shared_ptr

TimingWheel — O(1) Timeout

BenchmarkCPU TimeReal TimeIterationsThroughput
TimingWheel_ScheduleTick/1,00025.1 µs25.9 µs24,88939.8M items/s
TimingWheel_ScheduleTick/10,000288 µs275 µs3,20034.7M items/s
TimingWheel_ScheduleTick/50,0001.82 ms1.89 ms49827.5M items/s
TimingWheel_ScheduleOnly54.4 ns57.5 ns11,200,00018.4M items/s

Session Lifecycle

BenchmarkCPU TimeReal TimeIterationsThroughput
Session_Create295 µs299 µs2,4893,389 items/s
SessionPtr_Copy (intrusive_ptr)10.7 ns10.9 ns64,000,00093.1M items/s
SharedPtr_Copy10.5 ns10.5 ns64,000,00095.3M items/s
SessionPtr(intrusive_ptr)와 shared_ptr의 복사 비용이 10.5~10.7ns로 거의 동일하다. 이 수치만 보면 intrusive_ptr의 이점이 없어 보이지만, 이 벤치마크는 단일 스레드에서 측정된 것이다. intrusive_ptr의 진짜 이점은 Per-Core 아키텍처에서 발현된다 — 세션 객체가 특정 코어에 귀속되므로 참조 카운트를 non-atomic increment로 처리할 수 있다. 멀티스레드 환경에서 shared_ptr의 atomic increment는 캐시 라인 바운싱으로 인해 비용이 급등하며, 이때 intrusive_ptr와의 격차가 벌어진다.

TimingWheel은 O(1) 스케줄링으로 배치 크기 50배 증가(1K→50K)에도 처리량이 39.8M에서 27.5M으로 완만하게 감소한다. 이상적 O(1)이라면 처리량이 일정해야 하지만, 대형 배치에서 tick당 만료 콜백 실행이 누적되면서 캐시 압력이 증가한다. 그럼에도 50K 배치에서 27.5M ops/s는 초당 2,750만 개의 타임아웃을 처리할 수 있다는 뜻으로, 동시 접속 세션 수가 수만에 달해도 타이머가 병목이 될 가능성은 없다.

Session Create(295μs)는 TCP 소켓 생성 + 수신 버퍼 할당 + 세션 맵 등록을 포함한 비용이다. 커넥션 수립 시 1회만 발생하므로 핫패스 성능에 영향을 주지 않으며, 초당 3,389개 생성은 일반적 서버의 신규 연결 수용 속도를 충분히 상회한다.
9
Buffer — RingBuffer (zero-copy vs naive)
BenchmarkCPU TimeReal TimeIterationsThroughput
RingBuffer_WriteRead/649.84 ns9.74 ns74,666,6676.5 GB/s
RingBuffer_WriteRead/51210.7 ns10.9 ns64,000,00047.7 GB/s
RingBuffer_WriteRead/409621.0 ns21.3 ns32,000,000195 GB/s
RingBuffer_Linearize/6411.4 ns11.5 ns56,000,0005.6 GB/s
RingBuffer_Linearize/51214.0 ns14.4 ns44,800,00036.7 GB/s
RingBuffer_Linearize/409634.4 ns34.0 ns21,333,333119 GB/s
NaiveBuffer_CopyWrite/6421.0 ns21.5 ns32,000,0003.0 GB/s
NaiveBuffer_CopyWrite/51227.6 ns27.6 ns24,888,88918.5 GB/s
NaiveBuffer_CopyWrite/409642.4 ns42.7 ns16,592,59396.7 GB/s

Zero-copy vs Naive Throughput (GB/s)

RingBuffer의 4KB WriteRead가 195 GB/s에 도달한다. DDR4-3200 듀얼채널의 이론 대역폭(~51 GB/s)을 크게 상회하는 이 수치는, 데이터가 L1/L2 캐시 내에서 순환하며 메인 메모리 접근 없이 처리되고 있음을 증명한다. 미리 할당된 순환 버퍼에서 포인터 산술만으로 읽기/쓰기 위치를 결정하므로, 힙 할당 비용이 제로다.

NaiveBuffer는 매 쓰기마다 힙 할당(new) + memcpy + 해제(delete)를 수행한다. 64B에서 RingBuffer 대비 2.2배 느리고, 512B에서 2.6배 느리다. 페이로드가 작을수록 힙 할당/해제의 고정 비용이 상대적으로 크게 작용하여 격차가 두드러진다.

Linearize(래핑 경계 처리)는 WriteRead 대비 약 50~60% 오버헤드가 추가된다. 순환 버퍼의 끝에서 시작으로 래핑되는 경우 연속 메모리로 복사하는 비용이지만, 대부분의 경우 데이터가 연속 구간에 위치하여 memcpy 없이 직접 접근(contiguous read)이 가능하다. 최악의 경우에도 119 GB/s로 NaiveBuffer를 상회한다.
10
Integration — End-to-End Pipeline

Cross-core Communication

Benchmark측정값비고
Cross-Core RTT (ping-pong)13.0 µs편도 6.5 µs
Cross-Core Post Throughput1.72M msg/s580 ns/msg (단방향 대량 전송)

Frame Pipeline (수신→파싱→디스패치→핸들러)

PayloadCPU TimeReal TimeThroughput
64B2.76 µs2.83 µs27.5 MB/s
512B2.67 µs2.99 µs196 MB/s
4KB2.91 µs3.02 µs1.41 GB/s

Session Echo (TCP 소켓 I/O 포함)

PayloadCPU TimeReal TimeThroughput
64B12.8 µs13.0 µs5.9 MB/s
512B13.2 µs13.2 µs39.7 MB/s
4KB14.8 µs14.8 µs278 MB/s

Pipeline vs Echo Throughput

Frame Pipeline이 보여주는 것은 Apex Core의 순수 CPU 처리 비용이다. WireHeader 파싱 → RingBuffer 프레임 추출 → FlatBuffers 역직렬화 → MessageDispatcher 핸들러 조회 → 핸들러 실행의 전체 경로가 2.7~2.9μs에 완료된다. 앞선 섹션들에서 각 컴포넌트가 나노초 수준의 성능을 입증했으므로, 이들을 조립한 파이프라인이 마이크로초 수준에서 끝나는 것은 자연스러운 귀결이다. 페이로드 64B→4KB 증가에도 레이턴시 변동이 0.2μs에 불과하며, CPU-side 메시지 처리 파이프라인은 현재 구조에서 도달할 수 있는 물리적 한계에 근접해 있다.

Session Echo와의 차이가 다음 최적화 방향을 제시한다. Echo는 Pipeline에 TCP loopback 소켓 전송/수신을 추가한 것으로, 64B 기준 Pipeline 2.76μs에 TCP I/O ~10μs가 더해져 Echo 12.8μs가 된다. CPU 처리(2.8μs)가 전체의 22%에 불과하고 I/O가 78%를 차지한다 — 프레임워크의 CPU-side는 이미 충분히 빠르므로, 전체 처리량을 끌어올릴 다음 레버는 io_uring이나 DPDK 같은 커널 바이패스 I/O에 있다. 이 방향의 최적화가 적용되면 Echo 레이턴시가 Pipeline 수준에 수렴하는 것이 기대된다.

Cross-Core RTT 13μs는 SPSC mesh를 경유하는 코어 간 메시지 전달의 완전 경로 비용이다. io_context::post() → SPSC 큐 enqueue → 타겟 코어 이벤트 루프 drain → dequeue → 코루틴 재개까지를 포함한다. 순수 SPSC 큐 연산(3.5ns)과의 격차는 주로 이벤트 루프 폴링 간격과 OS 스레드 스케줄링에서 발생하며, CPU Affinity 고정과 tick_interval 튜닝으로 이 구간을 줄일 수 있는 여지가 열려 있다.

Cross-Core Post Throughput 1.72M msg/s는 레이턴시가 아닌 대량 전송 관점의 측정이다. 단방향 연속 전송에서 SPSC 큐의 배치 효과가 발휘되어 메시지당 비용이 580ns까지 낮아지며, CPU Affinity 적용 시 이 수치의 추가 향상이 예상된다.
11
Summary & Conclusion

Methodology Comparison Highlights

ComparisonApex ChoiceAlternativeRatio
Per-Core vs Shared (8w)Per-Core: 7.65M msg/sShared: 2.10M3.64x
SPSC vs MPSC (1P1C)SPSC: 3.5 nsMPSC: 6.5 ns1.9x
Slab vs malloc (64B)Slab: 3.75 nsmalloc: 22.2 ns5.9x
Slab vs malloc (256B)Slab: 3.75 nsmalloc: 161.1 ns43x
FlatBuffers vs Heap Read (4KB)FB: 4.71 nsHeap: 98.4 ns21x
flat_map vs std iterate (10K)flat: 11.1 µsstd: 53.2 µs4.7x
RingBuffer vs Naive (512B)Ring: 47.7 GB/sNaive: 18.5 GB/s2.6x
v0.6.1 벤치마크는 Apex Core 프레임워크의 아키텍처 선택들이 20코어 환경에서 일관되게 유효함을 실증한다.

핵심 수치 7선:
Per-Core 아키텍처 — 8워커에서 7.65M msg/s, Shared 대비 최대 5.29배. 소프트웨어 병목 제로, 코어 수 비례 확장
SPSC Wait-free 큐1.89ns 레이턴시, 531M ops/s. 큐 용량 무관 플랫 성능
커스텀 할당기 — Slab/Bump 3.5~3.8ns, malloc 대비 6~43배. 크기 무관 O(1)
FrameCodec — 4KB Encode 128 GB/s, 100Gbps NIC 대역폭의 10배 이상
FlatBuffers zero-copy — Read 4KB에서 870 GB/s, HeapAlloc 대비 21배
flat_map 순회 — 10K 세션에서 std::unordered_map 대비 4.7배
Frame Pipeline E2E2.8μs CPU 처리, 물리적 한계 근접
모든 방법론 비교에서 Apex Core가 채택한 쪽이 우위를 점했다. SPSC가 MPSC보다 빠르고, 커스텀 할당기가 malloc보다 빠르고, zero-copy RingBuffer가 naive 버퍼보다 빠르고, FlatBuffers 읽기가 힙 역직렬화보다 빠르고, flat_map 순회가 std::unordered_map보다 빠르다. 이 결과들은 개별 컴포넌트 수준의 최적화가 아니라, Shared-nothing Per-Core 아키텍처 위에서 lock-free 경로를 일관되게 구성한 설계 철학의 산물이다.

다음 최적화 축은 두 가지다. 첫째, CPU Affinity 고정과 비대칭 워크로드 분배로 하이브리드 CPU 환경에서의 E-Core 구간 효율을 끌어올리는 것. 둘째, io_uring/DPDK 같은 커널 바이패스 I/O로 현재 전체 레이턴시의 78%를 차지하는 I/O 구간을 압축하는 것. CPU-side 파이프라인이 물리적 한계에 근접한 이상, 남은 성능 여지는 하드웨어 활용과 I/O 경로에 있다.