<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Data-Structure on kastori</title><link>http://blog.kastori.dev/tags/data-structure/</link><description>Recent content in Data-Structure on kastori</description><generator>Hugo -- gohugo.io</generator><language>ko-kr</language><lastBuildDate>Mon, 01 Jun 2026 00:00:00 +0900</lastBuildDate><atom:link href="http://blog.kastori.dev/tags/data-structure/index.xml" rel="self" type="application/rss+xml"/><item><title>[DB 완전 정복 #7] Redis가 빠른 진짜 이유 — 단일 스레드, 이벤트 루프, 자료구조</title><link>http://blog.kastori.dev/tech/2026-06-01-db-07-redis-internals/</link><pubDate>Mon, 01 Jun 2026 00:00:00 +0900</pubDate><guid>http://blog.kastori.dev/tech/2026-06-01-db-07-redis-internals/</guid><description>&lt;h2 id="redis가-빠른-이유가-인메모리라서-아닌가요"&gt;&lt;a href="#redis%ea%b0%80-%eb%b9%a0%eb%a5%b8-%ec%9d%b4%ec%9c%a0%ea%b0%80-%ec%9d%b8%eb%a9%94%eb%aa%a8%eb%a6%ac%eb%9d%bc%ec%84%9c-%ec%95%84%eb%8b%8c%ea%b0%80%ec%9a%94" class="header-anchor"&gt;&lt;/a&gt;&amp;ldquo;Redis가 빠른 이유가 인메모리라서 아닌가요?&amp;rdquo;
&lt;/h2&gt;&lt;p&gt;인메모리인 것은 맞지만, 그것만으로는 설명이 부족하다. Memcached도 인메모리인데 Redis만큼 다양하게 쓰이지 않는다. Redis가 특별한 이유는 &lt;strong&gt;단일 스레드 + 이벤트 루프 + 정교한 자료구조&lt;/strong&gt;의 조합이다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="단일-스레드인데-왜-느리지-않나"&gt;&lt;a href="#%eb%8b%a8%ec%9d%bc-%ec%8a%a4%eb%a0%88%eb%93%9c%ec%9d%b8%eb%8d%b0-%ec%99%9c-%eb%8a%90%eb%a6%ac%ec%a7%80-%ec%95%8a%eb%82%98" class="header-anchor"&gt;&lt;/a&gt;단일 스레드인데 왜 느리지 않나
&lt;/h2&gt;&lt;p&gt;Redis는 모든 명령을 &lt;strong&gt;단일 스레드&lt;/strong&gt;가 처리한다. 멀티코어 서버에서 코어 하나만 쓴다는 뜻이다. 직관적으로 비효율적으로 보이지만, 이것이 Redis의 핵심 설계 철학이다.&lt;/p&gt;
&lt;p&gt;멀티 스레드의 문제는 &lt;strong&gt;동기화 비용&lt;/strong&gt;이다. 여러 스레드가 같은 데이터에 접근할 때 Race Condition을 막으려면 뮤텍스와 락이 필요하다. 락을 거는 것 자체가 비용이고, Context Switch도 비용이다.&lt;/p&gt;
&lt;p&gt;Redis는 이 문제를 &lt;strong&gt;처음부터 단일 스레드&lt;/strong&gt;로 설계해 피해갔다.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;단일 스레드의 장점:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - Lock 없음 → Race Condition 없음
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - 모든 명령이 원자적(Atomic) 보장
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - Context Switch 없음
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - 예측 가능한 성능
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;그렇다면 I/O는 어떻게 처리할까? 단일 스레드가 소켓을 하나씩 읽으면 느리지 않나?&lt;/p&gt;
&lt;h3 id="이벤트-루프--io-multiplexing"&gt;&lt;a href="#%ec%9d%b4%eb%b2%a4%ed%8a%b8-%eb%a3%a8%ed%94%84--io-multiplexing" class="header-anchor"&gt;&lt;/a&gt;이벤트 루프 + I/O Multiplexing
&lt;/h3&gt;&lt;p&gt;Redis는 &lt;code&gt;epoll&lt;/code&gt;(Linux) 또는 &lt;code&gt;kqueue&lt;/code&gt;(macOS) 같은 OS 레벨 I/O Multiplexing을 사용한다.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[클라이언트 수백 개]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Client A ──┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Client B ──┤──▶ epoll (OS 커널) ──▶ 이벤트 큐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Client C ──┘
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ▼
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [단일 스레드 처리]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 명령 실행 → 응답
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;OS 커널이 수백 개의 소켓을 동시에 감시하다가, 읽을 데이터가 생기면 이벤트 큐에 넣는다. 단일 스레드는 큐에서 이벤트를 꺼내 처리한다. &lt;strong&gt;I/O 대기 시간을 OS가 흡수&lt;/strong&gt;하므로 단일 스레드도 충분히 많은 클라이언트를 처리할 수 있다.&lt;/p&gt;
&lt;p&gt;결국 Redis가 빠른 이유는: &lt;strong&gt;인메모리 + Lock 없는 단일 스레드 + OS가 처리하는 I/O 대기&lt;/strong&gt; 세 가지의 조합이다.&lt;/p&gt;
&lt;h3 id="60에서-멀티스레드-io"&gt;&lt;a href="#60%ec%97%90%ec%84%9c-%eb%a9%80%ed%8b%b0%ec%8a%a4%eb%a0%88%eb%93%9c-io" class="header-anchor"&gt;&lt;/a&gt;6.0+에서 멀티스레드 I/O
&lt;/h3&gt;&lt;p&gt;Redis 6.0부터 네트워크 I/O(패킷 읽기/쓰기)는 멀티스레드로 처리하도록 개선됐다. 하지만 실제 명령 실행은 여전히 단일 스레드다. 원자성과 단순함을 유지하면서 대용량 데이터 전송 성능만 개선한 것이다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="자료구조별-내부-구현"&gt;&lt;a href="#%ec%9e%90%eb%a3%8c%ea%b5%ac%ec%a1%b0%eb%b3%84-%eb%82%b4%eb%b6%80-%ea%b5%ac%ed%98%84" class="header-anchor"&gt;&lt;/a&gt;자료구조별 내부 구현
&lt;/h2&gt;&lt;p&gt;Redis의 또 다른 강점은 상황에 따라 &lt;strong&gt;내부 인코딩을 자동으로 최적화&lt;/strong&gt;한다는 것이다.&lt;/p&gt;
&lt;h3 id="sorted-set--실시간-랭킹의-핵심"&gt;&lt;a href="#sorted-set--%ec%8b%a4%ec%8b%9c%ea%b0%84-%eb%9e%ad%ed%82%b9%ec%9d%98-%ed%95%b5%ec%8b%ac" class="header-anchor"&gt;&lt;/a&gt;Sorted Set — 실시간 랭킹의 핵심
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;데이터가 128개 이하: listpack (연속 메모리, 캐시 효율)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;데이터가 많아지면: skiplist + hashtable 조합
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - skiplist: 정렬된 순서로 빠른 범위 조회 (O(log N))
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - hashtable: 멤버 → 점수 O(1) 조회
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ZADD ranking 1500 &amp;#34;user:1&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ZADD ranking 2300 &amp;#34;user:2&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ZADD ranking 1800 &amp;#34;user:3&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ZREVRANGE ranking 0 9 WITHSCORES → 상위 10명 O(log N + 10)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ZRANK ranking &amp;#34;user:1&amp;#34; → 내 순위 O(log N)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ZSCORE ranking &amp;#34;user:2&amp;#34; → 점수 조회 O(1)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;점수 변경이 잦은 실시간 랭킹에 최적이다.&lt;/p&gt;
&lt;h3 id="hash--세션-저장의-패턴"&gt;&lt;a href="#hash--%ec%84%b8%ec%85%98-%ec%a0%80%ec%9e%a5%ec%9d%98-%ed%8c%a8%ed%84%b4" class="header-anchor"&gt;&lt;/a&gt;Hash — 세션 저장의 패턴
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;필드가 128개 이하: listpack (연속 메모리)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;필드가 많아지면: hashtable
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;HSET session:abc userId 1 username &amp;#34;kastori&amp;#34; // O(1)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;HGET session:abc userId // O(1)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;// 필드별 부분 업데이트 가능 (전체 덮어쓰기 필요 없음)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;사용자 세션 데이터를 Hash로 저장하면 필드별로 읽고 쓸 수 있어 효율적이다.&lt;/p&gt;
&lt;h3 id="자료구조-시간복잡도-요약"&gt;&lt;a href="#%ec%9e%90%eb%a3%8c%ea%b5%ac%ec%a1%b0-%ec%8b%9c%ea%b0%84%eb%b3%b5%ec%9e%a1%eb%8f%84-%ec%9a%94%ec%95%bd" class="header-anchor"&gt;&lt;/a&gt;자료구조 시간복잡도 요약
&lt;/h3&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;자료구조&lt;/th&gt;
 &lt;th&gt;주요 연산&lt;/th&gt;
 &lt;th&gt;시간복잡도&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;String&lt;/td&gt;
 &lt;td&gt;SET/GET&lt;/td&gt;
 &lt;td&gt;O(1)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;List&lt;/td&gt;
 &lt;td&gt;LPUSH/RPUSH, LPOP/RPOP&lt;/td&gt;
 &lt;td&gt;O(1)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Hash&lt;/td&gt;
 &lt;td&gt;HSET/HGET&lt;/td&gt;
 &lt;td&gt;O(1)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Set&lt;/td&gt;
 &lt;td&gt;SADD/SISMEMBER&lt;/td&gt;
 &lt;td&gt;O(1)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Sorted Set&lt;/td&gt;
 &lt;td&gt;ZADD/ZSCORE&lt;/td&gt;
 &lt;td&gt;O(log N)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Sorted Set&lt;/td&gt;
 &lt;td&gt;ZRANGE&lt;/td&gt;
 &lt;td&gt;O(log N + M)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="영속성--인메모리인데-재시작하면-데이터는"&gt;&lt;a href="#%ec%98%81%ec%86%8d%ec%84%b1--%ec%9d%b8%eb%a9%94%eb%aa%a8%eb%a6%ac%ec%9d%b8%eb%8d%b0-%ec%9e%ac%ec%8b%9c%ec%9e%91%ed%95%98%eb%a9%b4-%eb%8d%b0%ec%9d%b4%ed%84%b0%eb%8a%94" class="header-anchor"&gt;&lt;/a&gt;영속성 — 인메모리인데 재시작하면 데이터는?
&lt;/h2&gt;&lt;p&gt;Redis는 기본적으로 인메모리라 서버가 꺼지면 데이터가 사라진다. 영속성이 필요하다면 두 가지 방법이 있다.&lt;/p&gt;
&lt;h3 id="rdb--스냅샷"&gt;&lt;a href="#rdb--%ec%8a%a4%eb%83%85%ec%83%b7" class="header-anchor"&gt;&lt;/a&gt;RDB — 스냅샷
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;주기적으로 현재 메모리를 .rdb 파일로 저장
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; → fork() 로 자식 프로세스가 저장, 부모는 계속 요청 처리
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;장점: 파일 크기 작음, 복구 빠름
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;단점: 마지막 스냅샷 이후 데이터 유실 가능
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="aof--명령-로그"&gt;&lt;a href="#aof--%eb%aa%85%eb%a0%b9-%eb%a1%9c%ea%b7%b8" class="header-anchor"&gt;&lt;/a&gt;AOF — 명령 로그
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;모든 쓰기 명령을 파일에 순서대로 기록
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;재시작 시 파일을 재실행해서 복구
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;appendfsync everysec → 1초마다 flush (권장, 최대 1초 유실)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;장점: 데이터 유실 최소화
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;단점: 파일 크기 큼, 복구 시간 느림
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="권장-혼합-모드"&gt;&lt;a href="#%ea%b6%8c%ec%9e%a5-%ed%98%bc%ed%95%a9-%eb%aa%a8%eb%93%9c" class="header-anchor"&gt;&lt;/a&gt;권장: 혼합 모드
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# redis.conf&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="l"&gt;aof-use-rdb-preamble yes&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;→ AOF 파일 앞&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;RDB 스냅샷 (빠른 로딩)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;→ AOF 파일 뒤&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;스냅샷 이후 증분 명령 (데이터 안전)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="실무에서-꼭-지켜야-할-것"&gt;&lt;a href="#%ec%8b%a4%eb%ac%b4%ec%97%90%ec%84%9c-%ea%bc%ad-%ec%a7%80%ec%bc%9c%ec%95%bc-%ed%95%a0-%ea%b2%83" class="header-anchor"&gt;&lt;/a&gt;실무에서 꼭 지켜야 할 것
&lt;/h2&gt;&lt;h3 id="keys-명령-절대-금지"&gt;&lt;a href="#keys-%eb%aa%85%eb%a0%b9-%ec%a0%88%eb%8c%80-%ea%b8%88%ec%a7%80" class="header-anchor"&gt;&lt;/a&gt;KEYS 명령 절대 금지
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;KEYS * → 전체 키 순회, O(N), 단일 스레드 완전 블로킹
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; → 운영 환경에서 1초도 안에 서버 응답 불가 상태 만들 수 있음
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;대신 SCAN:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; SCAN 0 MATCH user:* COUNT 100 → 커서 기반, 블로킹 없음
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="ttl-설정-필수"&gt;&lt;a href="#ttl-%ec%84%a4%ec%a0%95-%ed%95%84%ec%88%98" class="header-anchor"&gt;&lt;/a&gt;TTL 설정 필수
&lt;/h3&gt;&lt;p&gt;캐시 목적의 키는 반드시 만료 시간을 설정해야 한다. 안 하면 메모리가 계속 쌓이다가 &lt;code&gt;maxmemory&lt;/code&gt;에 도달하고, eviction 정책에 따라 데이터가 예고 없이 삭제된다.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SET key value EX 3600 // 1시간 후 자동 만료
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="마치며"&gt;&lt;a href="#%eb%a7%88%ec%b9%98%eb%a9%b0" class="header-anchor"&gt;&lt;/a&gt;마치며
&lt;/h2&gt;&lt;p&gt;Redis를 &amp;ldquo;그냥 캐시&amp;quot;로만 알면 반쪽이다. 단일 스레드 이벤트 루프가 어떻게 동시 처리를 하는지, 자료구조마다 다른 내부 인코딩이 성능에 어떤 영향을 주는지 이해하면 Redis를 더 잘 쓸 수 있다. 다음 편에서는 문서 지향 DB인 MongoDB의 내부 구조를 다룬다.&lt;/p&gt;</description></item></channel></rss>