前言

當系統從單體架構走向微服務(Microservices),並部署在動態的雲端環境(如 AWS EC2、ECS 或 EKS)中時,**「無狀態(Stateless)」「水平擴展(Scale-out)」**成為了架構設計的顯學。在這樣的環境下,Redis 不僅僅是快取,更是撐起微服務之間狀態共享、限流、併發控制與事件驅動的核心骨幹。

然而,當 Redis 運行在真實的高流量生產環境加上複雜的網路拓樸中時,往往會衍生出許多教科書上沒寫的「痛點」。本文將依循架構師 → 後端工程師 → DevOps/SRE 三個視角,深度解析 Redis 在 AWS 微服務環境下的經典場景、常見災難以及對應的解決方案。


📖 本文架構導覽

層次 主題
Part 1:部署選型 EC2/ECS/EKS 環境的 Redis 部署模式選擇
Part 2:實戰場景 Session、快取、分散式鎖、事件佇列
Part 3:架構師視角 命名規範、選型決策、快取一致性、讀寫分離
Part 4:後端工程師視角 Bloom Filter、Lua Script、Pipeline 優化
Part 5:DevOps/SRE 視角 優雅退出、維護視窗、多 Region、可觀測性
Part 6:維運雷區清單 生產環境禁忌與常見錯誤設定

Part 1:部署選型 — 自托管 vs AWS ElastiCache

在 AWS 環境中,我們通常有兩種選擇:

面向 自行託管(Self-hosted on EC2/EKS) AWS ElastiCache for Redis
控制度 高,可深度調整核心參數 中,多數參數透過 Parameter Group 設定
HA 建置 需自行配置 Sentinel / Cluster 開箱即用,Multi-AZ 自動 Failover
自動備份 需自行處理 RDB/AOF 備份與 S3 上傳 開箱即用,並支援 Point-in-Time Restore
維運成本 極高
適用情境 法規限制、需極致調校 絕大多數量產環境的首選

⚠️ 自行託管 Redis 於 ECS:可行性與坑點分析

雖然 Redis 比 Kafka 輕量許多,但要在 ECS (尤其是 Fargate) 上跑穩一個生產等級的 Redis,依然有幾個硬傷需要克服:

1. 記憶體管理的「生死線」 (Memory vs. OOM)

  • 問題:Redis 的記憶體管理極度依賴 maxmemory 設定。不同於實體機,ECS 容器沒有 Swap 空間緩衝。
  • ECS 挑戰:ECS Task 有硬性的記憶體限制。如果 Redis 因為 Fork (執行 BGSAVE) 或流量激增導致記憶體略微超過 Task Limit,AWS 會直接 SIGKILL 掉整個 Container,導致服務瞬間中斷。
  • 建議:必須將 maxmemory 設為 Task Limit 的 60-70%,預留空間給作業系統與 Redis 的 Fork 進程。

2. 持久化 (RDB/AOF) 與儲存效能

  • 問題:Redis 的 AOF 寫入非常頻繁,對磁碟延遲極度敏感。
  • ECS 挑戰:雖然 ECS 支援掛載 EBS 或 EFS,但 EFS 的隨機 I/O 延遲對 Redis 效能是致命的。若使用 EBS,在 Task 重新調度 (Reschedule) 時,掛載卷的切換延遲可能導致 Redis 啟動與恢復時間變長。

3. HA 叢集 (Sentinel/Cluster) 的維運複雜度

  • 問題:Redis Cluster 需要固定的 IP 或可互相識別的名稱。
  • ECS 挑戰:ECS Task 的 IP 是動態的,雖然可配合 Cloud Map,但當發生 Failover 時,重新廣播集群拓樸與客戶端連動的複雜度遠高於 ElastiCache 提供的單一 DNS Endpoint。

💡 最終建議

  • 自建 ECS Redis:僅適合測試環境,或資料完全不具備持久化價值(丟了沒關係)的短暫快取場景。
  • 生產環境:強烈建議使用 AWS ElastiCache,它所提供的自動補丁、無損 Failover 與完善的監控指標,能節省下的維運成本遠大於基礎設施費用的價差。

【踩坑警告】
許多團隊初期為了省錢把 Redis 裝在和 App 同一個 EC2 上。當流量突增或 CPU 飆高時,應用程式和 Redis 互相搶佔資源,導致延遲嚴重惡化。生產環境中 Redis 必須獨立部署,並優先使用 ElastiCache。


Part 2:實戰場景

🎯 場景一:分散式 Session 與狀態共享

場景描述

在 EKS/ECS 環境中,Pod 與 Container 隨時可能因為擴縮容(HPA/Auto Scaling)或節點滾動更新(Rolling Update)而銷毀。若使用者的登入狀態(Session)存在本機記憶體,Pod 重啟後使用者就會被強制登出,嚴重影響體驗。

解法:將 Session 與 JWT Token 的黑名單、Refresh Token 集中儲存於 Redis(使用 HashString 結構),所有微服務實例都向同一個 Redis 驗證。搭配合理的 TTL,讓 Session 自動失效。

🚨 問題:連線數耗盡 (Connection Leaks)

當 EKS 叢集突然擴展出數百個 Pod,每個 Pod 內的 App(Node.js、Spring Boot 等)都會建立一組獨立的連線池(Connection Pool)。

  • 現象:ElastiCache 的 CurrConnections 指標狂飆,超過節點連線上限(依 Instance Type 不同,通常約 65,000),新 Pod 啟動失敗並一直噴 Redis Timeout
  • 解決方法
    1. 縮減每個 Pod 的連線池大小:嚴格控制 max-activemax-idle。節點越多,每個節點的連線池應越小。
    2. 引入 Proxy 層:超大規模 EKS 叢集可在 App 與 Redis 之間加入 Proxy(如 Twemproxy 或 Envoy),由 Proxy 進行連線收斂與多路復用,大幅減少 Redis 側實際連線數。

🎯 場景二:高併發快取與資料庫減壓

場景描述

API Gateway 接收請求後,微服務先向 Redis 查詢熱點資料(如商品資訊、使用者資料),未命中才回頭查 RDS(Aurora/PostgreSQL),查詢後結果寫回快取(Cache-Aside 模式)。

🚨 問題:Hot Key 導致單一 Shard CPU 滿載與快取擊穿

在 Redis Cluster 模式下,資料依 Hash Slot 分散至各 Shard。若某個 Key(如秒殺商品、百萬網紅的動態)極度熱門,所有流量會集中打在同一個 Shard。

  • 現象:ElastiCache Cluster 整體 CPU 僅 20%,但某個 Shard 的 CPU 頂到 100% 並開始 Timeout。快取擊穿(Cache Breakdown) 發生後,大量流量直接灌入 RDS,資料庫連帶崩潰。
  • 解決方法
    1. 兩級快取(Local Cache + Redis):在應用端(JVM 的 Caffeine、Node.js 的 LRU-Cache)建立數秒效期的本地快取。熱點流量在第一層就被擋除 95~99%,只有極少數請求真正打進 Redis。
    2. 打散 Hot Key(Key Sharding):將熱點 Key 複製多份(如 product:1001_r1product:1001_r2_r10),讀取時隨機選一份,使請求分散至不同 Shard。
    3. 互斥鎖防止快取擊穿:當快取失效瞬間,用 SETNX 確保只有一個執行緒能回查 DB 並重建快取,其他執行緒等待或返回舊資料,避免「雪崩式」的 DB 查詢。

🎯 場景三:分散式鎖與冪等性保障

場景描述

微服務架構中,因網路抖動或訊息系統的「至少一次投遞(At-Least-Once)」特性,同一個操作可能被觸發多次(如重複扣款、重複建立訂單)。Redis 分散式鎖是防止重複操作的第一道防線。

🚨 問題:鎖提早過期導致並發保護失效

常見做法是 SET key uuid NX EX 30(30 秒後鎖自動釋放以防 Pod 崩潰造成死鎖)。

  • 現象:Pod A 搶到鎖後,業務邏輯執行了 40 秒。第 30 秒時鎖自動到期,Pod B 搶入並同時執行,同一筆訂單被兩台機器處理。更糟的是,Pod A 執行完去 DEL key 時,實際刪掉的是 Pod B 剛建立的鎖,讓 Pod C 又衝了進來。
  • 解決方法
    1. 唯一 Value + Lua Script 原子解鎖:解鎖時必須先用 Lua Script 確認 GET key 的值等於自己當初放入的 UUID,才能執行 DEL,確保不會誤刪別人的鎖。
    2. Watch Dog 看門狗機制(以 Redisson 為例):框架在後台啟動一個守護執行緒,只要業務尚未完成,每隔 lockWatchdogTimeout / 3(預設每 10 秒)自動幫鎖延長 TTL,從根本解決鎖提前過期的問題。
    3. 資料庫唯一索引作為終極兜底:Redis 分散式鎖在極端網路分區(如 Clock Drift、Redlock 的 Fencing Token 缺失)下仍有極低機率失效。涉及核心金流,資料庫的 Unique Constraint 是最後且最可靠的防線,任何正確的冪等性設計都不應省略。

🎯 場景四:非同步事件驅動與 Redis Streams

場景描述

在 ECS 部署的輕量級 Worker 服務中,需要一個簡單的任務佇列——例如非同步發送 Email、同步訂單狀態。相比架設 Kafka(基礎設施成本高)或用 AWS SQS(輪詢延遲較長),Redis 5.0+ 的 Streams 提供了輕量的中間選擇,支援消費者群組(Consumer Group)與訊息 ACK 機制。

🚨 問題:記憶體暴增(OOM)與 XPENDING 訊息堆積

Redis 的所有資料(包含 Stream)都在記憶體中。若消費者處理速度跟不上生產者,或 Consumer Pod 因 Bug 持續報錯而不發出 XACK,訊息會無限在 XPENDING 狀態堆積。

  • 現象:Redis 記憶體直線上衝,最終觸發 Linux OOM Killer 將整個 Redis 程序砍掉,或觸發 Eviction Policy 將其他重要的快取鍵踢出。
  • 解決方法
    1. 強制限制 Stream 長度XADD mystream MAXLEN ~ 50000 * field value,設定最大訊息保留數量,超過時舊訊息自動捨棄。
    2. 獨立 CronJob 清理 XPENDING:用 XPENDING mystream group - + 100 定期偵測停滯超過閾值的訊息,將其轉入死信佇列(Dead Letter Queue)並強制 ACK,避免殭屍訊息永久阻塞消費者進度。
    3. CloudWatch 告警:設定 ElastiCache 的 Evictions > 0 與 DatabaseMemoryUsagePercentage > 80% 的告警,在問題擴大前及時介入。

Part 3:架構師視角

📐 一、Key 命名規範(Key Naming Convention)

在多微服務環境中,沒有統一命名規範的 Redis 快速淪為「命名垃圾堆」,難以排查問題且極易發生跨服務 Key 碰撞。

建議命名格式{service}:{module}:{identifier}:{field}

1
2
3
4
5
# 正確示範
order-service:idempotency:tx-abc123
user-service:session:uid-456
product-service:cache:sku-789:detail
rate-limit:api:ip-1.2.3.4

注意事項

  • 不建議使用過長的 Key(Key 本身也占記憶體)。
  • 對於有數量級增長規律的 Key(如每個使用者都有一個),應為其設定 TTL,避免 Redis 逐漸被過期的僵屍 Key 佔滿記憶體。
  • 在 Redis Cluster 中,可利用 Hash Tag({})強制多個 Key 落在同一個 Slot,以便配合 Lua Script 做跨 Key 的原子操作:{order:123}:lock{order:123}:status

📐 二、Redis Sentinel vs Cluster 選型決策

面向 Sentinel(哨兵模式) Cluster(叢集模式)
設計目標 高可用性(HA):主從切換自動化 水平擴展(Scalability)
資料分片 否,所有資料在主節點 是,16384 個 Slot 分佈於多個 Shard
記憶體上限 受限於單一節點記憶體 可線性擴展
多 Key 原子操作 無限制 受 Hash Slot 限制,除非使用 Hash Tag
客戶端複雜度 高(需支援 Cluster Protocol)
ElastiCache 對應 Cluster Mode Disabled Cluster Mode Enabled
適用情境 一般量級,資料量 < 100GB 超大資料量、極高吞吐,需分片

決策建議:大多數中型服務從 Cluster Mode Disabled(近似 Sentinel)出發即可。若單節點記憶體開始吃緊(> 60%),再評估遷往 Cluster Mode。兩者在 ElastiCache 上無法直接就地升級,需要透過備份還原或 Application-level Migration,切換代價高。請在一開始就做好容量規劃。


📐 三、快取一致性問題(Cache Consistency)

這是最容易被輕描淡寫、但實務上最棘手的議題。當資料庫數據更新時,Redis 快取如何同步?

策略 說明 優點 缺點
Cache Invalidation(主動失效) 更新 DB 後立即 DEL 對應的快取 Key 簡單,下次請求自然重建快取 在高並發情境下,DEL 與下次 SET 之間有短暫空窗,可能造成多個請求同時回查 DB
Write-Through 更新 DB 的同時,同步更新 Redis 快取永遠與 DB 一致 每次寫入都有雙倍延遲;若 Redis 寫入失敗需處理 Rollback
Write-Behind(Write-Back) 先寫 Redis,非同步批量寫入 DB 寫入速度極快 若 Redis 宕機,未落地的資料永久遺失,金融場景嚴禁使用

微服務環境的特殊挑戰:若多個微服務都快取了同一份資料(例如,Price Service 和 Order Service 都各自快取了商品價格),當 Price Service 更新後,如何通知 Order Service 也失效其快取?常見解法是透過 Domain Event(領域事件),由訊息佇列(SNS/SQS、Kafka)廣播失效訊號,各服務訂閱後自行清除本地快取。


📐 四、讀寫分離(Read Replica)與 Replica Lag

在 ElastiCache 中,可以為 Primary 節點建立多個 Read Replica,將讀取流量分散至 Replica 以降低 Primary 負擔。

  • 客戶端設定要點:確保讀操作路由至 Replica Endpoint,寫操作路由至 Primary Endpoint。許多客戶端框架(如 Jedis、ioredis)已內建此路由邏輯。
  • Replica Lag 問題:Replica 的複製是非同步的,通常有數毫秒的延遲。若業務邏輯要求「寫入後立即讀到最新值(Read-Your-Writes)」,必須將該次讀取強制路由至 Primary,而非 Replica。ElastiCache 的 ReplicationLag 指標可協助監控此延遲。

Part 4:後端工程師視角

🛠️ 一、Bloom Filter 防快取穿透

快取穿透(Cache Penetration) 是指查詢一個在 DB 和 Redis 中都不存在的資料(如惡意爬蟲隨機帶入無效的使用者 ID),請求每次都直接穿透快取層打到 DB。

解法:布隆過濾器(Bloom Filter)

在服務啟動時,將所有合法的 ID(如資料庫現存的所有商品 SKU)載入 Bloom Filter。後續請求進來時,先讓 Bloom Filter 判斷此 Key 是否「可能存在」:

  • 若 Bloom Filter 判定「一定不存在」→ 直接返回空,不打 Redis 也不打 DB。
  • 若 Bloom Filter 判定「可能存在」→ 正常走快取再查 DB 的流程。

AWS 實作選項

  1. Redis Enterprise / RedisBloom 模組:提供原生 BF.ADDBF.EXISTS 指令(注意:AWS ElastiCache 原生不支援,需用 ElastiCache Serverless 或自建 Redis Stack)。
  2. 應用層實作:在 EKS/ECS 應用的記憶體中維護一個 Bloom Filter(Java: Guava 或 Redisson;Node.js: bloom-filters 套件),定期從 DB 全量同步合法 ID,是最常見且最實際的做法。

🛠️ 二、Lua Script 的原子性操作

Redis 雖然是單執行緒,但多個指令組合在一起仍非原子(間隙中可能被其他客戶端插入指令)。Lua Script 是讓多條指令在 Redis 中原子執行的唯一正確方式。

場景一:安全解鎖(分散式鎖)

1
2
3
4
5
6
7
-- 只有當鎖的 Value 等於自己的 UUID 時,才允許刪除
-- KEYS[1] = 鎖的 Key, ARGV[1] = 自己的 UUID
if redis.call("GET", KEYS[1]) == ARGV[1] then
return redis.call("DEL", KEYS[1])
else
return 0
end

場景二:滑動視窗限流(Sliding Window Rate Limit)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
-- KEYS[1] = 限流用的 ZSET Key
-- ARGV[1] = 目前時間戳(ms), ARGV[2] = 時間視窗大小(ms), ARGV[3] = 最大允許次數, ARGV[4] = 本次請求的唯一 ID
local key = KEYS[1]
local now = tonumber(ARGV[1])
local window = tonumber(ARGV[2])
local limit = tonumber(ARGV[3])
local req_id = ARGV[4]
-- 清除視窗外的舊紀錄
redis.call("ZREMRANGEBYSCORE", key, 0, now - window)
-- 計算視窗內的請求數量
local count = redis.call("ZCARD", key)
if count < limit then
redis.call("ZADD", key, now, req_id)
redis.call("EXPIRE", key, math.ceil(window / 1000))
return 1 -- 允許通過
else
return 0 -- 超出限制,拒絕
end

🛠️ 三、Pipeline 批量操作減少 RTT

每次 Redis 指令都是一次網路來回(Round-Trip Time, RTT)。在 EKS 的 Pod 與 ElastiCache 之間,即使同 AZ 也有 0.1~0.5ms 的網路延遲。若在迴圈中依序發送 1,000 個 GET

1
1,000 × 0.5ms RTT = 500ms(在後端邏輯裡憑空多出半秒)

解法:Pipeline 或批量指令

  • MGET / MSET:一次網路請求取回多個 Key 的值,最適合讀取場景。
  • Pipeline:將多個指令打包成一批,一次送出並等待一次回應。適用於指令彼此無依賴關係的情境(如批量初始化計數器)。

注意:在 Redis Cluster 中,MGET 的多個 Key 若落在不同 Slot(不同 Shard),會被客戶端拆分成多個子請求分別發送,無法保證整體原子性,且效益會降低。使用 Hash Tag 可強制讓相關 Key 落在同一 Slot 以最大化 Pipeline 效益。


Part 5:DevOps / SRE 視角

🔧 一、Graceful Shutdown 與 Rolling Update 期間的連線問題

在 EKS 執行 Rolling Update 時,舊 Pod 收到 SIGTERM 信號開始退出。若此時 Pod 內的 Redis 客戶端尚未優雅關閉連線,可能導致:

  • 進行中的 Redis 請求突然被中斷,客戶端收到 ECONNRESET 錯誤。
  • 連線池中的「幽靈連線」未被正常釋放,ElastiCache 側的連線計數短暫飆升。

解決方法(以 Kubernetes 為例)

1
2
3
4
5
6
7
8
# 在 Pod Spec 的 container 中設定
lifecycle:
preStop:
exec:
# 給 App 一個緩衝時間完成 in-flight 請求後再退出
command: ["/bin/sh", "-c", "sleep 5"]
# 確保 terminationGracePeriodSeconds 大於 preStop 等待時間 + 最長請求處理時間
terminationGracePeriodSeconds: 60

同時,應用程式必須監聽 SIGTERM 信號,在收到後:

  1. 停止接受新請求。
  2. 等待進行中的請求完成。
  3. 呼叫 Redis 客戶端的 quit()disconnect() 方法優雅關閉連線池。

🔧 二、ElastiCache 維護視窗(Maintenance Window)衝擊

AWS 在設定的維護時段(Maintenance Window)內可能對 ElastiCache 執行小版本升級。期間 Primary 節點會進行 Failover,有約 10~60 秒的主從切換時間。

  • 未做防禦的現象:應用程式在 Failover 期間發出的所有 Redis 請求都會失敗,導致 API 批量返回 500 錯誤。
  • 解決方法
    1. 客戶端設定 Retry with Exponential Backoff:Failover 期間,客戶端自動以指數退避重試(如第 1 次 100ms 後重試,第 2 次 200ms,第 3 次 400ms…),而非立即失敗。大多數主流客戶端(ioredis、Jedis、StackExchange.Redis)都有內建設定。
    2. 將維護視窗排在流量最低峰:在 AWS Console 中明確設定維護視窗為深夜離峰時段。
    3. 應用程式的降級策略:在 Redis 不可用時,關鍵功能應有 Fallback 邏輯(如限流器暫時放寬、快取失效時直接查 DB 並設定保護機制),而非直接拋出錯誤給使用者。

🔧 三、跨 Region 架構(Multi-Region with Global Datastore)

當系統需要跨 AWS Region 部署(如主要服務在 ap-northeast-1,災備或低延遲副本在 us-east-1)時,ElastiCache 提供了 Global Datastore 功能(僅支援 Cluster Mode Disabled):

  • 讀取:各 Region 的應用程式讀取本地的 Replica,延遲低至毫秒等級。
  • 寫入:只能寫入 Primary Region 的主節點,再非同步複製至其他 Region(複製延遲通常 < 1 秒)。
  • 限制:不支援 Active-Active 雙向寫入。若需要多 Region 同時寫入且保持一致,需引入更複雜的 CRDT(Conflict-free Replicated Data Type)解決方案,或改用 Redis Enterprise。

🔧 四、可觀測性(Observability)三支柱

支柱 工具 / 方法 關鍵指標或設定
Metrics(指標) AWS CloudWatch (ElastiCache) CurrConnectionsCacheHits/CacheMissesEvictionsDatabaseMemoryUsagePercentageReplicationLagCPUUtilization
Metrics(指標) Prometheus + redis_exporter Sidecar (EKS) 可將 Redis 內部指標(INFO 命令輸出)暴露至 Prometheus,搭配 Grafana Dashboard 呈現豐富的視覺化報表
Slow Log(慢查詢) Redis SLOWLOG 指令 設定 slowlog-log-slower-than 10000(單位:微秒),SLOWLOG GET 10 取出最近 10 筆慢查詢,定期執行是找出 KEYS * 等危險指令的最快方法
Logging(日誌) ElastiCache + CloudWatch Logs 開啟 Slow Log 與 Engine Log 輸出至 CloudWatch Logs Group,配合 Metric Filter 設定告警

建議必設的 CloudWatch 告警

1
2
3
4
5
- Evictions > 0         → 記憶體不足,正在踢出資料
- CacheMissRate > 30% → 快取命中率過低,大量請求穿透至 DB
- ReplicationLag > 5s → Replica 同步嚴重落後
- CPUUtilization > 70% → 接近單執行緒瓶頸,需升級 Instance 或調整指令
- CurrConnections > (閾值 × 0.8) → 連線數接近上限,預警

Part 6:維運雷區清單

☠️ 禁忌一:生產環境絕對禁止 KEYS *

Redis 是單執行緒,KEYS * 會全量掃描直到結束。在資料量大時,整個 Redis 就卡死了。此時微服務所有呼叫 Timeout,連帶觸發 EKS 的 Liveness/Readiness Probe 失敗,K8s 開始大規模重啟 Pod,發生完美的雪崩效應。

解法:禁止寫入到程式碼中。若必須模糊搜尋 Key,改用非阻塞的 SCAN cursor MATCH pattern COUNT 100,分批迭代掃描,絕不阻塞主執行緒。


☠️ 禁忌二:Eviction Policy 設定錯誤

  • noeviction(預設):記憶體滿後拒絕所有寫入並報錯。若 Redis 被當作純快取使用,滿了就全面崩盤,是最危險的設定。
  • 建議:純快取場景改設為 allkeys-lru(淘汰最近最少使用的任意 Key)。

最重要原則:若在同一個 Redis 實例中混存了「快取」(可重建)與「持久狀態」(Session、分散式鎖、Idempotency Key)兩類資料,任何 Eviction Policy 都不安全——noeviction 讓快取爆炸,allkeys-lru 可能隨機踢掉正在使用中的鎖。強烈建議將這兩類資料物理分離到兩個獨立的 ElastiCache 實例,分別套用最適合的設定。


☠️ 禁忌三:跨可用區的隱藏成本

EKS Node Group 可能散佈在多個 AZ(ap-northeast-1a1b1c)。若 Pod 在 1a 但 Redis Primary 在 1c

  • 效能影響:每次讀寫多 1~3ms RTT(在大量高頻讀寫場景下累積可觀)。
  • 費用影響:AWS 對跨 AZ 資料傳輸收費(約 $0.01/GB),高吞吐的 Redis 通訊可能每月產生意外的帳單。

解法:評估使用 ElastiCache 的 Topology Aware 路由,或透過 Kubernetes Topology Spread Constraints 與 Node Affinity,盡量讓同一服務的 Pod 與其 Redis 節點部署在同一個 AZ。


結語

從「只是加個快取」到成為整個微服務架構的核心基礎設施,Redis 的每一種應用模式都承載著對應場景下的工程智慧與血淚教訓。

這些實戰問題與解法並非孤立的技巧,它們背後有一條共同的主線:在動態、不可預測的分散式環境中,你不應假設任何事情保證成功,你需要為每一個失敗點設計降級與兜底策略。

希望本文能幫助讀者在真正遭遇這些問題之前,就先做好架構上的準備。