iT邦幫忙

2025 iThome 鐵人賽

DAY 4
0

當在 Twitter 上分享一個長達 200 個字元的商品連結時,短網址服務悄悄地將它變成了簡潔的
bit.ly/abc123。這個看似簡單的轉換背後,隱藏著每秒處理數十萬請求、確保毫秒級回應、防範惡意攻擊的複雜系統設計。今天我們要探討的不只是如何產生短碼,更要理解如何設計一個能夠承載十億級請求的短網址服務。

場景定義與需求分析

業務場景描述

想像你正在經營一個行銷平台,客戶需要在社群媒體、簡訊、Email 中分享產品連結。原始連結可能包含複雜的追蹤參數,長度超過 500 個字元。你需要一個短網址服務來:

  • 讓連結在字數限制的平台(如 Twitter)中更容易分享
  • 追蹤點擊數據,提供行銷分析
  • 隱藏真實 URL 結構,保護商業邏輯
  • 提供品牌化的短連結,增強識別度

這不僅是技術問題,更是商業價值的體現。一個穩定、快速、可分析的短網址服務,直接影響著數位行銷的成效。

核心需求分析

功能性需求

  • URL 縮短:將長網址轉換為 6-8 位字元的短碼
  • URL 還原:根據短碼快速重定向到原始網址
  • 自訂短碼:允許用戶指定易記的短碼(如 brand.ly/summer2024)
  • 點擊統計:記錄訪問次數、來源、裝置等資訊
  • 過期管理:支援設定連結有效期限
  • 批次處理:支援 API 批次建立短網址
  • 黑名單管理:防止惡意網址的縮短服務

非功能性需求

  • 效能要求:URL 重定向的 P99 < 50ms
  • 併發量:100K QPS ,尖峰時段的讀取請求
  • 可用性:99.99% SLA ,年度停機時間 < 52 分鐘
  • 資料規模:10 億條記錄 ,系統需支援的 URL 總數
  • 擴展性:水平擴展 ,可透過增加節點提升容量
  • 安全性:防止短碼猜測,避免連續短碼洩露資訊

核心架構決策

識別關鍵問題

技術挑戰 1:短碼生成策略

  • 影響:決定系統的擴展性上限與效能表現
  • 核心問題:如何在確保唯一性的同時維持高效能

技術挑戰 2:高併發讀取優化

  • 影響:直接影響使用者體驗與系統成本
  • 核心問題:如何在數十億資料中實現毫秒級查詢

技術挑戰 3:資料一致性與快取策略

  • 影響:決定系統的可靠性與維護複雜度
  • 核心問題:如何平衡快取命中率與資料正確性

短碼生成方案比較

維度 雜湊演算法 計數器方案 預生成池 雪花演算法
核心特點 MD5/SHA 後取前 N 位 自增 ID 轉 Base62 預先產生短碼池 分散式 ID 生成
優勢 無狀態、實作簡單 短碼長度可控 效能最佳 可排序、含時間戳
劣勢 可能碰撞、需處理 需要全域計數器 需要額外儲存 短碼較長
適用場景 小規模系統 中等規模 高併發場景 需要時序性
複雜度
成本 最低

決策思考框架

diagram1

系統演進路徑

第一階段:MVP(0-10萬 / 使用者)

架構重點:

  • 單體應用快速迭代
  • 使用 PostgreSQL 儲存映射關係
  • Redis 做熱點資料快取
  • Nginx 處理靜態重定向

系統架構圖:

diagram2

為什麼這樣設計:

  • 計數器方案:簡單可靠,避免碰撞問題
  • Redis 快取:減少資料庫壓力,提升回應速度
  • 非同步統計:不阻塞主要重定向流程
  • 批次同步:減少資料庫寫入次數

第二階段:成長期(10萬-1000萬 / 使用者)

架構演進重點:

  • 讀寫分離,主從複製
  • 多層快取架構(本地快取 + Redis)
  • 引入訊息佇列處理統計
  • CDN 加速靜態資源

主要系統架構圖:

diagram3

分散式 ID 生成架構:

diagram4

關鍵設計變更:

  1. 分散式短碼生成

    • 原因:單點計數器成為瓶頸
    • 實施方式:號段分配策略,每個節點預先獲取一段 ID 範圍
    • 預期效果:每個節點獨立生成,無需同步,提升 10 倍生成速度
  2. 多層快取架構

    • 原因:Redis 連線成為瓶頸
    • 實施方式:LRU 本地快取(5000 項)+ Redis 分散式快取
    • 預期效果:減少 90% Redis 請求,降低網路開銷
  3. 讀寫分離架構

    • 原因:讀取請求佔比達 95% 以上
    • 實施方式:主資料庫處理寫入,2~3 個從庫分擔讀取
    • 預期效果:讀取能力線性擴展,支撐百萬級併發

第三階段:規模化(1000萬+ / 使用者)

企業級架構特點:

高層架構總覽:

diagram5

資料分片策略:

diagram6

多區域部署架構:

diagram7

即時分析資料流:

diagram8

架構設計考量:

  1. 高可用性設計

    • 多區域部署,就近訪問
    • 主從自動切換,故障轉移
    • 熔斷降級機制
  2. 擴展性規劃

    • 按短碼範圍分片(如 a-z 開頭分到不同分片)
    • 讀寫分離,獨立擴展
    • 無狀態設計,水平擴展
  3. 營運效率

    • 自動化監控告警
    • A/B 測試框架
    • 灰度發布機制

技術選型深度分析

關鍵技術組件比較

技術選項 優勢 劣勢 適用場景
資料庫
PostgreSQL ACID 保證、成熟穩定 單機效能上限 MVP 階段
MySQL + Vitess 水平擴展、相容性好 運維複雜 成長期
TiDB 分散式事務、自動分片 成本較高 規模化階段
快取
Redis 效能極高、功能豐富 記憶體成本 全階段
Memcached 簡單高效 功能單一 純快取場景
Hazelcast 分散式、自動發現 Java 生態 企業級
訊息佇列
RabbitMQ 可靠性高、易用 吞吐量限制 中小規模
Kafka 超高吞吐、持久化 複雜度高 大規模
Pulsar 多租戶、儲存分離 生態較新 雲原生

技術演進策略

  • 初期技術:PostgreSQL + Redis + Nginx
  • 成長期調整:加入 RabbitMQ、讀寫分離、CDN
  • 成熟期優化:分散式資料庫、Kafka、全球部署

實戰經驗與教訓

常見架構陷阱

  1. 短碼長度規劃不當

    • 錯誤:使用 4 位短碼,很快耗盡
    • 正確:預留 6-8 位,考慮未來成長
    • 原因:改變短碼長度需要資料遷移,成本極高
  2. 忽視快取雪崩

    • 錯誤:所有快取同時過期
    • 正確:隨機過期時間、多級快取
    • 原因:瞬間大量請求會壓垮資料庫
  3. 統計即時寫入

    • 錯誤:每次點擊都寫資料庫
    • 正確:批次寫入、非同步處理
    • 原因:寫入會成為效能瓶頸

業界案例分析

案例:Bitly 的架構演進 參考資料

發展歷程

  1. 初期(2008-2012)

    • 架構特點:Ruby on Rails 單體應用,在 Betaworks 內部孵化
    • 技術:MySQL 作為主要資料庫,Memcached 處理快取需求
    • 規模:開始時處理每天數百萬短網址請求,快速成長至每月數億次點擊
  2. 成長期(2012-2016)

    • 主要改進:轉向服務導向架構(SOA),將單體應用拆分為數十個小型服務
    • 遇到的挑戰:MySQL 寫入瓶頸、全球用戶的延遲問題、需要更好的水平擴展能力
    • 解決方案:引入 Cassandra 處理大規模資料儲存、實施多資料中心部署、開發 NSQ 分散式訊息系統
  3. 規模化時期(2016-2020)

    • 架構革新:使用 Go 語言重寫核心服務,提升效能 10 倍以上
    • 技術升級:採用 Kafka 作為事件串流平台、Kubernetes 容器編排、微服務架構
    • 規模突破:每月處理 90-110 億次點擊,覆蓋 40 億個瀏覽器,400+ 伺服器支撐全球服務

關鍵學習點

  • 學習點 1:服務隔離是分散式系統的核心 - Bitly 採用 SOA + 佇列 + 非同步訊息的組合,讓各元件能獨立運作、併發處理工作,單一服務故障不會導致整體系統崩潰
  • 學習點 2:事件驅動優於命令驅動 - 使用「X 發生了」的事件風格訊息,而非「執行 X」的命令風格,實現更好的服務隔離並自然支援多個消費者處理同一事件
  • 學習點 3:地理分佈需要及早規劃 - 全球化服務的延遲問題難以在後期解決,初期就應考慮多資料中心架構和邊緣節點部署
  • 學習點 4:選擇正確的儲存方案勝過優化查詢 - 從 MySQL 遷移到 Cassandra 解決了寫入瓶頸,證明選擇適合場景的資料庫比不斷優化 SQL 更有效
  • 學習點 5:監控系統與主系統同等重要 - 「如果沒有 Nagios 監控,那它幾乎肯定已經壞了,你只是還不知道」- 完善的監控讓 400 台伺服器的運維成為可能

技術債務與重構決策

Bitly 的 Go 語言重寫決策展示了技術債務管理的最佳實踐。他們沒有一次性重寫整個系統,而是採用漸進式重構策略,優先重寫高負載的核心服務,保持新舊系統並行運作,直到新系統證明穩定性後才完全切換。這種方式讓他們在保持服務可用性的同時,實現了 10 倍的效能提升。

監控與維護策略

關鍵指標體系

技術指標:

  • P50/P95/P99 延遲(目標:< 20ms/50ms/100ms)
  • QPS(目標:100K+)
  • 快取命中率(目標:> 95%)
  • 錯誤率(目標:< 0.01%)

業務指標:

  • 日活躍短網址數量
  • 短碼使用率
  • 惡意連結攔截率
  • API 調用量與配額使用

維護最佳實踐

  1. 自動化策略

    • 自動擴容:根據 QPS 自動調整實例數
    • 自動清理:定期清理過期連結
    • 自動備份:增量備份 + 定期全量備份
  2. 監控告警

    • 應用層:APM 工具(如 New Relic)
    • 基礎設施:Prometheus + Grafana
    • 業務層:自定義 Dashboard
  3. 持續優化

    • 定期壓測,發現瓶頸
    • A/B 測試新演算法
    • 逐步遷移到新技術推疊

總結

核心要點回顧

  • 短碼生成的權衡:在簡單性、效能、擴展性之間找平衡
  • 多層快取的重要性:這是達到毫秒級回應的關鍵
  • 統計系統的解耦:不要讓分析需求影響核心服務
  • 預留擴展空間:短碼長度、資料分片策略都要考慮未來

設計原則提煉

  1. 簡單開始,逐步演進:不要過度設計,但要預留演進路徑
  2. 讀寫分離是必然趨勢:短網址服務讀遠大於寫
  3. 快取不是萬能藥:要考慮快取失效、雪崩等問題
  4. 監控先於優化:沒有數據支撐的優化都是盲目的
  5. 安全不能事後補:從一開始就要防範短碼猜測、惡意連結

下期預告

明天我們將設計「線上聊天室系統」,這將帶我們進入即時通訊的世界。
不同於短網址的請求-回應模式,聊天室需要處理 WebSocket 長連接、訊息即時推送、線上狀態管理等全新挑戰。
我們會探討如何實現訊息的可靠傳遞、如何處理斷線重連、如何設計可擴展的即時通訊架構。準備好迎接即時性的挑戰了嗎?

參考資源

Bitly 架構演進與案例分析

開源專案與工具

系統設計教學資源

雲端架構參考

延伸學習資源


上一篇
線上投票系統 - 只是簡單計數而已吧?
下一篇
線上聊天室系統 - 即時通訊的架構藝術
系列文
30個系統設計實戰:全端工程師的架構修煉8
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言