Skip to content

會員系統架構怎麼設計?資料表與驗證的取捨

Posted in :

jc-seo

會問到架構的人,通常已經過了「要不要做會員」的階段,手上可能是一份要交給工程師的規格,或是一套改起來越來越吃力的舊系統。這個題目的難處在於,會員資料同時被行銷、客服、財會、前台程式讀寫,任何一個欄位的定義改動都會牽動別處;而且它保存的是個人資料,設計不當的代價不只是難維護。這篇從分層開始談,一路走到資料表切法、驗證與授權、敏感欄位處理、跨服務整合,以及量長大之後最先出問題的地方。

先把層次分開,改動才不會擴散

一套會員系統至少要分成三個層次。最外層是介面層,處理請求進出、格式轉換與基本檢核;中間是規則層,負責等級怎麼算、點數怎麼扣、什麼情況拒絕;最內層是儲存層,只管把資料正確寫下與讀出。

分層的實益在於改動的範圍可控。等級規則調整時只動規則層;換一種登入方式時只動介面層與驗證模組。最常見的失敗是把規則寫在資料庫的預存程序或前端程式裡,結果同一條規則散在三個地方,改了一處另外兩處還是舊的。

拆表的原則:身分、資料、行為分開放

把所有欄位塞進一張大表,是初期最省事、後期最麻煩的做法。比較能撐的切法是拆成三類:

  • 身分:只放識別與登入相關的欄位,例如內部識別碼、帳號、密碼雜湊值、狀態、建立時間。這張表變動少、被讀取的頻率最高。
  • 個人資料:姓名、生日、地址、聯絡方式等。這類欄位會因為需求增加而變動,也是個資保護的重點,單獨放比較好控管存取。
  • 行為紀錄:消費、點數異動、登入紀錄、通知發送。這類資料只增不改,用流水帳的方式累積,餘額由累計得出或另存彙總欄位並定期核對。

點數餘額特別值得注意。只存一個餘額數字,出錯時沒有人能說明為什麼是這個數;保留每一筆異動並記下原因與來源單號,日後對帳與客訴處理才有依據。

驗證:憑證的形式與存活時間

登入之後要用什麼證明身分,決定了系統能怎麼擴充。伺服器端保存登入狀態的做法單純、要讓某個人立刻登出也容易,但多台伺服器時需要共用儲存。改用簽章憑證的做法可以讓各服務自行驗證、不必回頭查詢,代價是憑證發出後在到期前難以撤銷。

折衷的常見做法是發一張短效的存取憑證,搭配一張長效的更新憑證,短效的過期就用長效的換新,而長效的紀錄留在伺服器端,需要時可以作廢。無論選哪一種,都要先想清楚三件事:憑證存在哪裡、多久到期、使用者改密碼或被停權時如何讓現有憑證失效。

權限要綁在資源上,不是綁在職稱上

會員系統的權限有兩套,不要混在一起。一套是會員自己的等級或身分,決定他能享有什麼;另一套是後台人員的角色,決定誰能看到與修改什麼。

後台這一套建議用「角色對應動作,動作對應資源」的方式描述,例如客服角色可以查詢會員與註記,但不能調整點數;主管角色可以調整點數,但每次都要留下原因。用職稱直接寫死判斷式,之後新增一個職務就要改程式碼。此外,凡是能改動權益的動作都要寫稽核紀錄,記下操作者、時間、前後值,這件事沒有在初期做,之後幾乎補不回來。

密碼與敏感欄位的處理原則

密碼不應該可以被還原。正確做法是使用專為密碼設計的雜湊演算法,每個帳號各自加上隨機鹽值,並依運算成本參數調整強度。任何「忘記密碼時把原密碼寄給你」的設計,都代表儲存方式錯了。

其他敏感欄位如身分證字號、金融相關資訊,原則是能不存就不存,必須存則加密保存並限制可解密的服務。另外三件常被忽略的事:記錄檔不要輸出完整的個資與憑證內容;測試環境不要直接複製正式資料,要先去識別化;顯示時做遮蔽,只在必要的操作中還原完整值。

跨服務整合要假設呼叫會失敗

會員系統很少獨立運作,它要接收訂單完成的訊息、送出通知、把資料同步到分析用的資料庫。整合方式大致是即時呼叫與事件通知兩種。即時呼叫寫起來直觀,但對方壞掉時自己也跟著壞;改成把事件寫入佇列由消費端處理,可以容忍短暫中斷,代價是資料有先後落差。

不論哪一種,都要處理重複送達。同一筆訂單的加點訊息可能被送兩次,因此加點的操作要能依單號判斷是否已處理過,重複時直接忽略而不是再加一次。另外要設定重試策略與失敗後的處理方式,把送不出去的事件留在一個可以人工查看與重送的地方。

量長大之後最先卡住的地方

會員系統的效能問題通常不在寫入,而在查詢。行銷要撈出符合多個條件的名單、客服要用姓名的一部分搜尋、報表要跨月份彙總,這些查詢會掃過大量資料。做法上先確認索引有沒有對上實際查詢的條件組合,再考慮把報表與名單查詢移到另一份供讀取的資料庫,避免影響前台登入。

快取則要小心。會員等級、權益設定這類不常變動的資料適合快取,但一定要定義清楚什麼事件會讓它失效,否則會出現客人已經升等、畫面卻還是舊等級的狀態。

常見問題

會員資料要跟訂單放在同一個資料庫嗎?

規模不大時放在一起最單純,交易一致性容易保證,也不必處理跨庫查詢。當團隊分工變細、或會員服務要被多個系統共用時,才考慮拆開,並改用識別碼關聯與介接查詢。提早拆開會付出額外的一致性成本,太晚拆則要面對盤根錯節的關聯,判斷點在於是否真的有多個系統需要獨立部署。

為什麼密碼要用雜湊而不是加密?

加密是可逆的,只要金鑰外流,全部密碼等於一起外流。雜湊是單向的,系統只需要在登入時把輸入值再算一次比對結果,本身不需要知道原始密碼。再加上每個帳號獨立的鹽值,可以避免相同密碼產生相同雜湊值,讓預先算好的對照表失去作用。

用手機號碼當唯一識別有什麼風險?

號碼會被釋出後重新配給他人,也可能因為換號而由使用者主動更換,這代表它不是穩定的識別。建議內部一律使用系統自行產生的識別碼作為主鍵,手機號碼只當作可驗證的登入方式之一,並保留變更紀錄。變更時要重新驗證,避免有人透過改號接管帳號。

一開始就要做讀寫分離嗎?

通常不需要,但要先讓程式碼具備切換的條件,例如把讀取與寫入的資料存取路徑分開撰寫。等到實際觀察到讀取造成壓力時再加入供讀取的副本,成本較低。反過來,若初期就把查詢邏輯與寫入邏輯混在同一段程式裡,日後要分離會需要大範圍改寫。

舊系統沒有稽核紀錄,可以事後補嗎?

過去的操作補不回來,但可以從現在開始累積。做法是在所有會改動權益與個資的進入點加上紀錄,先確保新增的動作都有跡可循,再逐步把舊有的直接資料庫操作收攏到同一組介面之下。同時把目前的餘額與狀態做一次盤點與封存,當成日後對帳的起點。

本文由京采數位科技整理。我們自 2005 年起提供官網設計、系統開發與 Google SEO 服務,實際案例可見成果與案例

相關主題

下一步

如果你正在評估「會員系統架構」相關的規劃,可以參考我們的系統開發需求討論,或直接與我們聯繫,我們會依你的產業與現況給出務實的建議。