今天我們要設計的線上投票系統,表面上只是點擊按鈕、累加數字這麼簡單,但深入探討後會發現,它涉及了分散式系統中最經典的幾個問題:資料一致性、併發控制、即時通訊,以及防作弊機制。透過這個系統的設計,我們將學習如何在不同規模下做出合適的架構決策。
場景定義與需求分析
業務場景描述
想像一個全國性的電視節目正在進行年度最受歡迎歌手投票,預計有數百萬觀眾參與。投票期間為期一週,每位用戶可以每天投一票給不同的歌手。主辦方希望觀眾能即時看到投票排名變化,增加節目的互動性和話題性。同時,系統必須能防止惡意刷票,確保投票結果的公正性。
這個場景代表了現代投票系統的典型需求:高併發、即時性、防作弊。無論是企業內部的決策投票、社區的意見調查,還是大型活動的觀眾投票,核心挑戰都是相似的。
系統的核心價值在於:
-
資料準確性:每一票都必須被正確記錄,不能遺失或重複
-
即時性:使用者期待看到實時更新的投票結果
-
公正性:防止各種形式的作弊行為
-
可擴展性:能夠應對從小型投票到大型活動的不同規模
核心需求分析
功能性需求:
- 建立投票活動(設定選項、時間、規則)
- 投票功能(單選、多選、排序投票)
- 即時結果顯示(數字、百分比、圖表)
- 投票歷史記錄查詢
- 投票活動管理(開始、暫停、結束)
- 結果匯出與報表生成
- 使用者身份驗證(可選)
非功能性需求:
-
效能要求:頁面載入時間 < 1秒,投票回應時間 < 500ms
-
併發量:支援每秒 10,000 次投票請求
-
可用性:99.9% SLA,關鍵投票活動期間不允許停機
-
資料一致性:強一致性要求,不允許票數錯誤
-
安全性:防止 SQL 注入、XSS 攻擊、CSRF 攻擊、DDos 攻擊
-
防作弊:限制重複投票、機器人投票
-
成本控制:根據使用量彈性擴展,避免資源浪費
核心架構決策
識別關鍵問題
技術挑戰 1:即時結果更新
投票結果需要即時反映給所有線上使用者,這涉及到伺服器如何推送資料給客戶端。傳統的輪詢方式會造成大量無效請求,WebSocket 雖然即時但維護成本較高,Server-Sent Events (SSE) 則是折衷方案。
技術挑戰 2:防止重複投票
如何識別並阻止同一使用者重複投票是系統設計的核心難題。單純依賴 IP 地址會誤傷同一網路的不同使用者,Cookie 容易被清除,而強制登入又會降低參與率。
技術挑戰 3:高併發下的計數準確性
當大量使用者同時投票時,如何確保票數統計的準確性?資料庫的鎖機制可能成為瓶頸,而快取層的引入又會帶來資料一致性的挑戰。
架構方案比較
維度 |
方案A:傳統單體架構 |
方案B:微服務架構 |
方案C:Serverless 架構 |
核心特點 |
所有功能在單一應用中 |
投票、統計、推送分離 |
事件驅動、按需擴展 |
優勢 |
開發簡單、部署方便 |
獨立擴展、故障隔離 |
零運維、成本最優 |
劣勢 |
擴展困難、單點故障 |
複雜度高、網路開銷 |
冷啟動、廠商鎖定 |
適用場景 |
小型投票、內部使用 |
中大型投票平台 |
不定期的投票活動 |
複雜度 |
低 |
高 |
中 |
成本 |
固定成本低 |
固定成本高 |
按使用付費 |
決策思考框架

系統演進路徑
第一階段:MVP(0-10,000 / 使用者)
架構重點:
- 單體應用快速開發
- 關聯式資料庫儲存投票資料
- Session 或 Cookie 防重複投票
- 簡單的定時輪詢更新結果
系統架構圖:

為什麼這樣設計:
在 MVP 階段,我們優先考慮快速上線和開發效率。選擇單體架構是因為它能讓小團隊快速迭代,不需要處理分散式系統的複雜性。使用 PostgreSQL 作為主要資料庫,因為它提供了 ACID 特性,確保投票資料的一致性。Redis 作為快取層,減少資料庫壓力並提供更快的讀取速度。
這個階段的防重複投票機制相對簡單,主要依賴 Session 或 Cookie。雖然不夠完美,但對於大多數正常使用者已經足夠。即時性方面,我們使用客戶端定時輪詢(例如每 5 秒一次),這在使用者量不大時是可接受的。
第二階段:成長期(10,000-100,000 / 使用者)
架構演進重點:
- 引入 Server-Sent Events 實現真正的即時推送
- 實施多層防重複投票機制
- 資料庫讀寫分離
- 引入訊息佇列處理投票請求
關鍵設計變更:
-
即時推送機制升級
-
原因:輪詢方式在使用者增長後造成大量無效請求
-
實施方式:採用 SSE 技術,伺服器主動推送更新
-
預期效果:減少 80% 的無效請求,提升使用者體驗
-
防作弊機制強化
-
原因:簡單的 Cookie 機制容易被繞過
-
實施方式:結合 IP 限流、設備指紋
-
預期效果:有效攔截 95% 以上的惡意投票
-
投票處理異步化
-
原因:同步處理在高峰期造成回應延遲
-
實施方式:投票請求進入訊息佇列,異步處理後更新結果
-
預期效果:提升系統吞吐量 3-5 倍
系統架構圖:

第三階段:規模化(100,000+ / 使用者)
企業級架構特點:

架構設計考量:
-
高可用性設計
- 多區域部署,任一區域故障不影響服務
- 資料跨區域同步,確保一致性
- 自動故障轉移機制,RTO < 1 分鐘
-
擴展性規劃
- 水平擴展能力,可根據流量自動擴縮容
- 資料分片策略,支援 PB 級資料儲存
- 邊緣運算降低核心系統壓力
-
營運效率
- 完整的監控體系,包含業務指標和技術指標
- 自動化部署流程,藍綠部署確保零停機
- A/B 測試框架,支援功能漸進式發布
技術選型深度分析
即時通訊技術比較
技術選項 |
優勢 |
劣勢 |
適用場景 |
長輪詢 |
實作簡單、相容性好 |
延遲較高、資源消耗大 |
小型應用、即時性要求不高 |
SSE |
單向推送、自動重連 |
只支援文本、IE 不支援 |
中型應用、結果推送場景 |
WebSocket |
雙向通訊、低延遲 |
維護複雜、需要心跳機制 |
大型應用、高即時性需求 |
HTTP/2 推送 |
多路復用、頭部壓縮 |
需要 HTTPS、瀏覽器支援 |
現代化應用、效能優先 |
資料儲存方案選擇
儲存方案 |
寫入效能 |
查詢效能 |
一致性 |
擴展性 |
成本 |
PostgreSQL |
中 |
高 |
強 |
垂直 |
低 |
MongoDB |
高 |
中 |
最終 |
水平 |
中 |
Cassandra |
極高 |
中 |
可調 |
水平 |
高 |
DynamoDB |
高 |
高 |
最終 |
自動 |
按用量 |
防重複投票機制層級

實戰經驗與教訓
常見架構陷阱
-
過度依賴資料庫鎖
-
錯誤:使用悲觀鎖確保計數準確性
-
正確:使用樂觀鎖配合重試機制
-
原因:悲觀鎖在高併發下會成為嚴重瓶頸
-
忽視快取一致性
-
錯誤:直接更新快取中的計數
-
正確:使用 Cache Aside 模式或事件驅動更新
-
原因:避免快取與資料庫資料不一致
-
即時推送連線管理不當
-
錯誤:為每個客戶端維持獨立的推送連線
-
正確:使用連線池和訊息廣播機制
-
原因:減少伺服器資源消耗,提升擴展性
業界案例分析
案例:Twitter 投票功能的架構演進 參考文章
發展歷程:
-
初期(2015-2016)
-
架構特點:投票作為推文的附加功能,使用既有的推文儲存架構
-
技術:Gizzard(分片框架)+ Manhattan(分散式資料庫)
-
規模:每日數百萬投票,峰值 QPS 約 10,000
-
成長期(2017-2019)
-
主要改進:獨立的投票服務、引入串流處理進行即時統計
-
遇到的挑戰:熱門投票造成的熱點問題、跨區域資料同步延遲
-
解決方案:實作投票結果的分層快取、使用 EventBus 進行非同步處理
-
成熟期(2020-現在)
-
當前架構特點:完全微服務化、多層快取架構、機器學習反作弊
-
技術棧:Kafka Streams 即時處理、Hadoop 離線分析、GraphQL API
-
未來發展:探索區塊鏈技術確保投票透明度
關鍵學習點:
- 熱點問題不可避免,需要從架構層面設計應對策略
- 投票防作弊需要多維度偵測,包括行為模式、設備指紋、社交圖譜分析
- 即時性和準確性的平衡點會隨業務發展不斷調整
監控與維護策略
關鍵指標體系
技術指標:
- API 回應時間 P99(目標值 < 200ms)
- 投票處理延遲(目標值 < 1s)
- WebSocket 連線成功率(目標值 > 99.5%)
- 資料庫連線池使用率(目標值 < 70%)
- 快取命中率(目標值 > 90%)
業務指標:
- 每分鐘投票數(監控異常峰值)
- 重複投票攔截率(目標值 > 95%)
- 使用者參與率(活躍使用者/總使用者)
- 投票完成率(完成投票/開始投票)
- 地理分布熱力圖(識別異常集中)
維護最佳實踐
-
自動化策略
- 自動擴容:基於 CPU 和連線數的 Auto Scaling
- 自動故障轉移:健康檢查失敗自動切換
- 自動備份:每小時增量備份,每日全量備份
-
監控告警
- 分級告警:P0 立即處理,P1 15分鐘內回應
- 智慧告警:基於歷史資料的異常檢測
- 告警聚合:避免告警風暴
-
持續優化
- A/B 測試新的防作弊演算法
- 定期壓力測試,驗證系統容量
- 資料分析找出系統瓶頸
總結
核心要點回顧
今天我們深入探討了線上投票系統的設計,從簡單的 MVP 版本演進到支援百萬使用者的企業級架構。這個過程中,我們學習到幾個關鍵點:
-
即時性與一致性的平衡:不是所有場景都需要強一致性,合理使用最終一致性可以大幅提升系統效能
-
防作弊是系統工程:需要從客戶端到資料層的多層防護,沒有銀彈
-
架構演進要循序漸進:不要過早優化,根據實際需求逐步演進
-
技術選型要考慮團隊能力:最先進的技術不一定是最合適的
設計原則提煉
-
資料準確性優先於即時性:寧可延遲幾秒顯示,也不能顯示錯誤的投票結果
-
防護機制分層部署:每一層攔截不同類型的作弊行為,提高整體防護效果
-
優雅降級保證可用性:即時推送失敗時自動降級為輪詢,確保基本功能可用
-
監控先於優化:沒有資料支撐的優化都是臆測,先建立完善的監控體系
-
設計時考慮營運:架構設計不只是技術問題,還要考慮團隊的營運能力
下期預告
明天我們將進入短網址服務系統。同時也是系統設計面試中的經典題目,看似簡單的功能背後,隱藏著許多有趣的設計挑戰:如何設計高效的編碼演算法?如何處理每秒數萬次的跳轉請求?如何防止惡意網址?如何實現自定義短網址?
短網址系統會讓我們深入探討分散式 ID 生成、快取策略優化、以及如何在儲存成本與查詢效能間取得平衡。準備好了嗎?讓我們一起揭開短網址服務的設計奧秘!
參考資源