<?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>Keydb on Tarragon</title><link>https://tarrragon.github.io/blog/tags/keydb/</link><description>Recent content in Keydb on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Mon, 22 Jun 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/keydb/index.xml" rel="self" type="application/rss+xml"/><item><title>KeyDB → Redis / Valkey：從多線程 fork 回歸主線的遷移路徑</title><link>https://tarrragon.github.io/blog/backend/02-cache-redis/vendors/keydb/migrate-to-redis/</link><pubDate>Mon, 22 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/02-cache-redis/vendors/keydb/migrate-to-redis/</guid><description>&lt;blockquote>
&lt;p>本文是跨 vendor migration playbook、cross-link 到 &lt;a href="https://tarrragon.github.io/blog/backend/02-cache-redis/vendors/keydb/" data-link-title="KeyDB" data-link-desc="Redis multi-threaded fork、active-replication、Snap 採用">KeyDB&lt;/a>（source）跟 &lt;a href="https://tarrragon.github.io/blog/backend/02-cache-redis/vendors/redis/" data-link-title="Redis" data-link-desc="OSS in-memory data structure store、cache 主流">Redis&lt;/a> / &lt;a href="https://tarrragon.github.io/blog/backend/02-cache-redis/vendors/valkey/" data-link-title="Valkey" data-link-desc="Redis fork、Linux Foundation 託管、BSD 授權">Valkey&lt;/a>（target）。跑 6 維 diff dimension audit 後判定為 &lt;strong>Type B drop-in&lt;/strong>（KeyDB 是 Redis fork、RESP 相容、RDB/AOF 相容），但 active-active replication 跟 multi-threading 特性回退需要額外處理。&lt;/p>&lt;/blockquote>
&lt;h2 id="為什麼從-keydb-遷回">為什麼從 KeyDB 遷回&lt;/h2>
&lt;p>KeyDB 是 Snap 維護的 Redis fork，主要差異化在多線程和 active-active replication。遷回的 driver：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>維護活躍度疑慮&lt;/strong>：KeyDB 的 release cadence 跟 Redis/Valkey 主線比較慢，部分組織擔心長期維護與安全 patch 的及時性&lt;/li>
&lt;li>&lt;strong>Valkey 生態收斂&lt;/strong>：Valkey 在 Linux Foundation 治理下快速演進（8.x 多線程改進），KeyDB 的多線程優勢逐漸縮小&lt;/li>
&lt;li>&lt;strong>Active-active 不再需要&lt;/strong>：業務不再需要跨 region active-active、或改用 application 層處理衝突解析&lt;/li>
&lt;li>&lt;strong>社群與工具生態&lt;/strong>：Redis/Valkey 的 client library、monitoring exporter、Operator 支援度更廣&lt;/li>
&lt;/ul>
&lt;h2 id="6-維-diff-dimension-audit">6 維 diff dimension audit&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>維度&lt;/th>
 &lt;th>評估&lt;/th>
 &lt;th>等級&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>Schema / API&lt;/td>
 &lt;td>完全相容（fork 自 Redis 6.x）&lt;/td>
 &lt;td>Low&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Operational model&lt;/td>
 &lt;td>active-active → Sentinel/Cluster；multi-thread config 移除&lt;/td>
 &lt;td>Medium&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Abstraction / paradigm&lt;/td>
 &lt;td>相同&lt;/td>
 &lt;td>Low&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Number of components&lt;/td>
 &lt;td>相近（1 primary + N replica + HA）&lt;/td>
 &lt;td>Low&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Application change&lt;/td>
 &lt;td>endpoint 換、client config 微調&lt;/td>
 &lt;td>Low&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Data topology&lt;/td>
 &lt;td>RDB/AOF 完全相容&lt;/td>
 &lt;td>Low&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>Type B drop-in，工作重心在 active-active replication 拆除和效能 baseline 對齊。&lt;/p>
&lt;h2 id="keydb-特有功能的處理">KeyDB 特有功能的處理&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>KeyDB 特有功能&lt;/th>
 &lt;th>Redis/Valkey 對應&lt;/th>
 &lt;th>遷移處理&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>Multi-threading（&lt;code>server-threads&lt;/code>）&lt;/td>
 &lt;td>Redis I/O threads / Valkey 8 async I/O&lt;/td>
 &lt;td>回到 Redis 後吞吐量下降是預期，需要 benchmark 建立新 baseline&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Active-active replication&lt;/td>
 &lt;td>無原生等價。Redis 需要 application 層解衝突或用 CRDTs（社群方案）&lt;/td>
 &lt;td>遷移前確認業務是否仍需 multi-master。不需要則直接切 Sentinel/Cluster&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>FLASH storage（&lt;code>storage-provider flash&lt;/code>）&lt;/td>
 &lt;td>無原生等價。Redis 純記憶體&lt;/td>
 &lt;td>遷移前把 FLASH 資料回收到記憶體，或接受遷移後記憶體需求上升。調整 &lt;code>maxmemory&lt;/code>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Subkey expires&lt;/td>
 &lt;td>Redis 無 subkey expire（只有 top-level key TTL）&lt;/td>
 &lt;td>檢查 application 是否依賴 subkey expire；若有需要改寫為 top-level key 或用 sorted set 模擬&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>EXPIREMEMBER&lt;/code> 命令&lt;/td>
 &lt;td>Redis 無此命令&lt;/td>
 &lt;td>grep application code 確認未使用；若有需改寫&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>FLASH storage 的處理取決於冷資料比例。如果多數資料在 FLASH 上（用 &lt;code>OBJECT FREQ&lt;/code> 確認），遷移後的 Redis 記憶體需求會大幅上升 — 要提前計算純記憶體所需容量，調整 instance 規格或改用更積極的 eviction policy。Subkey expires 和 &lt;code>EXPIREMEMBER&lt;/code> 的影響範圍通常較小，但一旦 application 依賴就需要重構資料結構（用 top-level key + TTL 或 sorted set 模擬過期）。&lt;/p></description><content:encoded><![CDATA[<blockquote>
<p>本文是跨 vendor migration playbook、cross-link 到 <a href="/blog/backend/02-cache-redis/vendors/keydb/" data-link-title="KeyDB" data-link-desc="Redis multi-threaded fork、active-replication、Snap 採用">KeyDB</a>（source）跟 <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> / <a href="/blog/backend/02-cache-redis/vendors/valkey/" data-link-title="Valkey" data-link-desc="Redis fork、Linux Foundation 託管、BSD 授權">Valkey</a>（target）。跑 6 維 diff dimension audit 後判定為 <strong>Type B drop-in</strong>（KeyDB 是 Redis fork、RESP 相容、RDB/AOF 相容），但 active-active replication 跟 multi-threading 特性回退需要額外處理。</p></blockquote>
<h2 id="為什麼從-keydb-遷回">為什麼從 KeyDB 遷回</h2>
<p>KeyDB 是 Snap 維護的 Redis fork，主要差異化在多線程和 active-active replication。遷回的 driver：</p>
<ul>
<li><strong>維護活躍度疑慮</strong>：KeyDB 的 release cadence 跟 Redis/Valkey 主線比較慢，部分組織擔心長期維護與安全 patch 的及時性</li>
<li><strong>Valkey 生態收斂</strong>：Valkey 在 Linux Foundation 治理下快速演進（8.x 多線程改進），KeyDB 的多線程優勢逐漸縮小</li>
<li><strong>Active-active 不再需要</strong>：業務不再需要跨 region active-active、或改用 application 層處理衝突解析</li>
<li><strong>社群與工具生態</strong>：Redis/Valkey 的 client library、monitoring exporter、Operator 支援度更廣</li>
</ul>
<h2 id="6-維-diff-dimension-audit">6 維 diff dimension audit</h2>
<table>
  <thead>
      <tr>
          <th>維度</th>
          <th>評估</th>
          <th>等級</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Schema / API</td>
          <td>完全相容（fork 自 Redis 6.x）</td>
          <td>Low</td>
      </tr>
      <tr>
          <td>Operational model</td>
          <td>active-active → Sentinel/Cluster；multi-thread config 移除</td>
          <td>Medium</td>
      </tr>
      <tr>
          <td>Abstraction / paradigm</td>
          <td>相同</td>
          <td>Low</td>
      </tr>
      <tr>
          <td>Number of components</td>
          <td>相近（1 primary + N replica + HA）</td>
          <td>Low</td>
      </tr>
      <tr>
          <td>Application change</td>
          <td>endpoint 換、client config 微調</td>
          <td>Low</td>
      </tr>
      <tr>
          <td>Data topology</td>
          <td>RDB/AOF 完全相容</td>
          <td>Low</td>
      </tr>
  </tbody>
</table>
<p>Type B drop-in，工作重心在 active-active replication 拆除和效能 baseline 對齊。</p>
<h2 id="keydb-特有功能的處理">KeyDB 特有功能的處理</h2>
<table>
  <thead>
      <tr>
          <th>KeyDB 特有功能</th>
          <th>Redis/Valkey 對應</th>
          <th>遷移處理</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Multi-threading（<code>server-threads</code>）</td>
          <td>Redis I/O threads / Valkey 8 async I/O</td>
          <td>回到 Redis 後吞吐量下降是預期，需要 benchmark 建立新 baseline</td>
      </tr>
      <tr>
          <td>Active-active replication</td>
          <td>無原生等價。Redis 需要 application 層解衝突或用 CRDTs（社群方案）</td>
          <td>遷移前確認業務是否仍需 multi-master。不需要則直接切 Sentinel/Cluster</td>
      </tr>
      <tr>
          <td>FLASH storage（<code>storage-provider flash</code>）</td>
          <td>無原生等價。Redis 純記憶體</td>
          <td>遷移前把 FLASH 資料回收到記憶體，或接受遷移後記憶體需求上升。調整 <code>maxmemory</code></td>
      </tr>
      <tr>
          <td>Subkey expires</td>
          <td>Redis 無 subkey expire（只有 top-level key TTL）</td>
          <td>檢查 application 是否依賴 subkey expire；若有需要改寫為 top-level key 或用 sorted set 模擬</td>
      </tr>
      <tr>
          <td><code>EXPIREMEMBER</code> 命令</td>
          <td>Redis 無此命令</td>
          <td>grep application code 確認未使用；若有需改寫</td>
      </tr>
  </tbody>
</table>
<p>FLASH storage 的處理取決於冷資料比例。如果多數資料在 FLASH 上（用 <code>OBJECT FREQ</code> 確認），遷移後的 Redis 記憶體需求會大幅上升 — 要提前計算純記憶體所需容量，調整 instance 規格或改用更積極的 eviction policy。Subkey expires 和 <code>EXPIREMEMBER</code> 的影響範圍通常較小，但一旦 application 依賴就需要重構資料結構（用 top-level key + TTL 或 sorted set 模擬過期）。</p>
<h3 id="active-active-拆除">Active-active 拆除</h3>
<p>若 KeyDB 的 active-active replication 正在使用，遷移前需要先收斂為單主寫入：</p>
<ol>
<li>選定一個 region 的 KeyDB 為 primary，其他 region 停止寫入</li>
<li>等資料同步完成（replica 追上 primary offset）</li>
<li>從 primary 做 RDB export</li>
<li>用 RDB 建立 Redis/Valkey instance</li>
<li>各 region 的 application 切到新的 Redis/Valkey（Sentinel 或 Cluster）</li>
</ol>
<h2 id="資料搬遷">資料搬遷</h2>
<p>KeyDB 的 RDB 和 AOF 與 Redis 格式相容，搬遷流程跟 DragonflyDB 回退類似：</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="c1"># KeyDB 端觸發 BGSAVE</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">redis-cli -h keydb-host BGSAVE
</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="c1"># 複製 RDB 到 Redis/Valkey 資料目錄</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">scp keydb-host:/data/dump.rdb redis-host:/data/dump.rdb
</span></span><span class="line"><span class="ln">6</span><span class="cl">
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="c1"># Redis/Valkey 載入</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl">redis-server --dbfilename dump.rdb --dir /data</span></span></code></pre></div><p>如果使用了 FLASH storage，RDB 只包含記憶體中的資料。FLASH 上的冷資料需要先用 <code>OBJECT FREQ</code> 確認存取頻率，決定是要 warm up 到記憶體再 export，還是接受遷移後冷資料 cache miss 回源。</p>
<h2 id="效能差異預期">效能差異預期</h2>
<table>
  <thead>
      <tr>
          <th>指標</th>
          <th>KeyDB → Redis 變化</th>
          <th>應對</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>吞吐量</td>
          <td>下降（KeyDB multi-thread → Redis single-thread）</td>
          <td>評估是否需要 Cluster 分片補償。Valkey 8 的 async I/O 可部分彌補</td>
      </tr>
      <tr>
          <td>記憶體</td>
          <td>上升（若使用了 FLASH storage 被移除）</td>
          <td>提前計算純記憶體所需容量，調整 instance 規格</td>
      </tr>
      <tr>
          <td>Latency p99</td>
          <td>BGSAVE fork spike 可能出現</td>
          <td>KeyDB 的多線程降低了 fork 影響，回到 Redis 需要關注 <a href="/blog/backend/02-cache-redis/vendors/redis/persistence-fork-latency/" data-link-title="Redis 持久化與 fork latency：AOF、RDB 與那一次卡住整個 cluster 的 fork" data-link-desc="Redis 的 RDB save 與 AOF rewrite 都靠一次 fork()，而 fork 在大記憶體實例上會凍結主執行緒數百毫秒、複製分頁讓記憶體逼近翻倍。本文展開 AOF / RDB 的機制與 fsync 取捨、copy-on-write 的記憶體放大、5 個把持久化寫成延遲尖峰與資料遺失的 production 踩坑，以及 cache 場景到底要不要持久化的邊界">persistence fork latency</a></td>
      </tr>
      <tr>
          <td>Active-active latency</td>
          <td>不適用（已拆除）</td>
          <td>N/A</td>
      </tr>
  </tbody>
</table>
<h2 id="回退路徑">回退路徑</h2>
<p>Cache 資料可重建，回退方式：</p>
<ol>
<li>Application endpoint 改回 KeyDB</li>
<li>若 KeyDB 已下線，重啟 KeyDB 載入 Redis 的 RDB（格式相容）</li>
<li>Cache miss 回源到 DB 自然 warm up</li>
</ol>
<p>KeyDB 保留 7 天再下線。</p>
<h2 id="交接路由">交接路由</h2>
<ul>
<li>Source vendor：<a href="/blog/backend/02-cache-redis/vendors/keydb/" data-link-title="KeyDB" data-link-desc="Redis multi-threaded fork、active-replication、Snap 採用">KeyDB</a>、<a href="/blog/backend/02-cache-redis/vendors/keydb/active-active-replication/" data-link-title="KeyDB active-active 多主複製：last-write-wins 會默默吃掉哪一筆寫入" data-link-desc="KeyDB 的 active-active 讓兩個 master 都能寫、互相同步，聽起來解決了跨區寫入的所有問題——直到兩邊同時寫同一個 key，last-write-wins 默默丟掉其中一筆。本文展開 active-active 的複製機制與衝突語意、實機驗證雙向同步、5 個把多主複製寫成資料遺失與迴圈的 production 踩坑，以及哪些資料能放 active-active、哪些不能的邊界">KeyDB Active-Active Replication</a></li>
<li>Target vendor：<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> / <a href="/blog/backend/02-cache-redis/vendors/valkey/" data-link-title="Valkey" data-link-desc="Redis fork、Linux Foundation 託管、BSD 授權">Valkey</a></li>
<li>HA 重建：<a href="/blog/backend/02-cache-redis/vendors/redis/sentinel-ha-failover/" data-link-title="Redis Sentinel 與 failover 時序：從 master 死掉到 client 重連的每一段" data-link-desc="Redis Sentinel 的 failover 不是一個瞬間動作，是 down 偵測 → quorum 確認 → 選主 → 提升 → 配置廣播 → client 重連的一條時序鏈，每一段都有自己的延遲與失敗模式。本文展開 Sentinel 的判定模型與這條時序、5 個讓 failover 卡住或丟資料的 production 踩坑，以及 Sentinel 撐不住該往 Cluster 或 managed 走的邊界">Sentinel HA Failover</a></li>
<li>效能參考：<a href="/blog/backend/02-cache-redis/vendors/redis/persistence-fork-latency/" data-link-title="Redis 持久化與 fork latency：AOF、RDB 與那一次卡住整個 cluster 的 fork" data-link-desc="Redis 的 RDB save 與 AOF rewrite 都靠一次 fork()，而 fork 在大記憶體實例上會凍結主執行緒數百毫秒、複製分頁讓記憶體逼近翻倍。本文展開 AOF / RDB 的機制與 fsync 取捨、copy-on-write 的記憶體放大、5 個把持久化寫成延遲尖峰與資料遺失的 production 踩坑，以及 cache 場景到底要不要持久化的邊界">Persistence Fork Latency</a>、<a href="/blog/backend/02-cache-redis/vendors/redis/connection-pipeline-latency/" data-link-title="Redis 連線與 pipeline：RTT 稅、連線池與一次往返打包多命令" data-link-desc="Redis 單命令通常微秒級執行，但 application 端量到的延遲是毫秒級——差距全在網路往返（RTT）。pipelining 的本質不是『批次發命令』，是把 N 次 RTT 壓成 1 次。本文展開 RTT 會計、連線池配置、pipeline 與 MULTI 的差異、5 個把連線與往返寫成延遲與正確性問題的 production 踩坑，以及連線模型撞牆的邊界">Connection Pipeline Latency</a></li>
</ul>
]]></content:encoded></item><item><title>KeyDB active-active 多主複製：last-write-wins 會默默吃掉哪一筆寫入</title><link>https://tarrragon.github.io/blog/backend/02-cache-redis/vendors/keydb/active-active-replication/</link><pubDate>Tue, 16 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/02-cache-redis/vendors/keydb/active-active-replication/</guid><description>&lt;blockquote>
&lt;p>本文是 &lt;a href="https://tarrragon.github.io/blog/backend/02-cache-redis/vendors/keydb/" data-link-title="KeyDB" data-link-desc="Redis multi-threaded fork、active-replication、Snap 採用">KeyDB&lt;/a> overview 的 implementation-layer deep article。選型層（KeyDB vs Redis / DragonflyDB / Valkey、為何選 fork）見 overview；本文只處理「決定用 KeyDB active-active 後，衝突與一致性怎麼判」。命令實機驗證於 eqalpha/keydb image、最後檢查日 2026-06-16；複製機制以 &lt;a href="https://docs.keydb.dev/docs/active-rep/">KeyDB active-replication 文件&lt;/a> 為準。&lt;/p>&lt;/blockquote>
&lt;h2 id="兩邊都能寫聽起來太美好">兩邊都能寫，聽起來太美好&lt;/h2>
&lt;p>Redis 的複製是單向的：一個 master 寫、replica 唯讀。要跨區讓兩邊都能就近寫入，Redis 本身做不到（得靠應用層分區或外部工具）。KeyDB 的 active-active 把這個限制拿掉——兩個（含以上）KeyDB 節點都是 master、都能接受寫入、互相把寫入同步給對方。對「兩個 region 都要低延遲寫入同一份 cache」的場景，這聽起來解決了所有問題。&lt;/p>
&lt;p>問題藏在「兩邊同時寫同一個 key」的那一刻。active-active 沒有全域協調者來仲裁誰對誰錯，它用 last-write-wins（LWW）：比較兩筆寫入的時間戳，留下較晚的、默默丟掉較早的。多數時候沒事，但當兩個 region 在幾毫秒內各自更新同一個 key，其中一筆寫入會無聲消失——沒有錯誤、沒有日誌、application 以為自己寫成功了。&lt;/p>
&lt;p>理解 KeyDB active-active 就是理解這個取捨：它用 LWW 換到了「兩邊都能寫」的可用性，代價是放棄了強一致與「不丟寫入」的保證。本文展開複製機制、衝突語意，以及哪些資料放得進這個模型、哪些放進去就是 bug。&lt;/p>
&lt;h2 id="核心概念active-active-的複製與衝突語意">核心概念：active-active 的複製與衝突語意&lt;/h2>
&lt;p>active-active 不是「分散式交易」，它是「雙向非同步複製 + LWW 衝突解決」。理解它要抓三個點：&lt;/p>
&lt;p>&lt;strong>每個節點都是 active-replica&lt;/strong>。一般 Redis replica 是唯讀的；KeyDB 的 active-replica 既接受本地寫入、又接收對方的複製流。兩個節點互相設定對方為 master，形成雙向複製環。實機看到的 role 就是 &lt;code>active-replica&lt;/code>（不是 master / slave）。&lt;/p>
&lt;p>&lt;strong>複製是非同步的&lt;/strong>。本地寫入立即回 OK 給 client，之後才非同步傳給對方節點。這意味著兩個節點之間永遠有一個複製延遲窗口——在這個窗口內，兩邊看到的資料可能不同。這是 active-active 是 AP（可用性 + 分區容忍）而非 CP 的根本原因。&lt;/p>
&lt;p>&lt;strong>衝突用 last-write-wins 解決&lt;/strong>。同一個 key 在兩個節點被並發修改時，KeyDB 比較版本，保留較晚的寫入、丟棄較早的。沒有 merge、沒有 vector clock、沒有 application callback——就是比誰較晚。KeyDB 用 hybrid logical clock（HLC）排序、不是純 wall-clock，但 HLC 仍綁節點實體時鐘——時鐘不同步（clock skew）會直接影響哪一筆被判定為「較晚」。同步的是 key 的「值」不是「操作」，這也是為什麼並發 INCR 會互相覆蓋而非累加（見故障演練 Case 1）。&lt;/p>
&lt;p>&lt;strong>每筆寫入帶來源標記避免無限迴圈&lt;/strong>。A 的寫入同步給 B 後，B 不會再把它當成新寫入傳回 A（否則會無限循環）。KeyDB 用來源標記處理這個，但複製拓樸設計錯（例如環狀多節點）仍可能放大流量。&lt;/p>
&lt;h2 id="配置兩節點-active-active-的設定路徑">配置：兩節點 active-active 的設定路徑&lt;/h2>
&lt;p>實機驗證的最小雙主設定（兩個節點互相複製）：&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="c1"># 節點 A 與 B 都開 active-replica + multi-master&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">docker run -d --name kdb-a --network kdbnet -p 6401:6379 &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">&lt;span class="se">&lt;/span> eqalpha/keydb keydb-server --active-replica yes --multi-master yes
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">docker run -d --name kdb-b --network kdbnet -p 6402:6379 &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">&lt;span class="se">&lt;/span> eqalpha/keydb keydb-server --active-replica yes --multi-master yes
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">7&lt;/span>&lt;span class="cl">&lt;span class="c1"># 互相指向對方（形成雙向複製）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">8&lt;/span>&lt;span class="cl">keydb-cli -p &lt;span class="m">6401&lt;/span> replicaof kdb-b &lt;span class="m">6379&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">9&lt;/span>&lt;span class="cl">keydb-cli -p &lt;span class="m">6402&lt;/span> replicaof kdb-a &lt;span class="m">6379&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>實機驗證雙向同步（最後檢查日 2026-06-16）：&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="c1"># 寫 A、讀 B&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">keydb-cli -p &lt;span class="m">6401&lt;/span> SET fromA hello &lt;span class="c1"># → OK&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">keydb-cli -p &lt;span class="m">6402&lt;/span> GET fromA &lt;span class="c1"># → hello （A 的寫入同步到 B）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="c1"># 寫 B、讀 A（雙向）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">keydb-cli -p &lt;span class="m">6402&lt;/span> SET fromB world &lt;span class="c1"># → OK&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">keydb-cli -p &lt;span class="m">6401&lt;/span> GET fromB &lt;span class="c1"># → world （B 的寫入同步到 A）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="c1"># 確認 role 與複製鏈路&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">keydb-cli -p &lt;span class="m">6401&lt;/span> INFO replication &lt;span class="p">|&lt;/span> grep -E &lt;span class="s2">&amp;#34;role|master_link_status|connected_slaves&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="c1"># role:active-replica&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">&lt;span class="c1"># master_link_status:up&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">&lt;span class="c1"># connected_slaves:1&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>兩個節點都回報 &lt;code>role:active-replica&lt;/code>（不是傳統的 master / slave），&lt;code>master_link_status:up&lt;/code> 確認複製鏈路健康。寫入任一節點、另一節點都讀得到，這就是 active-active 的核心行為。&lt;/p></description><content:encoded><![CDATA[<blockquote>
<p>本文是 <a href="/blog/backend/02-cache-redis/vendors/keydb/" data-link-title="KeyDB" data-link-desc="Redis multi-threaded fork、active-replication、Snap 採用">KeyDB</a> overview 的 implementation-layer deep article。選型層（KeyDB vs Redis / DragonflyDB / Valkey、為何選 fork）見 overview；本文只處理「決定用 KeyDB active-active 後，衝突與一致性怎麼判」。命令實機驗證於 eqalpha/keydb image、最後檢查日 2026-06-16；複製機制以 <a href="https://docs.keydb.dev/docs/active-rep/">KeyDB active-replication 文件</a> 為準。</p></blockquote>
<h2 id="兩邊都能寫聽起來太美好">兩邊都能寫，聽起來太美好</h2>
<p>Redis 的複製是單向的：一個 master 寫、replica 唯讀。要跨區讓兩邊都能就近寫入，Redis 本身做不到（得靠應用層分區或外部工具）。KeyDB 的 active-active 把這個限制拿掉——兩個（含以上）KeyDB 節點都是 master、都能接受寫入、互相把寫入同步給對方。對「兩個 region 都要低延遲寫入同一份 cache」的場景，這聽起來解決了所有問題。</p>
<p>問題藏在「兩邊同時寫同一個 key」的那一刻。active-active 沒有全域協調者來仲裁誰對誰錯，它用 last-write-wins（LWW）：比較兩筆寫入的時間戳，留下較晚的、默默丟掉較早的。多數時候沒事，但當兩個 region 在幾毫秒內各自更新同一個 key，其中一筆寫入會無聲消失——沒有錯誤、沒有日誌、application 以為自己寫成功了。</p>
<p>理解 KeyDB active-active 就是理解這個取捨：它用 LWW 換到了「兩邊都能寫」的可用性，代價是放棄了強一致與「不丟寫入」的保證。本文展開複製機制、衝突語意，以及哪些資料放得進這個模型、哪些放進去就是 bug。</p>
<h2 id="核心概念active-active-的複製與衝突語意">核心概念：active-active 的複製與衝突語意</h2>
<p>active-active 不是「分散式交易」，它是「雙向非同步複製 + LWW 衝突解決」。理解它要抓三個點：</p>
<p><strong>每個節點都是 active-replica</strong>。一般 Redis replica 是唯讀的；KeyDB 的 active-replica 既接受本地寫入、又接收對方的複製流。兩個節點互相設定對方為 master，形成雙向複製環。實機看到的 role 就是 <code>active-replica</code>（不是 master / slave）。</p>
<p><strong>複製是非同步的</strong>。本地寫入立即回 OK 給 client，之後才非同步傳給對方節點。這意味著兩個節點之間永遠有一個複製延遲窗口——在這個窗口內，兩邊看到的資料可能不同。這是 active-active 是 AP（可用性 + 分區容忍）而非 CP 的根本原因。</p>
<p><strong>衝突用 last-write-wins 解決</strong>。同一個 key 在兩個節點被並發修改時，KeyDB 比較版本，保留較晚的寫入、丟棄較早的。沒有 merge、沒有 vector clock、沒有 application callback——就是比誰較晚。KeyDB 用 hybrid logical clock（HLC）排序、不是純 wall-clock，但 HLC 仍綁節點實體時鐘——時鐘不同步（clock skew）會直接影響哪一筆被判定為「較晚」。同步的是 key 的「值」不是「操作」，這也是為什麼並發 INCR 會互相覆蓋而非累加（見故障演練 Case 1）。</p>
<p><strong>每筆寫入帶來源標記避免無限迴圈</strong>。A 的寫入同步給 B 後，B 不會再把它當成新寫入傳回 A（否則會無限循環）。KeyDB 用來源標記處理這個，但複製拓樸設計錯（例如環狀多節點）仍可能放大流量。</p>
<h2 id="配置兩節點-active-active-的設定路徑">配置：兩節點 active-active 的設定路徑</h2>
<p>實機驗證的最小雙主設定（兩個節點互相複製）：</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="c1"># 節點 A 與 B 都開 active-replica + multi-master</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">docker run -d --name kdb-a --network kdbnet -p 6401:6379 <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>  eqalpha/keydb keydb-server --active-replica yes --multi-master yes
</span></span><span class="line"><span class="ln">4</span><span class="cl">docker run -d --name kdb-b --network kdbnet -p 6402:6379 <span class="se">\
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="se"></span>  eqalpha/keydb keydb-server --active-replica yes --multi-master yes
</span></span><span class="line"><span class="ln">6</span><span class="cl">
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="c1"># 互相指向對方（形成雙向複製）</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl">keydb-cli -p <span class="m">6401</span> replicaof kdb-b <span class="m">6379</span>
</span></span><span class="line"><span class="ln">9</span><span class="cl">keydb-cli -p <span class="m">6402</span> replicaof kdb-a <span class="m">6379</span></span></span></code></pre></div><p>實機驗證雙向同步（最後檢查日 2026-06-16）：</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="c1"># 寫 A、讀 B</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">keydb-cli -p <span class="m">6401</span> SET fromA hello   <span class="c1"># → OK</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">keydb-cli -p <span class="m">6402</span> GET fromA         <span class="c1"># → hello   （A 的寫入同步到 B）</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="c1"># 寫 B、讀 A（雙向）</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">keydb-cli -p <span class="m">6402</span> SET fromB world   <span class="c1"># → OK</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">keydb-cli -p <span class="m">6401</span> GET fromB         <span class="c1"># → world   （B 的寫入同步到 A）</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="c1"># 確認 role 與複製鏈路</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">keydb-cli -p <span class="m">6401</span> INFO replication <span class="p">|</span> grep -E <span class="s2">&#34;role|master_link_status|connected_slaves&#34;</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="c1"># role:active-replica</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="c1"># master_link_status:up</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="c1"># connected_slaves:1</span></span></span></code></pre></div><p>兩個節點都回報 <code>role:active-replica</code>（不是傳統的 master / slave），<code>master_link_status:up</code> 確認複製鏈路健康。寫入任一節點、另一節點都讀得到，這就是 active-active 的核心行為。</p>
<h2 id="production-故障演練">Production 故障演練</h2>
<h3 id="case-1並發寫同一-key一筆寫入無聲消失">Case 1：並發寫同一 key、一筆寫入無聲消失</h3>
<p><strong>徵兆</strong>：兩個 region 的 application 各自更新同一個 user 的 cache（例如 profile），事後發現其中一個 region 的更新「沒生效」——但寫入時 application 收到的是 OK，沒有任何錯誤。</p>
<p><strong>根因</strong>：active-active 的 LWW。兩筆寫入在複製延遲窗口內並發發生，KeyDB 比較時間戳保留較晚的、默默丟棄較早的。application 兩邊都以為自己寫成功了（本地確實 OK），但同步後只有一筆存活。</p>
<p><strong>修法</strong>：</p>
<ol>
<li>不要讓同一個 key 被多個 region 並發寫——按 key 分區（user X 的寫入永遠路由到 region A），把多主退化成「就近讀 + 單點寫」</li>
<li>真的需要多點寫的計數器類資料，用 CRDT 語意的結構（KeyDB 的 LWW 不適合 counter，並發 INCR 會互相覆蓋而非累加）</li>
<li>接受 LWW 是 cache 的取捨——可重建的 cache 副本丟一筆寫入可回源重算，不可重建的資料不該放 active-active</li>
<li>衝突無聲是最危險的——加應用層的寫入審計（不靠 KeyDB 告警）</li>
</ol>
<h3 id="case-2clock-skew-讓較晚的判定錯亂">Case 2：clock skew 讓「較晚」的判定錯亂</h3>
<p><strong>徵兆</strong>：明明 region B 後寫的值，最後存活的卻是 region A 先寫的值——LWW 的「後寫者勝」失效。</p>
<p><strong>根因</strong>：LWW 比較時間戳，但兩個節點的系統時鐘若沒同步（clock skew），「較晚」的判定就錯了。B 的時鐘慢了 200ms，B 後寫的值帶的時間戳反而比 A 早，被判定為「較舊」丟棄。</p>
<p><strong>修法</strong>：</p>
<ol>
<li>所有 KeyDB 節點強制 NTP 時鐘同步，把 skew 壓到毫秒級</li>
<li>監控節點間的時鐘偏差，skew 超過複製延遲就有 LWW 判定錯亂風險</li>
<li>對時間敏感的衝突，LWW 本質不可靠——時鐘永遠無法完美同步，這是 LWW 模型的固有弱點</li>
<li>需要正確衝突解決的場景，不要用 LWW 的 active-active，改強一致儲存</li>
</ol>
<h3 id="case-3複製延遲下的-stale-read">Case 3：複製延遲下的 stale read</h3>
<p><strong>徵兆</strong>：region A 寫入後，立刻有請求打到 region B 讀同一 key，讀到舊值；幾百毫秒後再讀才是新值。</p>
<p><strong>根因</strong>：active-active 是非同步複製，A 的寫入要經過網路傳到 B 才可見。在這個複製延遲窗口內，B 讀到的是 stale 值。跨 region 的延遲窗口比同 AZ 大得多。</p>
<p><strong>修法</strong>：</p>
<ol>
<li>寫後需要立即一致讀的路徑，讀同一個寫入的節點（read-your-writes 綁定到寫入 region）</li>
<li>監控節點間複製延遲，跨 region 的延遲是 stale window 的下界</li>
<li>接受最終一致——這是 active-active 的本質，cache 場景多數可容忍短暫 stale</li>
<li>不可容忍 stale 的資料不適合 active-active，走單寫入點 + 跨區唯讀 replica</li>
</ol>
<h3 id="case-4複製拓樸設計錯流量放大或迴圈">Case 4：複製拓樸設計錯、流量放大或迴圈</h3>
<p><strong>徵兆</strong>：加了第三個 active 節點組成環狀後，節點間流量異常放大、CPU 升高，甚至同一筆寫入被反覆傳遞。</p>
<p><strong>根因</strong>：active-active 多節點（&gt; 2）的拓樸需要小心設計。全互連（full mesh）下每筆寫入要傳給所有其他節點、流量隨節點數平方成長；環狀拓樸若來源標記處理不當可能放大傳遞。</p>
<p><strong>修法</strong>：</p>
<ol>
<li>多節點 active-active 優先用 full mesh 但控制節點數（active-active 不適合大量節點）</li>
<li>監控節點間複製流量，異常放大代表拓樸或來源標記問題</li>
<li>大規模多區優先考慮「每區單寫入點 + 跨區唯讀」而非全 active-active</li>
<li>active-active 的甜蜜點是 2-3 個區的雙向就近寫，不是大規模 mesh</li>
</ol>
<h3 id="case-5節點重連後的全量重同步衝擊">Case 5：節點重連後的全量重同步衝擊</h3>
<p><strong>徵兆</strong>：一個節點短暫斷線後重連，重連瞬間 CPU / 網路尖峰，期間延遲升高。</p>
<p><strong>根因</strong>：節點斷線時間過長、超過複製 backlog 能覆蓋的範圍，重連時要做全量重同步（full resync）——對方節點要產生快照（fork、見 <a href="/blog/backend/02-cache-redis/vendors/redis/persistence-fork-latency/" data-link-title="Redis 持久化與 fork latency：AOF、RDB 與那一次卡住整個 cluster 的 fork" data-link-desc="Redis 的 RDB save 與 AOF rewrite 都靠一次 fork()，而 fork 在大記憶體實例上會凍結主執行緒數百毫秒、複製分頁讓記憶體逼近翻倍。本文展開 AOF / RDB 的機制與 fsync 取捨、copy-on-write 的記憶體放大、5 個把持久化寫成延遲尖峰與資料遺失的 production 踩坑，以及 cache 場景到底要不要持久化的邊界">Redis persistence 的 fork 成本</a>，KeyDB 繼承 Redis 的 fork 機制）並傳輸整個 dataset。</p>
<p><strong>修法</strong>：</p>
<ol>
<li>設足夠大的 <code>repl-backlog-size</code>，讓短暫斷線走部分同步（partial resync）而非全量</li>
<li>重同步的 fork 成本跟記憶體 headroom 相關，節點要留 fork 空間</li>
<li>監控 <code>master_link_status</code>，頻繁 down / up 代表網路不穩、要先修網路</li>
<li>跨 region 的 active-active 對網路穩定性敏感，不穩的鏈路會頻繁觸發重同步</li>
</ol>
<h2 id="capacity--cost-邊界">Capacity / cost 邊界</h2>
<p>active-active 的容量判讀，核心在衝突率與複製健康：</p>
<table>
  <thead>
      <tr>
          <th>訊號</th>
          <th>健康區間</th>
          <th>警戒與動作</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>同 key 跨節點並發寫入率</td>
          <td>接近 0（key 按區分區）</td>
          <td>高 → LWW 丟寫入風險、改 key 分區</td>
      </tr>
      <tr>
          <td>節點間 clock skew</td>
          <td>&lt; 複製延遲（毫秒級）</td>
          <td>大 → LWW 判定錯亂、強制 NTP</td>
      </tr>
      <tr>
          <td>節點間複製延遲</td>
          <td>跨 region 可接受的 stale 窗</td>
          <td>過大 → stale read 嚴重、檢查網路</td>
      </tr>
      <tr>
          <td><code>master_link_status</code></td>
          <td><code>up</code></td>
          <td>頻繁 down → 網路不穩、會觸發重同步</td>
      </tr>
      <tr>
          <td>active 節點數</td>
          <td>2-3（雙向就近寫）</td>
          <td>過多 → mesh 流量平方成長、改單寫入點拓樸</td>
      </tr>
  </tbody>
</table>
<p>撞牆後的路由判斷：</p>
<ul>
<li><strong>需要正確的衝突解決 / 不能丟寫入</strong>：LWW 不保證，走強一致儲存（<a href="/blog/backend/01-database/" data-link-title="模組一：資料庫與持久化" data-link-desc="整理 SQL、transaction、migration 與 repository adapter 的後端實務">database 模組</a> 的 multi-region 一致性方案）或單寫入點架構。</li>
<li><strong>需要 counter / 累加語意的多點寫</strong>：LWW 會讓並發 INCR 互相覆蓋，KeyDB active-active 不適合，改 CRDT 或單點 counter。</li>
<li><strong>跨 region 但可接受單寫入點</strong>：用 Redis / Valkey 的單向複製（一區寫、其他區唯讀），比 active-active 簡單且無衝突。</li>
<li><strong>大規模多區</strong>：active-active 的甜蜜點是 2-3 區，更大規模走 managed 的跨區方案（<a href="/blog/backend/02-cache-redis/vendors/aws-elasticache/" data-link-title="AWS ElastiCache" data-link-desc="AWS managed Redis / Valkey / Memcached">ElastiCache Global Datastore</a> 的 active-passive）。</li>
</ul>
<h2 id="整合--下一步">整合 / 下一步</h2>
<p>active-active 是 KeyDB 區別於 Redis 的核心能力之一，但它的取捨跨多個子系統：</p>
<ul>
<li><strong>跟 <a href="/blog/backend/02-cache-redis/vendors/keydb/" data-link-title="KeyDB" data-link-desc="Redis multi-threaded fork、active-replication、Snap 採用">KeyDB overview</a></strong>：overview 點到 active-active 是 last-write-wins、本文展開它什麼時候默默丟資料。</li>
<li><strong>跟 <a href="/blog/backend/02-cache-redis/vendors/redis/persistence-fork-latency/" data-link-title="Redis 持久化與 fork latency：AOF、RDB 與那一次卡住整個 cluster 的 fork" data-link-desc="Redis 的 RDB save 與 AOF rewrite 都靠一次 fork()，而 fork 在大記憶體實例上會凍結主執行緒數百毫秒、複製分頁讓記憶體逼近翻倍。本文展開 AOF / RDB 的機制與 fsync 取捨、copy-on-write 的記憶體放大、5 個把持久化寫成延遲尖峰與資料遺失的 production 踩坑，以及 cache 場景到底要不要持久化的邊界">Redis persistence / fork latency</a></strong>：KeyDB 繼承 Redis 的 fork 機制，節點重連的全量重同步付 fork 成本。</li>
<li><strong>跟 <a href="/blog/backend/02-cache-redis/cache-copy-freshness-boundary/" data-link-title="2.7 Cache Copy Boundary 與 Freshness" data-link-desc="說明快取何時只是可重建副本，何時會影響交易、權限或配額正確性。">cache copy boundary</a></strong>：active-active 的 stale window 與 LWW 丟寫入，本質是「cache 副本的新鮮度與一致性邊界」議題的多主版本。</li>
<li><strong>跟 <a href="/blog/backend/09-performance-capacity/cases/snap-gcp-keydb-cross-cloud/" data-link-title="9.C35 Snap：GCP &#43; KeyDB 在 multi-cloud 架構下的低延遲快取" data-link-desc="Snap 用 GCP 上的 KeyDB cluster 減少跨 cloud cache 延遲、用 TPU 訓練廣告推薦模型">Snap KeyDB cross-cloud case</a></strong>：Snap 用 KeyDB 的主因是 cross-cloud latency 治理（cache 與 application 共置），active-active 的雙向就近寫是這類 multi-cloud 場景的工具，但要按 key 分區避開 LWW 衝突。</li>
</ul>
<h2 id="相關連結">相關連結</h2>
<ul>
<li>上游 vendor 頁：<a href="/blog/backend/02-cache-redis/vendors/keydb/" data-link-title="KeyDB" data-link-desc="Redis multi-threaded fork、active-replication、Snap 採用">KeyDB</a></li>
<li>對照 vendor：<a href="/blog/backend/02-cache-redis/vendors/dragonflydb/shared-nothing-multicore-architecture/" data-link-title="DragonflyDB shared-nothing 多核架構：用 scale-up 取代 Redis Cluster" data-link-desc="Redis 要靠 Cluster 分片才能用滿一台多核機器，DragonflyDB 賭的是相反方向——單一進程 thread-per-core、shared-nothing、把單機推到 Redis 要好幾個 shard 才達到的規模。本文展開 thread-per-core 與 dashtable 的架構、fork-less snapshot、5 個把架構假設寫成 production 事故的踩坑，以及 scale-up 撞牆該回 Cluster 的邊界">DragonflyDB 多核架構</a>、<a href="/blog/backend/02-cache-redis/vendors/redis/sentinel-ha-failover/" data-link-title="Redis Sentinel 與 failover 時序：從 master 死掉到 client 重連的每一段" data-link-desc="Redis Sentinel 的 failover 不是一個瞬間動作，是 down 偵測 → quorum 確認 → 選主 → 提升 → 配置廣播 → client 重連的一條時序鏈，每一段都有自己的延遲與失敗模式。本文展開 Sentinel 的判定模型與這條時序、5 個讓 failover 卡住或丟資料的 production 踩坑，以及 Sentinel 撐不住該往 Cluster 或 managed 走的邊界">Redis Sentinel failover</a>（單向複製的 HA）</li>
<li>上游概念：<a href="/blog/backend/02-cache-redis/cache-copy-freshness-boundary/" data-link-title="2.7 Cache Copy Boundary 與 Freshness" data-link-desc="說明快取何時只是可重建副本，何時會影響交易、權限或配額正確性。">2.7 cache copy boundary</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>