需求背景

目前的服務跑在 Vultr Regular Performance VPS 上,隨著流量成長與運算需求提升,決定升級至 High Performance 或 Optimized Cloud Compute 機型。然而這套系統有幾個特性讓遷移不能草率進行:

  • 系統持續有使用者流量,幾乎所有 request 都會觸發資料庫寫入
  • 使用 MariaDB 作為主要資料庫
  • 不能接受長時間停機
  • 必須確保資料一致性,不允許雙寫導致資料分裂

這不是一台純靜態網站的搬家——任何瞬間都可能有資料正在寫入,所以遷移策略的核心問題是:如何在不丟資料的前提下,把停機時間壓到最短?

本案例為多個服務與資料庫在同一台主機上,若資料庫與服務是分開的,遷移策略會有些微不同。一般也建議將資料庫與服務分開部署。


為什麼不能直接切 DNS?

最直覺的做法是在新機器部署好之後直接修改 DNS A Record。但 DNS 存在 propagation 延遲——修改後全球各地的 DNS cache 不會同步更新,可能需要數分鐘到數小時才能完全生效。

在這段過渡期內,部分使用者的請求會被導向舊主機,部分則會進入新主機。如果兩邊都允許寫入,就會發生:

  • 資料分裂:同一筆業務邏輯的資料分散在兩台機器
  • Session 不一致:使用者登入狀態在新舊主機之間無法共享
  • Queue / Cache 異常:任務被重複消費或遺失
  • 上傳檔案不同步:圖片或附件只存在於其中一台

結論很明確:新舊主機不能同時對外提供正式寫入服務。需要一個機制確保切換瞬間只有一台在服務。


遷移策略:MariaDB Replication + 短暫維護模式

業界對這類有狀態服務遷移的標準做法是 先同步、後切換

  1. 新主機在背景持續從舊主機同步資料
  2. 確認同步完成後,短暫停止舊主機的寫入
  3. 等待最後一筆資料同步完畢
  4. 將 DNS 指向新主機,新主機正式接手

這個策略的關鍵在於:大量的資料同步工作都在正式切換之前完成,使用者完全無感。真正需要停機的只有最後「停止寫入 → 追平 → 切換」這幾秒鐘。

MariaDB Replication 的運作原理

MariaDB Replication 基於 binary log(binlog)機制:

  • 舊主機(Master)的所有寫入操作都會記錄到 binlog
  • 新主機(Replica)持續讀取 Master 的 binlog 並重放(replay)這些操作
  • Replica 的資料幾乎即時與 Master 保持一致

整個 replication 過程中,舊主機正常服務、使用者正常使用,完全不受影響。


完整操作步驟

Step 1:建立 Snapshot

Vultr 控制台對舊 VPS 建立 Snapshot。這一步有兩個目的:

  • 快速複製環境:新主機可以直接從 Snapshot 建立,省去重新安裝與設定的時間
  • 保留 Rollback 能力:萬一遷移過程出問題,可以隨時回復

Step 2:建立新 VPS

Vultr 控制台建立新的 VPS,注意幾個要點:

  • 選擇目標機型(High Performance / Optimized Cloud Compute)
  • 使用剛才建立的 Snapshot 作為系統映像
  • Region 盡量與舊機一致,降低 replication 延遲

Step 3:驗證新主機環境

由於是從 Snapshot 建立,大部分服務應該已經就位,但仍需逐一確認:

項目確認內容
Web ServerNginx/Apache 是否正常啟動、站台設定是否正確
MariaDB服務是否啟動、資料是否完整
Cron排程任務是否正確載入
FirewallUFW / iptables 規則是否與舊機一致
SSL憑證是否有效(Snapshot 複製過來的憑證可能需要重新簽發)
Disk Mount如有額外掛載磁碟,確認 mount point 正確

注意:此時新主機的 Web Server 應該保持關閉或僅允許內部存取,避免外部流量意外進入。

Step 4:建立 MariaDB Replication

這是整個遷移的核心步驟。

舊主機(Master)設定

編輯 MariaDB 設定檔(通常為 /etc/mysql/mariadb.conf.d/50-server.cnf),加入:

[mysqld]
server-id = 1
log_bin = mysql-bin

重啟 MariaDB 後,建立 replication 專用帳號:

CREATE USER 'repl'@'新主機IP' IDENTIFIED BY '強密碼';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'新主機IP';
FLUSH PRIVILEGES;

查看目前的 binlog 位置,後續 Replica 需要用到:

SHOW MASTER STATUS;
-- 記下 File(如 mysql-bin.000003)和 Position(如 785)

新主機(Replica)設定

編輯 MariaDB 設定檔,設定不同的 server-id

[mysqld]
server-id = 2

重啟 MariaDB 後,指定 replication 來源並啟動同步:

CHANGE MASTER TO
  MASTER_HOST = '舊主機IP',
  MASTER_USER = 'repl',
  MASTER_PASSWORD = '強密碼',
  MASTER_LOG_FILE = 'mysql-bin.000003',
  MASTER_LOG_POS = 785;

START SLAVE;

確認同步狀態:

SHOW SLAVE STATUS\G

關鍵欄位:

  • Slave_IO_Running: Yes — IO 執行緒正常連線
  • Slave_SQL_Running: Yes — SQL 執行緒正常重放
  • Seconds_Behind_Master: 0 — 已完全追平,無延遲

Tip:如果 Seconds_Behind_Master 持續大於 0,可能是網路延遲或新主機效能不足。在正式切換前,必須等到這個值穩定為 0。

Step 5:提前降低 DNS TTL

在正式切換前 至少 1~2 小時,將 DNS TTL 調低至 60~300 秒。這樣做的目的是讓各地 DNS cache 更快過期,縮短切換後的 propagation 時間。

如果原本 TTL 是 3600 秒(1 小時),你至少需要等 1 小時讓舊的 cache 過期後,新的低 TTL 才會全面生效。

Step 6:正式切換(唯一的短暫停機)

這是整個遷移中真正影響服務的階段,目標是將時間控制在 數秒到數分鐘 以內。

6-1. 舊主機進入維護模式

停止應用層的寫入——可以透過 Nginx 返回 503 維護頁面,或在應用層啟用 maintenance mode。

重點:Nginx 和 MariaDB 本身不要停止,因為 replication 仍需要繼續運作。

6-2. 等待 Replica 完全追平

在新主機上確認:

SHOW SLAVE STATUS\G
-- 確認 Seconds_Behind_Master: 0

此時新舊資料庫的資料完全一致。

6-3. 停止 Replication,新主機升格為 Master

STOP SLAVE;
RESET SLAVE ALL;

執行完畢後,新主機不再是任何人的 Replica,正式成為獨立的 Master。

Step 7:切換 DNS

將 A Record 指向新主機的 IP。由於 Step 5 已經降低了 TTL,大部分使用者會在數分鐘內被導向新主機。

Step 8:新主機正式上線

此時的流量分佈:

  • 已更新 DNS 的使用者 → 進入新主機,正常使用
  • 仍持有舊 DNS cache 的使用者 → 進入舊主機,看到維護頁面

因為舊主機已經進入維護模式、不接受寫入,所以不會發生雙寫問題。使用者最多看到一個維護頁面,等 DNS cache 過期後自動切換到新主機。

Step 9:觀察與驗證

切換後建議至少觀察 30~60 分鐘,確認以下項目正常:

  • HTTP 回應正常(狀態碼、回應時間)
  • 資料庫讀寫正常
  • API 回應正確
  • 排程任務正常執行
  • SSL 憑證有效

建議保留舊主機至少一天,作為緊急 rollback 的備案。

Step 10:收尾

確認一切穩定後:

  • 恢復 DNS TTL 至正常值(如 3600 秒)
  • 關閉或銷毀舊 VPS
  • 清理不再需要的 Snapshot(可選,保留一段時間更安全)
  • 清除新主機上 replication 相關設定(server-id 可保留,但 replication user 可移除)

為什麼這個方案停機時間極短?

因為整個流程中,最耗時的資料同步工作都是在 服務正常運行期間 完成的。Replication 從建立到追平可能需要數分鐘到數小時(取決於資料量),但這段時間使用者完全無感。

真正需要停止服務的只有三個動作:

  1. 舊主機進入維護模式(瞬間)
  2. 等待 Replica 追平最後幾筆資料(通常數秒)
  3. 切換 DNS(瞬間)

加總起來,實際停機時間通常在 10 秒到 5 分鐘之間


真正零停機為何困難?

如果連這幾秒的維護模式都不能接受,就需要更複雜的基礎設施:

方案用途
Load Balancer在多台主機之間分配流量,可逐台切換
Floating IPVultr 提供的虛擬 IP,可瞬間切換指向
Managed Database(RDS)資料庫獨立於 VPS,遷移時不需要搬資料庫
Galera ClusterMariaDB 多主同步,任一節點都可讀寫
Kubernetes容器編排,支援 rolling update

這些方案的共同特點是架構複雜度與成本都顯著提升。對於單台 VPS + DNS 的架構來說,短暫維護模式已經是風險最低、成本最低的最佳解。


小結

這套遷移方案的核心思路是「提前同步、最後切換」:

  • 利用 MariaDB Replication 在背景持續同步資料,使用者無感
  • 最後短暫停止寫入,確保資料完全一致
  • 切換 DNS,新主機正式接手
  • 舊主機保留作為 rollback 備案

適用於任何持續有寫入流量的系統——SaaS、API 服務、電商、CMS、後台管理系統等。只要資料庫是 MariaDB/MySQL,這套方法都能直接套用。