文件 v1.0.0

正常模式讀取

本頁說明正常模式下 Get 依序查哪幾層、何時判定 Redis 失敗,以及失敗後如何在同一次呼叫內降級。

流程

graph TB
    Start[Get key] --> R1{記憶體命中?}
    R1 -->|命中且有效| Hit[回傳 Data,背景回寫 Redis]
    R1 -->|命中但過期| Exp[刪記憶體與檔案,回傳 Not found]
    R1 -->|未命中| R2[redis.Get 最多 MaxRetry 次]
    R2 -->|成功且可解析為 Cache| Store[寫入記憶體並回傳]
    R2 -->|全部失敗| Switch[切入 Fallback 模式]
    Switch --> Local[改走 Fallback 讀取路徑]

步驟

步驟 條件 行為 原始碼
1 記憶體命中且未過期 立即回傳,並以 goroutine 寫回 Redis(讀取修補) get.go:24-37
2 記憶體命中但已過期 刪除記憶體項目與本地 JSON 檔,回傳 Not found get.go:28-33
3 記憶體未命中 向 Redis 執行 GET,最多 MaxRetry 次(預設 3);成功且可解析就寫入記憶體並回傳 get.go:39-50
4 重試用盡 取得寫鎖、切入 fallback 模式(啟動健康檢查)、釋放鎖,接著呼叫 Fallback 模式讀取 get.go:52-58

記憶體優先

正常模式下記憶體快取優先於 Redis。同一實例寫入或讀取過的鍵,Get 一律回傳記憶體中的值,不會再查 Redis;因此在 Redis 端被外部修改或刪除的鍵,本實例仍會讀到舊值,直到該項目過期。

重試行為

項目 行為
間隔 重試之間沒有等待
單次逾時 由 go-redis client 預設值決定(實例只設定 Addr/Password/DB)
計為失敗的情況 連線錯誤、redis.Nil(鍵不存在)、值無法解析為 Cache 結構

什麼值能從 Redis 讀回

步驟 3 以 json.Unmarshal 把 Redis 值解析為 Cache 結構(key/data/type/timestamp/ttl),但 Set 寫入 Redis 的只是 Data 本身的 JSON(字串會去掉引號)。實測結果:

情境 結果
同一實例 Set 後 Get 記憶體命中,正常回傳
另一個實例(或重啟後)Get 同一個鍵 解析失敗 → 切入 fallback → 本地無檔 → Not found
Get 不存在的鍵 redis.Nil → 切入 fallback → Not found

後兩種情況都會讓實例離開正常模式,直到健康檢查下一次 Ping 成功並完成恢復。詳見 已知限制。

範例

value, err := rf.Get("user:1")
if err != nil {
    // 鍵不存在、已過期,或本地檔案解析失敗
    log.Println(err)
    return
}
fmt.Println(value)

Get 回傳的錯誤只有 Not found 與 Failed to parse 兩種訊息,不會回傳 Redis 連線錯誤。

EN