📢 [文章新增公告] 新增 為 Kubernetes 而生的 GitOps 工具 - ArgoCD 介紹與說明統一機密、身份與加密的管理系統 - HashiCorp Vault 介紹與說明 文章,歡迎點擊前方連結前往查看 💙
目前 Blog 頁籤支援折疊側邊欄功能,在閱讀文章會更方便,歡迎多加利用 💪
GCP Memorystore HA 高可用性 failover 測試

GCP Memorystore HA 高可用性 failover 測試

發布於 2024-07-02 · 最後更新於 2025-08-08

此文章主要針對 GCP Memorystore failover 來做測試,測試 Memorystore 高可用性 (HA) 在標準 Standard Tier failover 故障轉移需要多久,以及不同 replica 條件下轉移是否會有差異等等。


文件說明

首先我們可以先閱讀 Google Memorystore for Redis FAQ 文章,可以得知 Standard Tier 在 failover 轉移,大約會花 30 秒左右。


Google Memorystore for Redis FAQ

Google Memorystore for Redis FAQ


我們也可以從 High availability for Memorystore for Redis 文章中知道,當 Primary 資料庫發生故障時,就會發生故障轉移。在轉移期間,Primary Endpoint 和 Read Endpoint 會自動重新導向新的 Primary 資料庫 和 Replica。這時候 Primary Endpoint 和 Read Endpoint 連線都會被刪除


when a failover is triggered

when a failover is triggered


因次會導致有幾秒鐘連不到 Redis。重新連接時,將使用原本的 IP 位址即可自動重新定向到新的服務上。故障轉移後,不需要調整連線設定。


接下來我們來實際測試看看,我們分成兩個測試組,分別為:1m1s、1m2s 的方式,來看看故障轉移時,需要花多久,還有不同 Replica 條件下會不會有差異。

實作測試 (1m1s)

可以只用之前 IaC 文章來建立,或是用 UI 來建立 Memorystore,這邊用 IaC 來示範:

terraform {
  source = "${get_path_to_repo_root()}/modules/memorystore"
}

include {
  path = find_in_parent_folders()
}

inputs = {
  name           = "ian-1m1s"
  memory_size_gb = 5
  region         = "asia-east1"
  network        = "bbin-XXX"
  replica_count  = 1
  redis_version = "REDIS_6_X"
  redis_configs = {
    "maxmemory-policy" = "allkeys-lru"
  }
}

這邊 memorystore module 預設是 Standard Tier,另外小提醒,如果要使用 Replica memory_size_gb 最小必須是 5G。


設定監控

建立完成後,我們也先把監控給拉出來,設定可以參考 About manual failover,主要是選擇 Cloud Memorystore Redis > replication > Node role


監控圖表

監控圖表


可以看到 node-0 跟 node-1,數字 1 代表 Primary (node-0)、數字 0 代表 Replica (node-1)


查看 describe

我們也可以下指令查看:

gcloud redis instances describe ian-1m1s --region=asia-east1 --project={project_id}

describe 畫面

describe 畫面


可以看到 currentLocationId 代表現在 Primary (node-0) asia-east1-a,locationId 代表最初配置 Primary 區域,alternativeLocationId 則是最初配置 Replica 的區域,因此我們也可以在故障轉移後,來查看區域是否變化。詳細可以參考:gcloud verification


接著我們可以參考 Initiate a manual failover 文章,手動來觸發 failover,這邊提醒一下 手動 failover 有分兩種資料保護模式:limited-data-loss、force-data-loss,詳細請看 Optional data protection mode,這邊測試就不討論兩種保護模式,都使用預設的 limited-data-loss 來測試。


寫 shell 測試 redis 連線

另外,我們在寫一個 shell 到 GKE 裡面 (用同 VPC 打) 打 Memorystore Redis 的 Primary Endpoint 以及 Read Endpoint,看看當 failover 是不是會有連不上的問題 ~

apiVersion: v1
kind: Pod
metadata:
  name: redis-test
  namespace: default
spec:
  initContainers:
    - name: copy-scripts
      image: busybox
      command:
        [
          "sh",
          "-c",
          "cp /config/redis.sh /scripts/ && chmod +x /scripts/redis.sh",
        ]
      volumeMounts:
        - name: config-volume
          mountPath: /config
        - name: scripts
          mountPath: /scripts
  containers:
    - name: redis-cli
      image: redis:alpine
      command: ["sh", "-c", "while true; do /scripts/redis.sh; sleep 1; done"]
      env:
        - name: READ_PRIMARY_HOST
          value: "172.18.0.69"
        - name: READ_REPLICA_HOST
          value: "172.18.0.68"
        - name: REDIS_PASSWORD
          value: "XXXX"
      volumeMounts:
        - name: scripts
          mountPath: /scripts
      workingDir: /scripts
  volumes:
    - name: config-volume
      configMap:
        name: redis-scripts
    - name: scripts
      emptyDir: {}
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: redis-scripts
  namespace: default
data:
  redis.sh: |
    #!/bin/sh

    ## 顏色設定
    GREEN="\033[1;32m"
    RED="\033[1;31m"
    NC="\033[0m"

    READ_PRIMARY_HOST=${READ_PRIMARY_HOST}
    READ_REPLICA_HOST=${READ_REPLICA_HOST}
    READ_REPLICA_PORT=6379
    REDIS_PASSWORD=${REDIS_PASSWORD}

    while true; do
      TIMESTAMP=$(TZ="Asia/Taipei" date +"%Y-%m-%d %H:%M:%S")
      PRIMARY_OUTPUT=$(timeout 1 redis-cli -h $READ_PRIMARY_HOST -p $READ_REPLICA_PORT -a $REDIS_PASSWORD --no-auth-warning PING) 1>/dev/null
      if [ $? -eq 0 ]; then
      echo -e "[$TIMESTAMP] PRIMARY PING ${GREEN}SUCCESS${NC}:" "$PRIMARY_OUTPUT"
      else
        echo -e "[$TIMESTAMP] PRIMARY PING ${RED}FAILED${NC}"
      fi

      REPLICA_OUTPUT=$(timeout 1 redis-cli -h $READ_REPLICA_HOST -p $READ_REPLICA_PORT -a $REDIS_PASSWORD --no-auth-warning PING) 1>/dev/null
      if [ $? -eq 0 ]; then
      echo -e "[$TIMESTAMP] REPLICA PING ${GREEN}SUCCESS${NC}:" "$REPLICA_OUTPUT"
      else
        echo -e "[$TIMESTAMP] REPLICA PING ${RED}FAILED${NC}"
      fi

      sleep 1
    done

開始手動觸發 failover

我們準備好監控以及也先看好 describe 後,就可以下指令來手動觸發 failover:

gcloud redis instances failover ian-1m1s --data-protection-mode=limited-data-loss --region=asia-east1 --project={project_id}

可以看到目前 ian-1m1s 就開始 Failing over 了~


memorystore UI 畫面

memorystore UI 畫面


後續觀察

查看監控

首先我們先看監控部分,可以看到原本的 node-1 是 Primary 後來掉下來的同時,由 node-2 變成 Primary 最後完成故障轉移。


監控畫面

監控畫面


再來看 describe 的部分,可以發現原本的 currentLocationId 從 Primary (node-0) asia-east1-a 變成(node-1) asia-east1-b,完成故障轉移,因此更換區域。


describe 畫面

describe 畫面


查看腳本

最後,查看一下腳本的執行紀錄可以發現:在 18:12:58, 出現第一筆 Primary PING 不到的錯誤,到 18:13:18 才恢復,代表故障轉移時間約 20 左右 (最後面會測試 5 次來取平均),其流程是 Primary 會先連不到,接著變成 Primary 跟 Replica 都連不到,最後剩下 Replica,到都正常。


shell 畫面

shell 畫面


實作測試 (1m2s)

由於設定都差不多,所以上述 1m1s 設定這邊就不重複說明,記得把 IaC 的 replica_count 改成 2,以及 shell 的 IP 跟 Password 要記得換!

直接看監控部分:可以看到現在 node-2 是 1,代表 node-2 是 Primary,其他 node-1、node-0 都是 Replica。


監控畫面

監控畫面


接著看 describe:currentLocationId 是 asia-east1-c,也就是 node-2 (Primary)。


describe 畫面

describe 畫面


一樣下指令來跑 shell,並觀察監控、describe 來有 shell: 變成 node-0 變成 Primary,node-2 變成 Replica,node-1 一樣是 Replica。


監控畫面

監控畫面


currentLocationId 變成是 asia-east1-a,Primary 從 node-2 變成 node-0。


describe 畫面

describe 畫面


觀察 shell 發現,有出現 FAILED 都是 Primary,Replica 都正常。


shell 畫面

shell 畫面


整理故障轉移時間

測測次數1m1s (秒)1m2s (秒)
#11613
#21910
#3226
#42010
#5189

可以發現,多一個 Replica,在故障轉移的時間可以更快速。


最佳實踐

所以我們知道,每當發生 Failover 時,一定會出現斷線的問題,官方在 Memorystore for Redis 的 General best practices 中有提到需要重新連線的操作和場景,以下都會導致與 Redis instance 網路連線中斷:

所以我們需要再設計應用程式時,考量到這一點,可以參考 Exponential backoff ,要加上重試邏輯,讓應用程式自動重新連線並持續正常運作。


參考資料

Memorystore for Redis FAQ:https://cloud.google.com/memorystore/docs/redis/faq

High availability for Memorystore for Redis:https://cloud.google.com/memorystore/docs/redis/high-availability-for-memorystore-for-redis#when_a_failover_is_triggered

About manual failover:https://cloud.google.com/memorystore/docs/redis/about-manual-failover#stackdriver_verification

Initiate a manual failover:https://cloud.google.com/memorystore/docs/redis/initiate-manual-failover

General best practices:https://cloud.google.com/memorystore/docs/redis/general-best-practices

Exponential backoff:https://cloud.google.com/memorystore/docs/redis/exponential-backoff