前端與後端的快取策略比較:Redis 與 Apollo 的 key-value 應用實戰

更新日期: 2025 年 5 月 31 日

不論是打開網頁時瞬間讀取的內容,還是資料庫查詢變快的優化技巧,快取(Cache) 幾乎無所不在。

而在許多教學或系統設計中,我們常看到這樣的說法:

快取是以「key-value」的形式儲存在記憶體中。

例如常見的快取系統 Redis、或是前端的 Apollo Client,它們都選擇 key-value 結構來儲存資料。

但為什麼不是其他形式?這樣的設計有什麼優點?Redis 又和 Apollo Client 有什麼不同?

本篇文章將帶你一步步釐清這些問題。

什麼是 key-value 結構?為什麼適合做快取?

key-value 是什麼?

在程式設計與資料儲存中,key-value(鍵值對)結構 是一種非常常見的資料表示法,其核心概念是:

透過一個唯一的 key(鑰匙),對應一筆特定的資料 value(內容),用來快速存取或查找資料。

你可以把它想像成「查字典」的過程:

  • 字典中的單字是 key(例如:英文單字 "apple"
  • 對應的解釋是 value(例如:蘋果,一種水果)

在程式語言中,這樣的資料結構看起來通常是這樣:

{
  "user:1": { id: 1, name: "小明", age: 18 },
  "user:2": { id: 2, name: "小華", age: 20 }
}
  • "user:1" 是 key,用來識別這筆資料
  • { id: 1, name: "小明", age: 18 } 是 value,代表實際的資料內容

這種形式在不同語言中有不同的名稱與實作方式,例如:

程式語言對應資料結構名稱
JavaScriptObject、Map
PythonDictionary(dict)
JavaHashMap
Gomap
Redis(伺服器)支援多種型別,如 String、Hash 等 key 對應結構(不是語言)

🔔 注意:Redis 並不是一種程式語言,而是一個高效能的快取伺服器,它使用 key-value 來儲存資料,並支援多種資料型別(如 String、Hash、List、Set)。

我們在這裡只是將它列入,表示它也支援 key-value 的操作,並不是說它是語言的一種。

為什麼快取適合用 key-value?

快取(Cache)的主要目標是:

讓系統能夠在極短時間內取回常用資料,避免每次都從慢速來源(如資料庫、API)重新取得。

使用 key-value 結構來實作快取,有幾個明確的優勢:

🚀 快速查找,效能極高(O(1))

大多數 key-value 系統背後都是用 Hash Table(雜湊表) 實作。

這是一種能以幾乎「常數時間」查找資料的結構,也就是:

  • 不管資料量多少,只要知道 key,就能在 O(1) 時間內取回 value。
  • 比起陣列(O(n))或平衡樹(O(log n)),查詢速度極快。

這使得 key-value 結構非常適合「需要秒查資料」的場景,例如:

  • 查詢使用者資料
  • 顯示熱門商品清單
  • 判斷是否登入、權限檢查等

🧩 結構簡單、儲存彈性高

與傳統 SQL 資料表相比,key-value 不需事先定義資料表或欄位格式,也不需要考慮 JOIN、關聯設計等複雜邏輯。

你只需要定義:

快取名稱(key)  資料內容(value)

舉例來說:

cache["weather:Taipei"] = { temperature: 30, humidity: 70 }

這就代表你把「台北天氣資料」快取起來,之後再用 "weather:Taipei" 就能快速取出。

🧠 存取邏輯直覺,開發者容易管理

每筆資料的存取都透過清楚的 key 來標示,不需要額外學習查詢語言。這讓開發者可以直接掌控:

  • 要存什麼 → 自訂 key(如 user:123article:456
  • 要查什麼 → 用 key 查,不需寫 SQL

這種資料管理方式,非常適合高頻讀取、動態生成內容的情境。

📌 為什麼不是用其他資料結構?

雖然也可以用陣列(Array)、JSON 結構或關聯式資料表來存資料,但在「快取」這個使用情境下:

  • 速度第一
  • 結構簡單
  • 記憶體使用效率高

這三個條件讓 key-value 結構成為首選。

不管你用的是:

  • Redis → 伺服器端快取(共用資料)
  • Apollo Client → 前端快取(單一使用者)
  • 自寫的記憶體快取邏輯 → 本地程式中的變數暫存

它們幾乎都是以 key-value 為核心資料結構設計的。

前端快取 vs 後端快取:架構、儲存位置與角色總覽

當我們談到「快取(Cache)」時,其實可以依照資料儲存的位置與服務的作用層級,分為兩大類:

  • 前端快取(Client-side Cache)
  • 後端快取(Server-side Cache)

這兩種快取都是為了提升整體效能與使用者體驗,但它們所佔用的記憶體位置、管理方式、影響範圍完全不同。

前端快取:存在使用者裝置的快取

前端快取 指的是資料儲存在使用者個人裝置上的快取,這些裝置包括:筆電、桌機、手機等。

當使用者開啟網站,載入的 JavaScript 程式就會在「本機」的資源中建立快取。

📍 儲存在哪裡?

實體對應如下:

快取方式儲存媒介實體對象說明
JavaScript 變數、Apollo 快取瀏覽器記憶體(RAM)使用者的電腦或手機記憶體,屬於揮發性
localStorage / sessionStorage瀏覽器硬碟儲存區(Persistent)使用者本機硬碟或 SSD
IndexedDB瀏覽器內建資料庫使用者硬碟空間,可儲存大型結構化資料
HTTP Cache(圖片、CSS、JS 等)磁碟快取區使用者電腦的硬碟 Cache 區塊

🧠 什麼情況下會使用?

  • 快取登入資訊、查詢結果、使用者偏好、滾動位置
  • 儲存離線狀態資料(如 PWA 網頁應用)
  • 搭配 Apollo Client 快取 GraphQL 查詢結果,避免重複發送請求

📌 小結:

前端快取就是在使用者自己的電腦「記」資料,速度極快,能提供流暢的 UI 體驗。但這些資料只屬於「當前使用者」,也只在「這個瀏覽器」有效。

後端快取:存在伺服器的快取

後端快取 則是指資料儲存在伺服器端的記憶體或硬碟,由網站系統或 API 所掌控,屬於跨使用者共用的快取策略。

這些快取通常部署在:

  • Web Server、Application Server(應用層)
  • Cache Server(如 Redis、Memcached)
  • CDN 節點(邊緣節點伺服器)

📍 儲存在哪裡?

實體對應如下:

快取方式儲存媒介實體對象說明
Redis / Memcached伺服器記憶體(RAM)後端主機的記憶體空間,速度快但不持久
程式變數快取(如全域變數)應用程式記憶體空間運行中的應用後端服務,如 Node.js、Python
Nginx Reverse Proxy 快取伺服器硬碟或 SSD 快取目錄快取 HTML、圖片等靜態頁面
CDN(例如 Cloudflare、Akamai)全球節點 RAM / SSD分布式網路伺服器,靠近使用者地理位置

🧠 什麼情況下會使用?

  • 快取熱門文章、熱門商品資訊
  • 快取查詢結果以降低資料庫查詢負載
  • 快取圖片、CSS、JS 等靜態資源
  • 快取 API 回應結果、使用者 Session 等

📌 小結:

後端快取屬於「系統共用資源」,資料通常來自資料庫查詢後的結果,可以讓多人共用、減少伺服器負擔。資料存在的地方是伺服器,不是使用者自己電腦。

前端快取 vs 後端快取:總比較

項目前端快取後端快取
儲存在哪裡?使用者裝置(RAM / localStorage / 硬碟)伺服器(RAM / 硬碟 / 快取伺服器)
控制權使用者端 JavaScript 控制由後端架構設計與部署者控制
使用對象單一使用者、單一瀏覽器會話多位使用者共用、跨裝置統一
是否可離線存取視儲存機制而定(localStorage 可,記憶體不可)通常不可(除非搭配離線資料包)
常見技術或工具Apollo Client、React Query、localStorageRedis、Memcached、Nginx、CDN、程式記憶體快取等

🧩 為什麼要前後端都快取?分層快取設計的必要性

在現代 Web 應用中,使用者對「即時性」與「順暢體驗」的要求越來越高,而後端伺服器也面臨龐大的流量與資料存取壓力。這時候,如果只依賴單一層的快取機制(只有前端或只有後端),往往無法同時兼顧效能與穩定性。

這就是為什麼我們需要「分層快取(Cache Layering)」的設計概念。

🧪 實際情境流程解析

以下是一個常見情境,以「商品頁」為例:

📦 初次載入流程(Cold Start)

  1. 使用者打開商品頁面
  2. 前端(例如 React + Apollo Client)發送查詢請求
  3. 後端伺服器收到請求,先檢查 Redis 快取
  • 如果 Redis 裡有資料(命中),就直接回傳資料,不必查資料庫
  • 如果 Redis 裡沒有資料(未命中),就查詢資料庫,取得資料後:
    • 將資料存入 Redis(方便下一次使用)
    • 回傳資料給前端
  1. 前端收到資料後,寫入 Apollo Client 的快取
  • 未來在同一瀏覽器中,使用者只要沒重新整理,就能從 Apollo 快取直接取得這筆資料

🔁 再次載入流程(Revisit)

使用者切換頁面、或點擊返回商品頁時:

  • 前端 Apollo 會先檢查本地快取
  • 如果快取中有資料,立即顯示,不需等待網路請求
  • 如果快取過期或不存在,再發送請求給後端
  • 後端再次收到請求 → 可能 Redis 已命中 → 快速處理

這整個流程中,同一筆資料最多只查一次資料庫,其餘都來自快取層。

🔍 每一層快取的角色與好處

快取層級所在位置主要目的好處
前端快取使用者裝置(瀏覽器記憶體)提升單一使用者的操作體驗– 立即呈現資料– 減少閃爍、延遲感– 避免重複發送相同請求
後端快取伺服器(Redis)減輕資料庫負載、加速回應給所有使用者– 減少資料庫 I/O– 同一資料可被多人共用– 整體回應速度提升

🧠 為什麼兩者缺一不可?

  • 如果只做後端快取(例如只有 Redis):
  • 每次頁面載入仍需請求伺服器 → 使用者會看到載入動畫或白畫面
  • 無法提供滑順的 UI 切換體驗
  • 如果只做前端快取(例如只有 Apollo):
  • 首次載入或重新整理頁面時仍需查詢資料庫 → 系統承受不了高流量
  • 所有使用者都要自己查一次資料 → 資料重複處理,資源浪費

前端快取優化個人操作體驗,後端快取優化整體系統效能,兩者結合才能發揮最大效益。

📌 觀念總結:不是互相替代,而是互相補強

「分層快取」的設計不是前端 vs 後端的對立,而是:

🔁 一種協同機制,讓每一層根據它「最近的位置」與「負責的範圍」去處理資料。

✅ 小結:掌握快取層級與角色,才能正確使用工具

當你理解了「誰的資料?存在誰的裝置?誰能共用?誰是即時的?」這些基本問題後,就會更自然地理解各種快取工具的設計初衷:

工具所屬層級核心目的
Apollo Client前端快取快速讀取 UI 查詢資料、避免閃爍
React Query前端快取管理 REST 或 GraphQL 快取狀態
Redis / Memcached後端快取加速伺服器回應、降低資料庫負擔

這些工具本質上都使用 key-value 結構來快取資料,只是分別發生在「使用者端」與「伺服器端」,協同合作才能打造出真正快速、穩定的應用系統。

Redis 是什麼?它在後端快取中的角色?

在我們理解了「後端快取」是儲存在伺服器端、由整個系統共用的快取層之後。

你一定會好奇:那麼,這層快取實際是由什麼工具實作的?

答案就是目前最廣泛使用、也最成熟的快取伺服器之一 —— Redis

Redis 是什麼?一個高效能的記憶體型資料庫

Redis(Remote Dictionary Server) 是一套開源的、以記憶體為基礎的資料庫系統,專門設計用於處理高效率的資料存取與快取工作。

與傳統資料庫(如 MySQL、PostgreSQL)不同,Redis 並不是為了長期儲存而設計,而是著重於:

  • 極速存取速度(毫秒等級)
  • 彈性的資料快取管理
  • 支援高併發的大量資料請求

這使得它非常適合被放在伺服器端應用程式的中間層 —— 介於應用伺服器與資料庫之間,用來暫時快取熱門資料,避免每次都要重新查詢資料庫。

🧠 Redis 的核心特性解析:

特性說明
⚡ 記憶體運作,速度極快所有資料都儲存在 RAM 中,不需讀寫硬碟,因此存取速度是資料庫的數十倍以上。
🔑 key-value 結構為主體使用類似 JavaScript 物件的方式儲存資料,例如:"user:123" → {...}。
🔧 支援多種資料型別除了 String 外,還支援 Hash、List、Set、Sorted Set、Bitmaps、HyperLogLog 等複雜資料結構。
⏳ 支援自動過期與淘汰策略每筆資料都可以設定 TTL(Time-To-Live),也支援 LRU/LFU 等自動清除機制。
🌍 可分散式部署與高可用性可部署成主從架構,支援 replication、cluster 模式與自動故障轉移(failover)。

總結來說,Redis 就是一台「快取專用的記憶體伺服器」,為整個應用系統提供即時、可控、彈性且共用的快取層,在大多數微服務與高併發系統中扮演關鍵角色。

Redis 的應用場景與快取策略

Redis 不只是單純的 key-value 快取工具,透過其豐富的資料結構與指令設計,可以實作各種高效能服務功能:

應用場景使用方式與效益說明
✅ 資料庫查詢結果快取將熱門查詢結果快取起來,避免同樣的查詢一再存取資料庫,有效降低 DB 負載。
✅ 使用者 Session 管理儲存使用者登入資訊,支援跨伺服器共用登入狀態,實作高可用的登入系統。
✅ 排行榜 / 即時計算使用 Sorted Set 結構快速統計、排序分數,常見於遊戲排名、熱銷商品排行等功能。
✅ 訊息佇列(Message Queue)搭配 List 結構可實作簡易的非同步任務排程,或使用 Pub/Sub 實作即時事件推播。
✅ API 結果快取(GraphQL、REST)將相同參數查詢的 API 結果存入 Redis,未來直接命中快取快速回應。

Redis 的彈性與效能讓它不只是「資料庫的副手」,而是後端系統中獨立的一層 —— 快取層(Cache Layer),你可以精確地定義哪些資料要快取、快取多久、過期後怎麼處理,並針對使用場景設計最佳的資料流。

Redis 快取資料的真實位置是?

前面說過,Redis 是部署在伺服器上的服務,那它的快取資料實際存在於哪裡?答案是:

  • Redis 使用的是伺服器的 RAM(記憶體)
  • 通常部署在與應用後端同一台主機上,或作為獨立快取伺服器
  • 所有寫入 Redis 的資料,都會暫存在記憶體中,並依 TTL 或 LRU 策略清除

這表示:Redis 快取是屬於伺服器端資源,不會佔用使用者端的任何記憶體或儲存空間。

Redis 在「分層快取」中的角色

在前後端分層快取架構中,Redis 扮演的是:

高頻率共用資料的後端快取中心

具體貢獻包括:

  • 減少資料庫壓力:讓大量使用者查詢相同資料時,只需查一次資料庫
  • 提升系統整體效能:將熱門內容搬到記憶體中,回應時間大幅縮短
  • 與前端快取協同運作:例如第一次請求從 Redis 取得,後續由 Apollo Client 快取接手

小結:為什麼 Redis 是後端快取的首選?

Redis 並不是單純用來「存資料」的資料庫,而是專門設計來解決「怎麼讓資料更快、可控地被多人共享使用」這件事。在大多數現代應用中,它已經成為後端架構中不可或缺的核心快取層。

只要你面對的是:

  • 高流量
  • 重複查詢
  • 多使用者共用的動態資料

那麼,Redis 幾乎是你最佳的後端快取選擇。

Apollo Client 是什麼?它在前端快取中的角色?

在上一節,我們介紹了伺服器端的 Redis 如何作為後端快取中心,幫助整個系統承擔高併發請求、減輕資料庫壓力。

現在讓我們回到使用者端,看看在「前端快取」中,最具代表性的工具 —— Apollo Client,又扮演什麼樣的角色。

Apollo Client 是什麼?一套結合 GraphQL 的前端快取解決方案

Apollo Client 是一個專為 GraphQL API 設計的前端函式庫,廣泛應用於 React、Vue、Angular 等現代框架中。它不只是資料請求工具,最大的價值在於:

內建高階快取機制,讓前端開發者可以在無需手動處理狀態的情況下,自動管理查詢結果的存取、重用、更新與同步。

在沒有 Apollo 的情況下,開發者得自行維護 UI 狀態、管理請求 loading/error 狀態、決定資料該重取還是使用舊資料,非常繁瑣。而 Apollo 不僅讓你「拿得到資料」,更幫你「記得資料」,這就是前端快取的核心價值。

Apollo 快取的原理與結構:記憶體中的智慧資料庫

Apollo 的快取是運作在「瀏覽器的記憶體中(JavaScript heap)」,屬於前端快取的一種。

它的運作邏輯精準對應到 GraphQL 的資料模型,設計出一套以 物件型別與識別值為基礎 的 key-value 快取策略。

🚀 快取建立流程:

  1. 當使用者執行一段 GraphQL 查詢:
query GetUser {
  user(id: 1) {
    id
    name
  }
}
  1. 假設伺服器回傳:
{
  "data": {
    "user": {
      "__typename": "User",
      "id": "1",
      "name": "小明"
    }
  }
}
  1. Apollo 會根據 __typename + id 建立快取 key,儲存如下:
{
  "User:1": { __typename: "User", id: "1", name: "小明" }
}
  1. 若之後有其他查詢命中相同 User:1,Apollo 就會直接從快取中回傳資料,完全不必再請求伺服器。

🔄 與瀏覽器記憶體的關係:

  • Apollo 快取存在「瀏覽器 JavaScript 記憶體中」,屬於揮發性快取(重整就會消失)
  • 每一位使用者的快取資料互不相通,僅作用於自己的瀏覽器環境

⚙️ Apollo 的快取特性與優勢

特性詳細說明
✅ 自動快取命中查詢結果會自動快取,若 GraphQL 查詢命中已有資料,Apollo 自動回傳快取值
✅ 與 UI 深度整合快取變動會觸發 UI 自動更新,搭配 React 時無需手動設計資料同步邏輯
✅ 適合個人化場景適合快取當前使用者的暫存資料(如使用者資訊、查詢內容、表單暫存),不會被其他使用者共用
✅ 可自訂快取策略提供 cache-first、cache-and-network、no-cache 等策略,開發者可依需求調整快取行為
✅ 支援客製化結構與合併邏輯可自定義 typePolicies 決定哪些欄位該合併、哪些資料該覆蓋,適應複雜查詢場景

📌 Apollo 的快取行為是預設開啟的,但你可以微調其策略與結構,靈活控制資料要從快取拿、從網路拿,還是兩者並用。

使用情境:Apollo 快取解決了什麼問題?

開發場景有無 Apollo 快取的差異
頁面間切換時資料是否重新載入?✅ 有 Apollo:秒切畫面、資料直接命中快取❌ 沒 Apollo:重新請求、畫面閃爍
查詢相同資料是否會重複送出請求?✅ 有 Apollo:查一次就記住結果,避免重複查詢❌ 沒 Apollo:每次都查一次資料庫
使用者操作是否需等資料回來才能 render?✅ 有 Apollo:快取先 render,再背景更新資料❌ 沒 Apollo:畫面得等 API 回應後才顯示

Apollo 快取真正做到的是:為使用者創造「資料永遠在那裡」的錯覺,讓操作體驗像桌面應用一樣滑順。

Redis 與 Apollo:同樣是 key-value,分工卻不同層級

項目Redis(後端快取)Apollo Client(前端快取)
儲存位置伺服器記憶體(RAM)使用者端記憶體(瀏覽器 JavaScript Heap)
使用對象多位使用者共用單一使用者、單一瀏覽器實例
控制權後端開發者或 DevOps 團隊管理前端工程師透過程式控制與設定
適合快取的資料類型共用資料:熱門商品列表、Session 狀態、API 結果私人資料:單頁查詢內容、暫存表單資料、使用者資訊等
快取格式與邏輯key-value,可支援多種複雜資料結構(如 List、Sorted Set)key-value,以 __typename + id 為快取鍵,貼合 GraphQL 結構

快取協同:從 Redis 到 Apollo 的資料接力

在實務中,我們常見以下「快取接力」場景:

  1. 使用者開啟頁面,前端發送查詢請求
  2. 後端優先從 Redis 快取回應(減輕資料庫壓力)
  3. 回傳結果後,前端 Apollo 快取再儲存這筆資料
  4. 同一位使用者再次開啟該頁面時 → 直接從 Apollo 快取中命中
  5. 若過一段時間快取過期 → 自動重查,重新建立快取層

這種「前後端快取接力棒」的設計,就是建立現代應用最關鍵的效能優化策略:分層快取(Layered Caching)

Redis 幫你加速整個系統,但 Apollo 才是讓使用者感受到「資料已經在那裡」的關鍵角色。

它讓 GraphQL 應用在前端實現:

  • 更快的資料讀取
  • 更滑順的頁面切換
  • 更少的 API 請求
  • 更穩定的 UI 狀態同步

✅ 結語:Redis 與 Apollo 都用 key-value,是為了極速查找與管理

無論是 Redis 還是 Apollo Client,它們都選擇 key-value 結構來快取資料,是因為這種結構擁有:

  • 快速查找的能力(O(1))
  • 靈活彈性的儲存方式
  • 適合暫時保存與快速取得資料的應用場景

不同的是,Redis 是後端的快取伺服器,適合整個系統使用。

Apollo Client 是前端的快取機制,主要為單一使用者提供快速畫面回應。

兩者定位不同、使用場景也不同,但核心設計理念一致,都是為了讓資料存取更快速、更有效率

Similar Posts

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *