前面幾天,PokeThreads 的架構已經慢慢演化成分散式系統,不過所有功能都還圍繞在「發文、讀文」上。
只有這麼簡單的功能,實在太像古早時期的社群網站,今天要加入一個現代社群平台幾乎必備的功能:Notification(通知)。
情境很簡單:Pikachu 發了一篇貼文,Charmander 看到之後按下 Like,Pikachu 應該要收到一則「Charmander liked your post」的通知。
先從最直白的做法開始:Notification 就是一筆寫進 Database 的資料,使用者打開通知頁面時,Server 再把這些資料撈出來回傳。
先定義 Notifications 這張表:
LIKE)一個 Like 觸發通知的流程大致如下:

寫進 Database 的資料看起來會是這樣:
recipient_id = Pikachu
actor_id = Charmander
type = LIKE
post_id = 123
created_at = ...
is_read = false
之後 Pikachu 打開 PokeThreads,前端呼叫 GET /notifications,後端到 Database 撈出屬於他的通知回傳。
當系統還很小、通知類型也只有 LIKE 的時候,這個設計完全夠用。
假設現在通知類型不只 LIKE,還加入了 FOLLOW、REPLY、MENTION。
一個簡單的使用者操作,背後要觸發的工作也跟著變多。原本單純的一支 API,開始要做越來越多事情,新問題也隨之而來。
假設:
10ms
20ms
10ms
如果這些步驟全部同步執行,一次 Like 就要花 40ms 才能回應,而這還沒算上實際系統裡更多的 DB Query 與網路延遲。
假設 Charmander 對 Pikachu 的貼文按讚,Create Like 成功了,但緊接著 Create Notification 失敗。
如果這時候整支 API 回傳失敗,Charmander 可能會誤以為自己的 Like 根本沒生效;但如果反過來讓 API 回傳成功、卻放任 Notification 沒有真的建立,Pikachu 就永遠收不到這則通知。
問題的根源在於:我們把兩件重要程度完全不同的工作,硬綁在同一個同步流程裡。
現在的做法是完全同步:
Charmander -> Like API -> Create Like -> Create Notification -> Response
如果之後把 Create Notification 從這條流程裡拆出去,讓它在這次 Request 結束後再慢慢完成,這就是非同步處理。
今天做出了 Notification 的第一個版本:一個 Table、一支寫入、一支查詢,在系統規模小的時候完全合理。
但隨著通知類型變多,同步流程的缺點也跟著浮現,API 越來越慢,而且一個不重要的步驟(例如建立通知)出錯,反而可能拖累使用者真正在乎的操作(例如按讚有沒有成功)。
下一篇要處理的,就是怎麼把這些「不需要使用者立刻等待結果」的工作,從主流程中拆出去。