上一篇估算出來的流量其實非常小,每秒寫入大概 1~2 次、讀取大概 100 多次,這種規模不需要任何花俏的架構,先做出一個 「堪用」 的版本就好。
這也是這個系列一路會遵守的原則:
不要一開始就把系統蓋大,而是先用最簡單的方式解決問題,避免過度工程(Over-engineering)。
在加任何元件之前,第一版的目標只有一個:
讓「發文、看 Feed、追蹤」這三件事情能夠正常運作。
延續昨天定出的範疇,這一版先不處理:
先把這些全部砍掉,只留下最核心的骨架。
在只有一台 Server 就能撐住流量的前提下,第一版架構單純到不能再單純,簡直像古早時代的大學留言板:
瀏覽器 -> Server -> Database
↑↓
DNS
使用者在瀏覽器輸入網址,DNS 把網域名稱換成 IP,瀏覽器再把 Request 送到我們唯一的一台 Server,Server 讀寫 Database 之後把結果回傳。

沒有 Load Balancer 也沒有 Cache,如果你不清楚這些元件也沒關係,因為現在完全不需要,這些元件要解決的問題,我們根本還沒遇到,之後會再介紹。
資料表也是先求有再求好,這裡先把每個欄位的資料型別也一併定義出來:
follower 是發起追蹤的人,followee 是被追蹤的人。如果 Pikachu 追蹤 Charmander,就會多一筆:
follower = Pikachu
followee = Charmander
先定義三支最核心的 API。
POST /follow
{
"user_id": 123
}
POST /posts
{
"content": "Hello PokeThreads"
}
GET /feed
這裡故意先不展開 GET /feed 該回傳哪些貼文,明天會針對 Feed 單獨討論,今天只需要知道「這支 API 存在」就夠了。
發文、看 Feed 都建立在一個前提上:Server 要知道現在是誰在發 Request。
目前只有一台 Server,最直覺的做法就是把登入狀態(Session)直接放進這台 Server 的 Memory:
Server
├── Application
└── Session(存在 Memory 裡)
├── Pikachu
├── Charmander
└── Squirtle
流程是這樣的:
這種「Server 自己保存使用者狀態」的設計,稱為 Stateful Server。
它的好處就是非常簡單,缺點也很明顯:一旦以後多開一台 Server,新 Server 的 Memory 裡完全沒有這筆 Session,不過這也是之後才會遇到的問題,先知道有這問題就好。
即使是最陽春的登入機制,業界常見的做法大致分兩派:
在單台 Server、使用者不多的情況下,兩種做法差異不大。
Session-based 的優勢是「要收回權限」很直接(例如踢掉某個使用者,只要刪掉 Server 上的那筆 Session 就好)。
Token-based 則是天生比較適合之後多台 Server 的場景,因為身份驗證不依賴任何一台特定 Server 的記憶體。
這系列先選 Session-based 起步,之後多台 Server 出現時再認真討論。
前端也不用想太多,先切成兩個區塊:
POST /posts
使用者輸入文字 -> 按下發布
↓
POST /posts -> Server -> Database
使用者打開頁面
↓
GET /feed -> Server -> Database(取出 Posts)
↑ ↓
└──────── 回傳貼文 ──────┘
會員以及追蹤功能也非常簡單,不贅述了。
現在系統裡只有三個角色:瀏覽器、Server、Database,彼此的關係非常直白,Server 是唯一的窗口,所有讀寫都要經過它。
之後不管加 Cache、加 CDN,還是拆多台 Server,這個「Server 對外接 Client,對內接 Database」的基本分工都不會變,改變的只是這兩層各自要不要再增加元件。
到這裡,第一版最陽春的 PokeThreads 已經完成:
它撐不住太大的流量,也還沒有任何容錯機制,但它已經是一個能正常運作、而且我們完全理解它為什麼能動的系統。
不過剛剛在設計 GET /feed 的時候,其實刻意跳過了一個問題:
Feed 到底應該回傳哪些貼文?又該用什麼順序排?
這個問題,就留到明天處理。