<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Slab-Allocator on Tarragon</title><link>https://tarrragon.github.io/blog/tags/slab-allocator/</link><description>Recent content in Slab-Allocator on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Tue, 16 Jun 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/slab-allocator/index.xml" rel="self" type="application/rss+xml"/><item><title>Memcached slab allocator 與記憶體經濟學：明明有記憶體卻在 evict</title><link>https://tarrragon.github.io/blog/backend/02-cache-redis/vendors/memcached/slab-allocator-memory-economics/</link><pubDate>Tue, 16 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/02-cache-redis/vendors/memcached/slab-allocator-memory-economics/</guid><description>&lt;blockquote>
&lt;p>本文是 &lt;a href="https://tarrragon.github.io/blog/backend/02-cache-redis/vendors/memcached/" data-link-title="Memcached" data-link-desc="純記憶體 key-value cache、無持久化">Memcached&lt;/a> overview 的 implementation-layer deep article。選型層（純 KV vs Redis data types、何時選 Memcached）見 overview；本文只處理「決定用 Memcached 後，slab 記憶體怎麼配才不會莫名淘汰」。命令實機驗證於 &lt;code>memcached:1.6&lt;/code>（VERSION 1.6.42）、最後檢查日 2026-06-16；機制以 &lt;a href="https://github.com/memcached/memcached/wiki/UserInternals">Memcached 官方 wiki&lt;/a> 為準。&lt;/p>&lt;/blockquote>
&lt;h2 id="明明有記憶體卻在-evict">明明有記憶體、卻在 evict&lt;/h2>
&lt;p>Memcached 最違反直覺的故障是這樣：監控顯示 &lt;code>evictions&lt;/code> 持續上升、hit rate 在掉，但 &lt;code>stats&lt;/code> 算下來實際用掉的記憶體遠低於 &lt;code>-m&lt;/code> 設的上限——機器明明還有空間，Memcached 卻在淘汰資料。換成 Redis 思維的人會卡住，因為 Redis 是一個共用的記憶體池，不會出現「有空間卻淘汰」。&lt;/p>
&lt;p>這個現象叫 slab calcification，根因在 Memcached 的記憶體模型：它把記憶體預先切成許多固定大小的格子（slab class），每個 class 各自管自己那塊，跟 Redis 共用一個記憶體池的模型相反。記憶體一旦分配給某個 class，預設不會還回去給別的 class 用。如果你的 value 大小分布隨時間改變（早期都是小 value、後來都是大 value），早期被小 value 佔走的記憶體還鎖在小 class 裡，大 value 的 class 沒有足夠空間、開始淘汰——即使整體還有大量「屬於別人」的空閒記憶體。&lt;/p>
&lt;p>理解 Memcached 就是理解這套 slab 經濟學。它用「放棄記憶體的靈活性」換到了「永不碎片化、O(1) 分配、可預測的多執行緒擴展」。這個取捨在純 cache 場景非常划算，但它的失敗模式跟 Redis 完全不同，要用 slab 的語言來判讀。&lt;/p>
&lt;h2 id="核心概念slab-allocator-的會計模型">核心概念：slab allocator 的會計模型&lt;/h2>
&lt;p>Memcached 啟動時不會把 &lt;code>-m&lt;/code> 指定的記憶體一次配掉，而是按需求以 &lt;strong>page&lt;/strong>（預設 1MB）為單位分配給 &lt;strong>slab class&lt;/strong>，每個 class 存放某個大小區間的 item。&lt;/p>
&lt;p>&lt;strong>slab class 與 chunk size&lt;/strong>。每個 slab class 對應一個固定的 chunk size，item 被放進「裝得下它的最小 class」。class 的 chunk size 按 &lt;code>growth_factor&lt;/code> 等比成長——實機看預設值：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="nb">printf&lt;/span> &lt;span class="s1">&amp;#39;stats settings\r\nquit\r\n&amp;#39;&lt;/span> &lt;span class="p">|&lt;/span> nc localhost &lt;span class="m">11211&lt;/span> &lt;span class="p">|&lt;/span> grep growth_factor
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">&lt;span class="c1"># STAT growth_factor 1.25&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">&lt;span class="nb">printf&lt;/span> &lt;span class="s1">&amp;#39;set k1 0 0 5\r\nhello\r\nstats slabs\r\nquit\r\n&amp;#39;&lt;/span> &lt;span class="p">|&lt;/span> nc localhost &lt;span class="m">11211&lt;/span> &lt;span class="p">|&lt;/span> grep -E &lt;span class="s2">&amp;#34;chunk_size|active_slabs&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">&lt;span class="c1"># STAT 1:chunk_size 96 ← 最小的 slab class、chunk 96 bytes&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">&lt;span class="c1"># STAT active_slabs 1&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>growth_factor 1.25&lt;/code> 表示每個 class 的 chunk size 是前一個的 1.25 倍：class 1 是 96 bytes、class 2 約 120、class 3 約 152……一路到 item 大小上限。一個 100 bytes 的 value 放不進 96 bytes 的 class 1，被放進 120 bytes 的 class 2——浪費 20 bytes。這個「向上取整到 chunk size」的浪費是 slab 模型的固有成本。&lt;/p>
&lt;p>&lt;strong>page 分配是單向的&lt;/strong>。當某個 class 需要空間，Memcached 給它一個 1MB 的 page，切成該 class 的 chunk。這個 page 預設永久屬於這個 class——這就是 calcification 的來源。&lt;code>-o slab_automove&lt;/code> 與手動 &lt;code>slabs reassign&lt;/code> 可以把 page 在 class 間搬移，但預設行為偏保守。&lt;/p></description><content:encoded><![CDATA[<blockquote>
<p>本文是 <a href="/blog/backend/02-cache-redis/vendors/memcached/" data-link-title="Memcached" data-link-desc="純記憶體 key-value cache、無持久化">Memcached</a> overview 的 implementation-layer deep article。選型層（純 KV vs Redis data types、何時選 Memcached）見 overview；本文只處理「決定用 Memcached 後，slab 記憶體怎麼配才不會莫名淘汰」。命令實機驗證於 <code>memcached:1.6</code>（VERSION 1.6.42）、最後檢查日 2026-06-16；機制以 <a href="https://github.com/memcached/memcached/wiki/UserInternals">Memcached 官方 wiki</a> 為準。</p></blockquote>
<h2 id="明明有記憶體卻在-evict">明明有記憶體、卻在 evict</h2>
<p>Memcached 最違反直覺的故障是這樣：監控顯示 <code>evictions</code> 持續上升、hit rate 在掉，但 <code>stats</code> 算下來實際用掉的記憶體遠低於 <code>-m</code> 設的上限——機器明明還有空間，Memcached 卻在淘汰資料。換成 Redis 思維的人會卡住，因為 Redis 是一個共用的記憶體池，不會出現「有空間卻淘汰」。</p>
<p>這個現象叫 slab calcification，根因在 Memcached 的記憶體模型：它把記憶體預先切成許多固定大小的格子（slab class），每個 class 各自管自己那塊，跟 Redis 共用一個記憶體池的模型相反。記憶體一旦分配給某個 class，預設不會還回去給別的 class 用。如果你的 value 大小分布隨時間改變（早期都是小 value、後來都是大 value），早期被小 value 佔走的記憶體還鎖在小 class 裡，大 value 的 class 沒有足夠空間、開始淘汰——即使整體還有大量「屬於別人」的空閒記憶體。</p>
<p>理解 Memcached 就是理解這套 slab 經濟學。它用「放棄記憶體的靈活性」換到了「永不碎片化、O(1) 分配、可預測的多執行緒擴展」。這個取捨在純 cache 場景非常划算，但它的失敗模式跟 Redis 完全不同，要用 slab 的語言來判讀。</p>
<h2 id="核心概念slab-allocator-的會計模型">核心概念：slab allocator 的會計模型</h2>
<p>Memcached 啟動時不會把 <code>-m</code> 指定的記憶體一次配掉，而是按需求以 <strong>page</strong>（預設 1MB）為單位分配給 <strong>slab class</strong>，每個 class 存放某個大小區間的 item。</p>
<p><strong>slab class 與 chunk size</strong>。每個 slab class 對應一個固定的 chunk size，item 被放進「裝得下它的最小 class」。class 的 chunk size 按 <code>growth_factor</code> 等比成長——實機看預設值：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">printf</span> <span class="s1">&#39;stats settings\r\nquit\r\n&#39;</span> <span class="p">|</span> nc localhost <span class="m">11211</span> <span class="p">|</span> grep growth_factor
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c1"># STAT growth_factor 1.25</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="nb">printf</span> <span class="s1">&#39;set k1 0 0 5\r\nhello\r\nstats slabs\r\nquit\r\n&#39;</span> <span class="p">|</span> nc localhost <span class="m">11211</span> <span class="p">|</span> grep -E <span class="s2">&#34;chunk_size|active_slabs&#34;</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="c1"># STAT 1:chunk_size 96      ← 最小的 slab class、chunk 96 bytes</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="c1"># STAT active_slabs 1</span></span></span></code></pre></div><p><code>growth_factor 1.25</code> 表示每個 class 的 chunk size 是前一個的 1.25 倍：class 1 是 96 bytes、class 2 約 120、class 3 約 152……一路到 item 大小上限。一個 100 bytes 的 value 放不進 96 bytes 的 class 1，被放進 120 bytes 的 class 2——浪費 20 bytes。這個「向上取整到 chunk size」的浪費是 slab 模型的固有成本。</p>
<p><strong>page 分配是單向的</strong>。當某個 class 需要空間，Memcached 給它一個 1MB 的 page，切成該 class 的 chunk。這個 page 預設永久屬於這個 class——這就是 calcification 的來源。<code>-o slab_automove</code> 與手動 <code>slabs reassign</code> 可以把 page 在 class 間搬移，但預設行為偏保守。</p>
<p><strong>LRU 是 per-slab-class 的</strong>。淘汰不是全域的，是每個 slab class 維護自己的 LRU。所以「class 2 滿了開始淘汰、但 class 5 有空閒 page」是正常現象——淘汰看的是該 class 自己的空間，不是全域記憶體。</p>
<p>這三點合起來解釋了開頭的悖論：evict 發生在某個 class 內，跟全域剩餘記憶體無關。</p>
<h2 id="配置slab-與多執行緒的設定路徑">配置：slab 與多執行緒的設定路徑</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># 啟動參數（Memcached 的調校多在啟動參數、不像 Redis 有大量 runtime CONFIG SET）</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">docker run -d --name memcached -p 11211:11211 memcached:1.6 <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>  memcached <span class="se">\
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="se"></span>    -m <span class="m">1024</span> <span class="se">\ </span>         <span class="c1"># 記憶體上限 1024 MB</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    -t <span class="m">4</span> <span class="se">\ </span>            <span class="c1"># worker thread 數（多執行緒、對齊 CPU 核數）</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">    -f 1.25 <span class="se">\ </span>         <span class="c1"># slab growth factor（預設 1.25、調小→class 更密集→浪費更少但 class 更多）</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">    -I 2m <span class="se">\ </span>           <span class="c1"># 單一 item 大小上限（預設 1MB、超過要調大或拆 value）</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl">    -o <span class="nv">slab_automove</span><span class="o">=</span><span class="m">1</span> <span class="c1"># 自動把空閒 page 從一個 class 搬到吃緊的 class（緩解 calcification）</span></span></span></code></pre></div><p>調校判讀：</p>
<ul>
<li><code>-m</code> 是給 item 資料的上限，Memcached 自身的 hash table、連線 buffer 等 overhead 在 <code>-m</code> 之外，機器要留 headroom</li>
<li><code>-t</code> 對齊 CPU 核數——Memcached 從早期就是 multi-threaded，這是它跟早期單執行緒 Redis 的核心差異</li>
<li><code>-f</code> 調小（例如 1.08）讓 slab class 更密集、向上取整浪費更少，代價是 class 數變多、管理開銷略增</li>
<li><code>-I</code> 是單 item 上限，超過會 store 失敗（見故障演練 Case 3）</li>
<li><code>slab_automove=1</code> 是緩解 calcification 的關鍵，預設視版本而定，明確開啟較穩</li>
</ul>
<h2 id="production-故障演練">Production 故障演練</h2>
<h3 id="case-1slab-calcificationvalue-大小漂移造成假性記憶體不足">Case 1：slab calcification——value 大小漂移造成假性記憶體不足</h3>
<p><strong>徵兆</strong>：<code>evictions</code> 上升、hit rate 下降，但 <code>stats</code> 顯示 <code>bytes</code> 遠低於 <code>limit_maxbytes</code>。<code>stats slabs</code> 看到某個 class 的 page 用滿在淘汰，另一個 class 有大量空閒 chunk。</p>
<p><strong>根因</strong>：value 大小分布隨時間漂移。早期 value 小、記憶體被分配給小 slab class；後來 value 變大、需要大 class，但 page 已被小 class 鎖住不還，大 class 空間不足開始淘汰。整體記憶體沒滿，但「對的 class」沒空間。</p>
<p><strong>修法</strong>：</p>
<ol>
<li>開 <code>-o slab_automove=1</code>，讓 Memcached 自動把空閒 page 從冷 class 搬到吃緊的 class</li>
<li>手動觸發搬移：<code>slabs reassign &lt;src_class&gt; &lt;dst_class&gt;</code>（緊急救火用）</li>
<li>監控 <code>stats slabs</code> 各 class 的 <code>used_chunks</code> vs <code>total_chunks</code> 與 <code>stats items</code> 的 per-class evicted，找出失衡的 class</li>
<li>從源頭穩定 value 大小分布——序列化格式統一、避免同類資料時大時小</li>
</ol>
<h3 id="case-2chunk-向上取整浪費大量記憶體">Case 2：chunk 向上取整浪費大量記憶體</h3>
<p><strong>徵兆</strong>：存的 value 總大小算起來只有 600MB，但 Memcached 報用掉接近 1GB，記憶體效率異常低。</p>
<p><strong>根因</strong>：value 大小剛好落在 slab class chunk size 的「上緣之外」，被向上取整到下一個更大的 class，每個 item 浪費接近一個 growth step 的空間。例如大量 130 bytes 的 value 被放進 152 bytes 的 class，每個浪費 22 bytes，量大就顯著。</p>
<p><strong>修法</strong>：</p>
<ol>
<li><code>-f</code> 調小（1.25 → 1.08）讓 class 粒度更細，向上取整的浪費變小</li>
<li><code>stats slabs</code> 看主要 class 的 <code>chunk_size</code> 跟你的 value 實際大小差多少，量化浪費</li>
<li>value 設計上靠近 chunk 邊界（例如壓縮或裁剪 metadata 讓 value 剛好塞進較小的 class）</li>
<li>浪費是 slab 模型的固有成本，純 KV 的 trade-off——換到的是永不碎片化與 O(1) 分配</li>
</ol>
<h3 id="case-3value-超過-item-大小上限store-直接失敗">Case 3：value 超過 item 大小上限、store 直接失敗</h3>
<p><strong>徵兆</strong>：某些大 value 的寫入回 <code>SERVER_ERROR object too large for cache</code>，application 端 cache 寫入靜默失敗、之後一直 miss。</p>
<p><strong>根因</strong>：單一 item 超過 <code>-I</code> 設的上限（預設 1MB）。Memcached 設計上不適合存大 object，預設 1MB 是刻意的純 cache 邊界。</p>
<p><strong>修法</strong>：</p>
<ol>
<li>確認 value 大小分布，大 value 是否真該進 Memcached（純 KV cache 不適合大 blob）</li>
<li>必要時調大 <code>-I</code>（例如 <code>-I 2m</code>），但這會改變 slab class 結構、增加大 chunk 的記憶體佔用</li>
<li>大 object 考慮壓縮、或拆成多個小 key、或改放適合的儲存（物件儲存 / <a href="/blog/backend/02-cache-redis/vendors/redis/" data-link-title="Redis" data-link-desc="OSS in-memory data structure store、cache 主流">Redis</a> 的 hash）</li>
<li>application 端要處理 store 失敗，不要假設 set 一定成功——失敗就走 origin</li>
</ol>
<h3 id="case-4thread-數設太高lock-contention-反而拖慢">Case 4：thread 數設太高、lock contention 反而拖慢</h3>
<p><strong>徵兆</strong>：把 <code>-t</code> 從 4 調到 32 想榨多核效能，throughput 沒升反降，CPU 在 system time 飆高。</p>
<p><strong>根因</strong>：Memcached 的多執行緒有 per-item lock（hash bucket lock），thread 數遠超核數時，執行緒互搶 lock 與 CPU、context switch 開銷超過平行收益。</p>
<p><strong>修法</strong>：</p>
<ol>
<li><code>-t</code> 對齊實體核數，不要超配（多數場景 4-8 已足夠，極高核機器再往上調並壓測）</li>
<li>用實際 workload 壓測對比不同 <code>-t</code> 的 throughput，找拐點</li>
<li>hot key 集中時 lock contention 更明顯（同 bucket），這是資料分布問題不是 thread 數問題</li>
<li>跨機器水平擴展（client-side consistent hashing）比單機堆 thread 更能解規模，見本文整合段</li>
</ol>
<h3 id="case-5連線數打到上限新連線被拒">Case 5：連線數打到上限、新連線被拒</h3>
<p><strong>徵兆</strong>：高並發下新連線報錯或 hang，<code>stats</code> 的 <code>curr_connections</code> 接近 <code>max_connections</code>，<code>listen_disabled_num</code> 在增加。</p>
<p><strong>根因</strong>：每個 client 連線佔一個 connection slot，Memcached 預設 <code>-c 1024</code>。大量 client（尤其沒用連線池、每請求建連）會打滿 connection 上限。</p>
<p><strong>修法</strong>：</p>
<ol>
<li>client 端用連線池重用連線，不要每請求建連</li>
<li>調高 <code>-c</code>（例如 <code>-c 4096</code>），但連線本身有記憶體 overhead（在 <code>-m</code> 之外），要算進機器容量</li>
<li>監控 <code>curr_connections</code> 與 <code>listen_disabled_num</code>，後者非零代表曾達上限拒絕連線</li>
<li>連線數爆炸常是 client fan-out 問題，跨多 Memcached node 分散（consistent hashing）能攤平單 node 連線壓力</li>
</ol>
<h2 id="capacity--cost-邊界">Capacity / cost 邊界</h2>
<p>Memcached 的容量判讀，核心在 slab 效率與多執行緒擴展：</p>
<table>
  <thead>
      <tr>
          <th>訊號</th>
          <th>健康區間</th>
          <th>警戒與動作</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>evictions</code> 速率</td>
          <td>接近 0（working set 放得下）</td>
          <td>持續高但記憶體沒滿 → calcification、開 slab_automove</td>
      </tr>
      <tr>
          <td>各 class <code>used / total chunks</code></td>
          <td>各 class 均衡</td>
          <td>單 class 滿、其他空 → calcification</td>
      </tr>
      <tr>
          <td>chunk 向上取整浪費</td>
          <td>小（value 貼近 chunk size）</td>
          <td>大 → 調小 <code>-f</code> 或調整 value 大小</td>
      </tr>
      <tr>
          <td><code>curr_connections / -c</code></td>
          <td>&lt; 80%</td>
          <td>接近上限 → 用連線池或調高 <code>-c</code></td>
      </tr>
      <tr>
          <td>多執行緒 CPU</td>
          <td>核數內、system time 低</td>
          <td>system time 高 → <code>-t</code> 超配、lock contention</td>
      </tr>
  </tbody>
</table>
<p>撞牆後的路由判斷：</p>
<ul>
<li><strong>需要 data types / 持久化 / distributed lock</strong>：Memcached 是純 KV、刻意不做這些。需要這些走 <a href="/blog/backend/02-cache-redis/vendors/redis/" data-link-title="Redis" data-link-desc="OSS in-memory data structure store、cache 主流">Redis / Valkey</a>，這是 capability 差異不是調校能補。</li>
<li><strong>單機容量 / throughput 不夠</strong>：Memcached 沒有 server-side cluster，靠 client-side consistent hashing（ketama）水平擴展到多 node，見整合。</li>
<li><strong>想要 Memcached 的多執行緒 + Redis 的 data types</strong>：<a href="/blog/backend/02-cache-redis/vendors/dragonflydb/" data-link-title="DragonflyDB" data-link-desc="高效能 Redis / Memcached 相容替代、多核架構">DragonflyDB</a> 兼具多核與 Redis 相容，是兩者的中間點。</li>
</ul>
<h2 id="整合--下一步">整合 / 下一步</h2>
<p>Memcached 的單機很簡單，它的工程深度在「如何把多個 Memcached node 組成一個 cache 層」——而這發生在 client 端與代理層，不在 server：</p>
<ul>
<li><strong>client-side consistent hashing（ketama）</strong>：Memcached server 之間互不知道彼此，sharding 由 client library 用 consistent hashing 決定 key 去哪個 node，加減 node 時最小化 key 重新分布。這是 Memcached 水平擴展的基礎。</li>
<li><strong>跟 <a href="/blog/backend/02-cache-redis/cases/meta-mcrouter-global-cache-routing/" data-link-title="2.C2 Meta：mcrouter 與跨區快取路由" data-link-desc="快取從單點最佳化演進到分散式路由層的案例。">Meta mcrouter</a></strong>：Meta 的 mcrouter 是 Memcached 專屬的 protocol-aware routing proxy，把跨叢集 / 跨區的流量收斂、失效隔離、pool 管理從 client 端移到代理層——這是 Memcached 大規模治理的標準答案。</li>
<li><strong>跟 <a href="/blog/backend/02-cache-redis/cases/netflix-evcache-global-cache-layer/" data-link-title="2.C6 Netflix：EVCache 全域快取層" data-link-desc="快取從本地層演進為跨區分散式能力的案例。">Netflix EVCache</a></strong>：EVCache 基於 Memcached，Netflix 在上面加跨 AZ replication 與 client-side smart routing，補足 Memcached 沒有的跨區 HA。</li>
<li><strong>跟 <a href="/blog/backend/02-cache-redis/cases/meta-tao-social-graph-cache-evolution/" data-link-title="2.C8 Meta：TAO 社交圖快取演進" data-link-desc="社交圖查詢在規模化下如何把快取做成資料層能力。">Meta TAO</a></strong>：TAO 底層用 Memcached 作為 social graph 的 cache 層，上層加一致性與關聯查詢——展示了純 KV 之上如何疊加語意。</li>
<li><strong>跟 <a href="/blog/backend/02-cache-redis/cases/meta-cachelib-kangaroo-tiered-cache/" data-link-title="2.C4 Meta：CacheLib / Kangaroo 分層快取" data-link-desc="快取從 DRAM-only 轉向分層快取架構的實務案例。">Meta CacheLib + Kangaroo</a></strong>：當 DRAM 的記憶體經濟撞到極限，Meta 用 CacheLib 把 cache 分層到 flash——這是 slab 記憶體經濟學的下一個邊界。</li>
</ul>
<h2 id="相關連結">相關連結</h2>
<ul>
<li>上游 vendor 頁：<a href="/blog/backend/02-cache-redis/vendors/memcached/" data-link-title="Memcached" data-link-desc="純記憶體 key-value cache、無持久化">Memcached</a></li>
<li>對照 vendor：<a href="/blog/backend/02-cache-redis/vendors/redis/memory-eviction-tuning/" data-link-title="Redis 記憶體與淘汰調校：maxmemory-policy、LFU 與碎片化的實戰判讀" data-link-desc="Redis 的記憶體是一條會在半夜爆掉的曲線：maxmemory 設多少、policy 選 LRU 還 LFU、碎片化什麼時候開始吃掉 30% RAM、OOM 時 noeviction 怎麼讓寫入全部失敗。本文展開 Redis 記憶體會計模型、eviction policy 的選型判讀、5 個把記憶體配置寫成 production 事故的踩坑，以及單機記憶體撞牆後該往 cluster 還是 DragonflyDB 走的邊界">Redis 記憶體與淘汰調校</a>（jemalloc 池 vs slab class 的差異）、<a href="/blog/backend/02-cache-redis/vendors/dragonflydb/" data-link-title="DragonflyDB" data-link-desc="高效能 Redis / Memcached 相容替代、多核架構">DragonflyDB</a></li>
<li>相關 migration：<a href="/blog/backend/02-cache-redis/vendors/redis/migrate-to-memcached/" data-link-title="Redis → Memcached：Memcached 不是 simpler Redis、是 cache paradigm" data-link-desc="Redis → Memcached 是 Type E paradigm reduction migration — 從 multi-paradigm（KV &#43; 資料結構 &#43; pub/sub &#43; Lua &#43; streams）退到 pure cache；不是「remove Redis features」、是「重新分配 Redis-specific feature 到對應 specialized 服務」；5 個 production 踩雷 &#43; paradigm reduction 路線">Redis → Memcached</a></li>
<li>Methodology：<a href="/blog/posts/vendor-%E6%B7%B1%E5%BA%A6%E6%8A%80%E8%A1%93%E6%96%87%E7%AB%A0%E6%96%B9%E6%B3%95%E8%AB%96%E7%9A%84%E6%BC%94%E5%8C%96%E7%B4%80%E9%8C%84%E5%90%8C-vendor-%E7%B3%BB%E5%88%97%E7%9A%84%E9%96%8B%E5%A0%B4%E8%BC%AA%E6%9B%BF%E9%A9%97%E8%AD%89/" data-link-title="Vendor 深度技術文章方法論的演化紀錄：同 vendor 系列的開場輪替驗證" data-link-desc="vendor overview 飽和後要寫單一功能深度文章、需要選題與結構依據時回來。這套方法論的驗證來源與 cadence variant 在高風險場景（同 vendor sub-tool 系列）的實證。">Vendor 深度技術文章寫作方法論</a></li>
</ul>
]]></content:encoded></item></channel></rss>