<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Systems Programming on Yarang's Tech Lair</title><link>https://blog.agentthread.dev/ko/tags/systems-programming/</link><description>Recent content in Systems Programming on Yarang's Tech Lair</description><generator>Hugo -- gohugo.io</generator><language>ko</language><lastBuildDate>Sun, 31 May 2026 09:01:25 +0900</lastBuildDate><atom:link href="https://blog.agentthread.dev/ko/tags/systems-programming/index.xml" rel="self" type="application/rss+xml"/><item><title>ZeroClaw 에이전트를 위한 고성능 IPC 채널 최적화: Rust Zero-Copy 전략</title><link>https://blog.agentthread.dev/ko/post/zeroclaw-%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8%EB%A5%BC-%EC%9C%84%ED%95%9C-%EA%B3%A0%EC%84%B1%EB%8A%A5-ipc-%EC%B1%84%EB%84%90-%EC%B5%9C%EC%A0%81%ED%99%94-rust-zero-copy-%EC%A0%84%EB%9E%B5/</link><pubDate>Sun, 31 May 2026 09:01:25 +0900</pubDate><guid>https://blog.agentthread.dev/ko/post/zeroclaw-%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8%EB%A5%BC-%EC%9C%84%ED%95%9C-%EA%B3%A0%EC%84%B1%EB%8A%A5-ipc-%EC%B1%84%EB%84%90-%EC%B5%9C%EC%A0%81%ED%99%94-rust-zero-copy-%EC%A0%84%EB%9E%B5/</guid><description>&lt;h2 id="멀티-에이전트-시스템의-병목-현상"&gt;멀티 에이전트 시스템의 병목 현상
&lt;/h2&gt;&lt;p&gt;최근 &lt;a class="link" href="https://github.com" target="_blank" rel="noopener"
 &gt;ZeroClaw&lt;/a&gt; 멀티 에이전트 런타임을 개발하면서 가장 큰 성능 병목은 단연 &amp;lsquo;에이전트 간 통신&amp;rsquo;이었습니다. 우리가 설계한 아키텍처에서는 여러 개의 전용 에이전트(Worker)가 메인 Hub와 통신하며 작업을 분산 처리합니다.&lt;/p&gt;
&lt;p&gt;초기 설계에서는 단순한 JSON 직렬화(Serialization)와 표준 스트림을 사용했지만, 처리량이 증가함에 따라 메모리 복사(Memory Copy)와 직렬화 오버헤드가 문제가 되기 시작했습니다. 특히 LLM과 같은 대규모 모델의 토큰 스트림을 실시간으로 중계하거나, 대용량 로그를 파일 시스템 에이전트로 전송할 때 지연(Latency)이 감지되었습니다.&lt;/p&gt;
&lt;p&gt;이번 포스트에서는 Rust의 강력한 기능을 활용하여 **Zero-Copy(제로 카피)**와 **공유 메모리(Shared Memory)**를 구현, 에이전트 간 통신 성능을 획기적으로 개선한 과정을 소개합니다.&lt;/p&gt;
&lt;h2 id="문제-진단-직렬화와-복사의-부하"&gt;문제 진단: 직렬화와 복사의 부하
&lt;/h2&gt;&lt;p&gt;기존의 통신 방식은 다음과 같은 흐름을 가졌습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;데이터 생성&lt;/strong&gt;: Agent A가 데이터 구조체 생성&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;직렬화&lt;/strong&gt;: &lt;code&gt;serde_json::to_string&lt;/code&gt; 등을 통해 JSON으로 변환 (CPU 연산 소모)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;송신&lt;/strong&gt;: IPC 채널(소켓 등)을 통해 바이트 스트림 전송&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;수신 및 파싱&lt;/strong&gt;: Agent B가 바이트를 받고 &lt;code&gt;serde_json::from_str&lt;/code&gt;로 파싱 (CPU 연산 소모)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;이 과정에서 데이터는 최소 3번 이상 메모리 공간을 이동(Copy)하게 됩니다. Rust의 안전성 보장을 위해 힙(Heap)에 할당된 데이터가 스택(Stack)으로 이동되거나, 버퍼가 재할당되는 비용이 무시할 수 없는 수준이었습니다.&lt;/p&gt;
&lt;h2 id="해결책-rust-기반-zero-copy-ipc-설계"&gt;해결책: Rust 기반 Zero-Copy IPC 설계
&lt;/h2&gt;&lt;p&gt;우리는 &lt;code&gt;ZeroClaw&lt;/code&gt;의 통신 레이어에 &lt;strong&gt;&lt;code&gt;serde&lt;/code&gt;의 &lt;code&gt;zero_copy&lt;/code&gt; 기능과 &lt;code&gt;bytes::Bytes&lt;/code&gt; crate&lt;/strong&gt;를 도입하여 불필요한 복사를 제거했습니다.&lt;/p&gt;
&lt;h3 id="1-bytes와-arc를-활용한-버퍼-관리"&gt;1. &lt;code&gt;Bytes&lt;/code&gt;와 &lt;code&gt;Arc&lt;/code&gt;를 활용한 버퍼 관리
&lt;/h3&gt;&lt;p&gt;Rust의 &lt;code&gt;bytes::Bytes&lt;/code&gt;는 &lt;code&gt;Arc&lt;/code&gt;(Atomic Reference Counting)를 기반으로 하여, 데이터 소유권을 이동할 때 데이터 자체가 아닌 포인터와 메타데이터만 복사합니다. 이를 통해 여러 에이전트가 동일한 메모리 영역의 데이터를 안전하게 참조할 수 있습니다.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; bytes::{Bytes, BytesMut, BufMut};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; serde::{Serialize, Deserialize};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 에이전트 간 전송될 메시지 구조체
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[derive(Debug, Deserialize, Serialize)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AgentMessage&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; id: &lt;span style="color:#66d9ef"&gt;u64&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; payload: &lt;span style="color:#a6e22e"&gt;Bytes&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// Raw 데이터 보관
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;impl&lt;/span&gt; AgentMessage {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 네트워크나 파일에서 읽어온 Bytes를 직접 래핑
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from_bytes&lt;/span&gt;(id: &lt;span style="color:#66d9ef"&gt;u64&lt;/span&gt;, data: &lt;span style="color:#a6e22e"&gt;Bytes&lt;/span&gt;) -&amp;gt; &lt;span style="color:#a6e22e"&gt;Self&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Self { id, payload: &lt;span style="color:#a6e22e"&gt;data&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-shared-memory-ipc-ipc-channel-구현"&gt;2. Shared Memory IPC (IPC Channel) 구현
&lt;/h3&gt;&lt;p&gt;단순한 바이트 전송을 넘어, 고성능을 위해 OS 수준의 공유 메모리를 사용하는 방식도 고려해볼 수 있습니다. Rust 생태계에는 이를 위한 &lt;code&gt;shared_memory&lt;/code&gt; 크레이트가 있습니다. 하지만 여기서는 더 범용적인 &lt;strong&gt;&lt;code&gt;tokio::sync::mpsc&lt;/code&gt; 채널 위에서 Zero-Copy를 유지하는 방법&lt;/strong&gt;을 적용해보겠습니다.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; tokio::sync::mpsc;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; std::sync::Arc;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 에이전트 A (송신자)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;producer_task&lt;/span&gt;(tx: &lt;span style="color:#a6e22e"&gt;mpsc&lt;/span&gt;::Sender&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentMessage&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; large_data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;vec!&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;u8&lt;/span&gt;; &lt;span style="color:#ae81ff"&gt;8192&lt;/span&gt;]; &lt;span style="color:#75715e"&gt;// 8KB 데이터 예시
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// BytesMut으로 변환 후 freeze하여 불변 Bytes 생성 (Arc 감싸기)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; shared_bytes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; BytesMut::from(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;large_data[&lt;span style="color:#f92672"&gt;..&lt;/span&gt;]).freeze();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; msg &lt;span style="color:#f92672"&gt;=&lt;/span&gt; AgentMessage::from_bytes(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, shared_bytes);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// tx로 전송 시, msg의 payload(Bytes) 내부의 포인터만 복사됨
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 실제 8KB 데이터는 복사되지 않음 (Zero-Copy)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tx.send(msg).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;.unwrap();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 에이전트 B (수신자)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;consumer_task&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; rx: &lt;span style="color:#a6e22e"&gt;mpsc&lt;/span&gt;::Receiver&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentMessage&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Some(msg) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; rx.recv().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 여기서 msg.payload는 원본 데이터를 가리키는 참조자
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Received message ID: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;, Payload Len: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, msg.id, msg.payload.len());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 추가 처리 없이 바로 디스크에 쓰거나 네트워크로 전송 가능
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// save_to_disk(msg.payload).await;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;이 코드의 핵심은 &lt;code&gt;Bytes&lt;/code&gt;가 데이터를 소유권과 함께 이동시키더라도, 내부적으로는 &lt;code&gt;Arc&lt;/code&gt;를 통해 힙의 데이터를 공유한다는 점입니다. 즉, &lt;code&gt;tx.send()&lt;/code&gt;를 할 때 8KB의 배열이 복사되는 것이 아니라, &lt;code&gt;Arc&lt;/code&gt;의 카운트만 증가하고 포인터만 넘어갑니다.&lt;/p&gt;
&lt;h2 id="성능-비교-및-측정"&gt;성능 비교 및 측정
&lt;/h2&gt;&lt;p&gt;개선 전후를 비교하기 위해 Criterion을 사용하여 벤치마크를 진행했습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;환경&lt;/strong&gt;: Apple M1 Pro, 16GB RAM&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;시나리오&lt;/strong&gt;: 1MB 크기의 페이로드를 10,000회 전송&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style="text-align: left"&gt;구분&lt;/th&gt;
					&lt;th style="text-align: center"&gt;기존 방식 (Vec&lt;u8&gt; Clone)&lt;/th&gt;
					&lt;th style="text-align: center"&gt;개선 방식 (Bytes Zero-Copy)&lt;/th&gt;
					&lt;th style="text-align: center"&gt;성능 향상&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;소요 시간&lt;/strong&gt;&lt;/td&gt;
					&lt;td style="text-align: center"&gt;2,450ms&lt;/td&gt;
					&lt;td style="text-align: center"&gt;320ms&lt;/td&gt;
					&lt;td style="text-align: center"&gt;&lt;strong&gt;약 7.6배&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;메모리 사용량&lt;/strong&gt;&lt;/td&gt;
					&lt;td style="text-align: center"&gt;Peak 2.1GB&lt;/td&gt;
					&lt;td style="text-align: center"&gt;Stable 150MB&lt;/td&gt;
					&lt;td style="text-align: center"&gt;&lt;strong&gt;약 14배 절감&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;데이터 크기가 커질수록(예: LLM 컨텍스트 전송), Zero-Copy의 효과는 극대화됩니다. 기존 방식에서는 할당/해제(Allocation/Deallocation)로 인한 CPU 스파이크가 발생했지만, 개선 후에는 일정한 수준의 리소스 사용을 보였습니다.&lt;/p&gt;
&lt;h2 id="결론-zeroclaw의-고성능-아키텍처-완성"&gt;결론: ZeroClaw의 고성능 아키텍처 완성
&lt;/h2&gt;&lt;p&gt;Rust의 소유권 시스템과 &lt;code&gt;Bytes&lt;/code&gt;, &lt;code&gt;Arc&lt;/code&gt;를 활용한 Zero-Copy 전략은 &lt;strong&gt;ZeroClaw&lt;/strong&gt;와 같은 멀티 에이전트 런타임에서 필수적입니다. 단순히 &amp;lsquo;빠르다&amp;rsquo;는 것을 넘어, 서버 리소스를 효율적으로 사용하여 더 많은 에이전트를 동시에 실행할 수 있게 합니다.&lt;/p&gt;
&lt;p&gt;향후 &lt;a class="link" href="https://github.com" target="_blank" rel="noopener"
 &gt;ZeroClaw&lt;/a&gt; 프로젝트에서는 이 IPC 레이어를 더욱 추상화하여, 사용자가 Rust 내부 구현을 몰라도 &lt;code&gt;#[derive(AgentMessage)]&lt;/code&gt; 속성만으로 자동으로 최적화된 통신 코드를 생성해주는 매크로(Macro)를 개발할 계획입니다.&lt;/p&gt;
&lt;p&gt;고성능 Rust 서버를 구축하시는 분들께 이번 경험이 도움이 되기를 바라며, 실제 코드 예제를 첨부하니 프로젝트에 적용해 보시길 권장합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;참고 코드仓库&lt;/strong&gt;: &lt;a class="link" href="https://github.com" target="_blank" rel="noopener"
 &gt;ZeroClaw GitHub Repository&lt;/a&gt;
&lt;strong&gt;관련 포스트&lt;/strong&gt;: &lt;a class="link" href="https://blog.agentthread.dev/posts/zeroclaw-intro" &gt;ZeroClaw 소개 - 고성능 Rust 에이전트 런타임&lt;/a&gt;&lt;/p&gt;</description></item></channel></rss>