iT邦幫忙

2026 iThome 鐵人賽

DAY 5
0
Kubernetes

探討k8s部署方式系列 第 5

從快取延伸至無狀態後端[Day5]

  • 分享至 

  • xImage
  •  

三十六、什麼是 Stateless Backend?

Stateless Backend 可以翻成:

無狀態後端。

這裡的「無狀態」不是代表 Backend 完全沒有資料,而是:

Backend 不依賴某一台 Server 自己記住使用者或請求的狀態。

換句話說,每一個 Request 都應該攜帶足夠的資訊,讓任何一台 Backend 都能獨立處理。

例如現在有三台 Backend:

Backend 1
Backend 2
Backend 3

如果架構是 Stateless,那麼:

Request 1 → Backend 1
Request 2 → Backend 3
Request 3 → Backend 2

都不應該有問題。

因為三台 Backend 理論上具有相同的程式、相同的設定,也能存取相同的 Database、Redis 或其他外部服務。


三十七、什麼叫做 Stateful Backend?

先從相反的 Stateful Backend 來理解。

假設使用者登入後,Backend 1 直接把登入狀態存在自己的 Memory:

Backend 1 Memory

user_123 = logged_in

第一次 Request:

User
 │
 ▼
Load Balancer
 │
 ▼
Backend 1

登入成功

下一次 Request:

User
 │
 ▼
Load Balancer
 │
 ▼
Backend 2

Backend 2 的 Memory 中沒有:

user_123

因此 Backend 2 可能會認為這個使用者沒有登入。

這種情況表示:

Request 必須回到 Backend 1
才能正常工作

也就是 Backend 1 保存了某些只有它自己知道的 State。

這就是 Stateful。

架構會變成:

Backend 1
└── user A session

Backend 2
└── user B session

Backend 3
└── user C session

每台 Backend 的狀態不同。


三十八、Stateless 怎麼解決?

Stateless 的做法,就是不要把重要狀態只放在單一 Backend 的 Memory。

例如 Session 可以放到 Redis:

                Redis

        session:user_123
             │
             ▼
          logged_in

三台 Backend 都可以讀:

Backend 1 ─┐
Backend 2 ─┼──→ Redis
Backend 3 ─┘

因此:

Request 1 → Backend 1
Request 2 → Backend 3
Request 3 → Backend 2

每台都可以查到:

session:user_123

Backend 就不再依賴:

「上一個 Request 是哪台 Server 處理的」

這就是 Stateless 的重要精神。


三十九、JWT 也是 Stateless Authentication 的常見做法

JWT 是一個很典型的例子。

假設登入成功後,Backend 回傳:

JWT Token

裡面可能包含:

user_id
role
expiration

Browser 之後每次呼叫 API 都帶:

Authorization: Bearer <token>

例如:

Request 1 → Backend 1

Authorization: Bearer abc...

Backend 1 可以驗證 Token。

下一次:

Request 2 → Backend 3

Authorization: Bearer abc...

Backend 3 同樣可以驗證。

只要 Backend 都有相同的簽章驗證設定,就不需要知道:

這個使用者上一個 Request
到底去了哪一台 Backend

因此:

Browser
   │
   │ JWT
   ▼
Load Balancer
   │
   ├── Backend 1 ✓
   ├── Backend 2 ✓
   └── Backend 3 ✓

任何 Backend 都能處理。


四十、Stateless 不代表完全不能有 Memory

這裡容易產生一個誤解。

Stateless 並不是說:

Backend 完全不能使用 RAM

當然可以。

例如:

def calculate_price():
    result = 100 + 20
    return result

這些程式執行中的暫時資料,本來就會放在 Memory。

問題在於:

下一個 Request 是否依賴這些 Memory 資料。

例如這種情況通常沒有問題:

Request
   │
   ▼
Backend
   │
   ├── 建立變數
   ├── 計算
   └── 回傳 Response

Request 結束後資料消失也沒關係。

但如果:

Request 1
   │
   ▼
Backend 1 Memory
存入 user_state

然後:

Request 2
必須依賴 user_state

就開始變成 Stateful。


四十一、Stateless Backend 最大的好處:Backend 可以隨時被替換

如果 Backend 是 Stateless:

Backend 1
Backend 2
Backend 3

其中 Backend 2 突然掛掉:

Backend 1 ✓
Backend 2 X
Backend 3 ✓

問題相對比較小。

因為使用者的重要資料並沒有只存在 Backend 2。

Load Balancer 只需要停止送 Request 給 Backend 2:

          Load Balancer
             /      \
            ▼        ▼
       Backend 1  Backend 3

其他 Backend 還是可以繼續工作。

這就是 Stateless 很重要的一個概念:

Backend Server 本身應該盡可能是可以被替換的。

也就是:

Server 掛掉
   │
   ▼
換一台新的
   │
   ▼
服務繼續

而不是:

Server 掛掉
   │
   ▼
使用者的重要狀態也一起消失

四十二、什麼是 Auto Scaling?

Auto Scaling 可以翻成:

自動擴縮容。

意思是系統可以根據目前的負載,自動增加或減少 Backend 數量。

例如平常流量不高:

Backend 1
Backend 2

但到了中午活動開始:

CPU > 80%
Request 大量增加

系統自動增加 Backend:

Backend 1
Backend 2
Backend 3
Backend 4
Backend 5

等流量降低後:

CPU < 30%

再減少機器:

Backend 1
Backend 2

這就是 Auto Scaling。


四十三、為什麼 Stateless 對 Auto Scaling 很重要?

假設 Backend 是 Stateful。

目前:

Backend 1
Backend 2
Backend 3

而 Backend 3 裡面保存:

User A Session
User B Shopping Cart
Temporary Data

現在 Auto Scaling 判斷流量降低,想把 Backend 3 關掉:

Backend 3
   │
   ▼
Terminate

問題來了。

Backend 3 裡面的資料可能全部消失:

User A Session → 消失
User B Cart → 消失
Temporary Data → 消失

這代表:

Auto Scaling 不能隨便移除 Backend

系統會變得很難管理。


四十四、Stateless 就沒有這個問題

如果重要狀態都放在外部:

Redis
Database
Object Storage

Backend 本身只有:

Application Code

那麼:

Backend 1
Backend 2
Backend 3

其實就很像三個完全一樣的 Worker。

例如:

Backend 1
├── FastAPI
└── App Code

Backend 2
├── FastAPI
└── App Code

Backend 3
├── FastAPI
└── App Code

真正的資料在:

Redis
Database
Storage

所以 Backend 3 被關掉:

Backend 3 X

也沒有關係。

因為資料還在:

Redis ✓
Database ✓
Storage ✓

下一個 Request 可以直接交給 Backend 1 或 Backend 2。


四十五、Auto Scaling 增加 Backend 也很簡單

假設流量突然增加:

CPU = 90%

Auto Scaling 新增:

Backend 4

只要 Backend 4:

使用相同程式
使用相同設定
可以連 Redis
可以連 Database

就可以立刻開始處理 Request。

不需要:

把 Backend 1 的 Session
搬到 Backend 4

也不需要:

同步 Backend 2 的 Memory

因為所有重要狀態本來就在外部服務。

所以:

        Load Balancer
              │
      ┌───────┼───────┐
      ▼       ▼       ▼
  Backend 1 Backend 2 Backend 3

流量增加後直接:

             Load Balancer
                   │
       ┌───────────┼───────────┐
       ▼           ▼           ▼
   Backend 1   Backend 2   Backend 3
       │
       ▼
   Backend 4
   Backend 5

新 Backend 只要註冊進 Load Balancer,就可以開始接 Request。


四十六、Stateless Backend 的完整架構

目前整體架構就可以變成:

                         Internet
                            │
                            ▼
                      Load Balancer
                            │
               ┌────────────┼────────────┐
               ▼            ▼            ▼
           Backend 1    Backend 2    Backend 3
               │            │            │
               └──────┬─────┴─────┬──────┘
                      │           │
                      ▼           ▼
                    Redis       Database

Backend 負責:

接收 Request
執行 Business Logic
回傳 Response

Redis 負責:

Session
Cache
Lock
Counter
Temporary State

Database 負責:

正式 Business Data

因此 Backend 本身不需要記住:

上一個 Request
是哪個 User

上一個 Request
由哪台 Server 處理

使用者目前登入在哪台 Server

每一個 Request 都可以獨立處理。


四十七、Sticky Session 又是什麼?

有時候 Stateful 系統暫時無法改成 Stateless,Load Balancer 可以使用:

Sticky Session

意思是:

User A
永遠盡量送到 Backend 1

User B
永遠盡量送到 Backend 2

例如:

           Load Balancer

User A ─────────→ Backend 1

User B ─────────→ Backend 2

User C ─────────→ Backend 3

這樣 Backend 1 的 Memory Session 還是可以使用。

但它也有缺點。

如果:

Backend 1 掛掉

User A 原本存在 Backend 1 的狀態仍然可能消失。

而且:

Backend 1 很忙
Backend 2 很空

Load Balancer 也可能因為 Sticky Session,不能自由重新分配流量。

所以 Sticky Session 可以解決部分問題,但不等於真正的 Stateless。


四十八、Stateless 與 Auto Scaling 的關係

把這兩個概念放在一起,就很好理解:

Stateless
     │
     ▼
Backend 沒有重要本地狀態
     │
     ▼
任何 Backend 都能處理 Request
     │
     ▼
Backend 可以隨時加入或移除
     │
     ▼
Horizontal Scaling
     │
     ▼
Auto Scaling

因此 Stateless 是 Auto Scaling 非常重要的基礎。

如果 Backend 是:

可替換
可複製
彼此等價
不保存重要 Local State

系統才能自由地:

+ Backend
+ Backend
+ Backend

或:

- Backend
- Backend

而不用擔心某一台 Server 消失會把使用者狀態一起帶走。


四十九、從部署角度重新看 Stateless

到這裡,部署觀念已經從:

「我要怎麼把 FastAPI 跑起來?」

逐漸變成:

「我要怎麼讓任何一台 FastAPI
都可以隨時被建立或銷毀?」

這是一個很重要的架構轉變。

最初的部署可能是:

Server A

Nginx
Frontend
FastAPI
Database

之後拆成:

Frontend

Load Balancer

Backend 1
Backend 2
Backend 3

Redis

Database

而 Backend 如果做到 Stateless,就可以進一步做到:

自動建立 Backend
自動移除 Backend
自動部署
自動擴縮

這也就是為什麼接下來會開始出現:

Docker
Container
Image
Container Registry
Kubernetes
Auto Scaling

因為既然 Backend 可以隨時被建立與銷毀,下一個問題自然就會變成:

「我要怎麼快速、穩定地建立一台完全相同的 Backend?」

而這正是 Docker 要解決的其中一個核心問題。


上一篇
多台後端伺服器會遇到狀況與解法[Day4]
下一篇
Docker 淺談[Day6]
系列文
探討k8s部署方式9
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言