📗 大型網站技術架構

核心原理與案例分析

五大要素 × 九種模式

🧭 總綱

🎯 什麼情境該想到我

當你「面對高並發存取、海量資料處理、高可靠運行的挑戰,需要一份被許多大型網站反覆驗證過的通用招式清單」的時候。

⚙️ 怎麼用(九式 × 五要素的檢查清單)

第一部分:九種架構模式(2.1)

1. 分層(2.1.1) —— 把系統在橫向維度上切成幾個部分,每部分負責相對單一的職責,再透過上層對下層的依賴和呼叫組成完整系統。書中把網站軟體系統分為三層(表 2.1):

職責
應用層負責具體業務和視圖展示,如網站首頁及搜尋輸入和結果展示
服務層為應用層提供服務支援,如使用者管理服務、購物車服務等
資料層提供資料儲存存取服務,如資料庫、快取、檔案、搜尋引擎等

好處是便於分工合作開發和維護;各層之間具有一定獨立性,只要維持呼叫介面不變,各層可獨立演化。挑戰是必須合理規劃層次邊界和介面,開發過程中嚴格遵循約束,禁止跨層次呼叫(應用層直接呼叫資料層)及逆向呼叫(資料層呼叫服務層,或服務層呼叫應用層)。大的分層內部還可以繼續分層:應用層可再細分視圖層(美工負責)和業務邏輯層(工程師負責),服務層可細分資料介面層和邏輯處理層。分層架構是邏輯上的,三層可以部署在同一台機器,隨業務發展再分離部署到不同伺服器。因此在網站規模還很小的時候就應該採用分層架構,將來做大才好應對。

2. 分割(2.1.2) —— 如果分層是橫向切分,分割就是在縱向方面切分:把不同的功能和服務分割開來,包裝成高內聚低耦合的模組單元。書中的例子:在應用層把購物、論壇、搜尋、廣告分割成不同的應用,由獨立團隊負責、部署在不同伺服器上;同一個應用內部若規模龐大,購物業務可再分割成機票酒店業務、3C 業務、小商品業務;即使在這個粒度上,還可以繼續分割成首頁、搜尋列表、商品詳情等模組,這些模組不管邏輯上還是實體部署上都可以是獨立的。服務層同樣可依需要分割成合適的模組。

3. 分散式(2.1.3) —— 分層和分割的一個主要目的,就是讓切分後的模組便於分散式部署,把不同模組部署在不同伺服器上,透過遠端呼叫協同工作。書中列出的常用方案:

  • 分散式應用和服務:改善效能和並發性、加快開發和發布速度、減少資料庫連線資源消耗,還可以讓不同應用複用共同的服務,便於業務功能擴展。
  • 分散式靜態資源:JS、CSS、Logo 圖片等靜態資源獨立分散式部署,並採用獨立的域名,即所謂動靜分離。可減輕應用伺服器負載壓力,用獨立域名加快瀏覽器並發載入速度,並由負責使用者體驗的團隊開發維護。
  • 分散式資料和儲存:大型網站要處理以 P 為單位的海量資料,單台電腦無法提供如此大的儲存空間。除了對傳統關聯式資料庫做分散式部署外,為網站應用而生的各種 NoSQL 產品幾乎都是分散式的。
  • 分散式計算:搜尋引擎的索引建構、資料倉儲的資料分析統計等後台批次處理,目前普遍使用 Hadoop 及其 MapReduce 分散式計算框架,其特點是移動計算而不是移動資料——把計算程式分發到資料所在的位置以加速計算。
  • 此外還有支援線上伺服器設定即時更新的分散式設定、分散式環境下實現並發與協同的分散式鎖、支援雲端儲存的分散式檔案系統

書中警告分散式帶來的四個問題:①服務呼叫必須經過網路,可能嚴重影響效能;②伺服器越多,宕機機率越大,一台宕機可能導致很多應用無法存取,降低可用性;③分散式環境中保持資料一致性非常困難,分散式交易也難以保證;④導致網站依賴錯綜複雜,開發管理維護困難。所以「分散式設計要根據具體情況量力而行,切莫為了分散式而分散式」。

4. 叢集(2.1.4) —— 對於使用者存取集中的模組(比如網站首頁),還需要把獨立部署的伺服器叢集化:多台伺服器部署相同應用構成一個叢集,透過負載平衡設備共同對外提供服務。好處是並發特性更好(要更多容量只需向叢集中加入新機器),而且某台伺服器故障時,負載平衡設備或系統的失效轉移機制會把請求轉發到叢集中其他伺服器,故障不影響使用者使用。書中明講:即使是存取量很小的分散式應用和服務,也至少要部署兩台伺服器構成一個小的叢集,目的就是提高系統的可用性。

5. 快取(2.1.5) —— 把資料存放在距離計算最近的位置以加快處理速度;快取是改善軟體效能的第一手段。四個位置:

  • CDN(內容分發網路):部署在距離終端使用者最近的網路服務商,快取網站的一些靜態資源(較少變化的資料),就近以最快速度回傳;影音網站和入口網站會把使用者存取量大的熱點內容快取在 CDN。
  • 反向代理:屬於網站前端架構的一部分,部署在網站前端,使用者請求到達資料中心時最先存取到它,這裡快取靜態資源,無需轉發給應用伺服器就能回傳。
  • 本地快取:在應用伺服器本地快取熱點資料,應用程式直接存取本機記憶體,無需存取資料庫。
  • 分散式快取:資料量龐大到單機記憶體承受不住,把資料快取在專門的分散式快取叢集中,應用程式透過網路通訊存取。

使用快取的兩個前提條件:①資料存取熱點不均衡,某些資料會被更頻繁地存取,這些資料應該放在快取中;②資料在某個時間段內有效、不會很快過期,否則快取的資料會因失效而產生髒讀,影響結果正確性。快取除了加快存取速度,還能減輕後端應用和資料儲存的負載壓力——這點對網站資料庫架構至關重要,網站資料庫幾乎都是按照有快取的前提來設計負載能力的

6. 非同步(2.1.6) —— 降低耦合的重要手段:業務之間的訊息傳遞不是同步呼叫,而是把一個業務操作分成多個階段,各階段之間透過共享資料的方式非同步執行協作。單機內部可透過多執行緒共享記憶體佇列實現;分散式系統中,多個伺服器叢集透過分散式訊息佇列實現非同步,分散式訊息佇列可看作記憶體佇列的分散式部署。非同步架構是典型的生產者消費者模式,兩者不存在直接呼叫,只要保持資料結構不變,彼此實現可隨意變化。除此之外還有三個特性:

  • 提高系統可用性:消費者伺服器故障時,資料會在訊息佇列伺服器中堆積,生產者可以繼續處理業務請求,系統整體表現無故障;消費者恢復後繼續處理。
  • 加快網站回應速度:生產者處理完業務請求後把資料寫入訊息佇列即可回傳,不需等待消費者處理,回應延遲減少。
  • 消除並發存取高峰:促銷活動、熱點事件會造成並發存取突然增大,用訊息佇列把突增的請求放進去等消費者依次處理,就不會對整體負載造成太大壓力。

提醒:使用非同步方式處理業務可能會對使用者體驗、業務流程造成影響,需要網站產品設計方面的支援

7. 冗餘(2.1.7) —— 網站需要 7×24 小時連續運行,但伺服器隨時可能故障,規模大時宕機是必然事件。要在宕機時仍能繼續服務、不丟資料,就需要一定程度的伺服器冗餘運行與資料冗餘備份,宕機時把其上的服務和資料存取轉移到其他機器。存取和負載很小的服務也必須部署至少兩台伺服器構成叢集。資料庫除了定期備份、存檔保存實現冷備份外,為保證線上業務高可用,還需要主從分離、即時同步實現熱備份。為了抵禦地震、海嘯等不可抗力導致的完全癱瘓,某些大型網站會對整個資料中心進行備份,在全球範圍內部署災備資料中心,程式和資料即時同步到多個災備資料中心。

8. 自動化(2.1.8) —— 目前大型網站的自動化架構設計主要集中在發布運維方面。發布環節出的故障最多,減少人為干預可有效減少故障:

  • 自動化程式碼管理:版本控制、分支建立合併等自動化,工程師只要提交參與開發的產品代號,系統就自動建立開發分支,後期自動合併。
  • 自動化測試:提交測試後系統自動部署到測試環境,啟動自動化測試案例,發送測試報告並向系統回饋結果。
  • 自動化安全檢測:透過靜態安全掃描及部署到安全測試環境進行攻擊測試,評估安全性。
  • 自動化部署:把工程程式碼自動部署到線上生產環境。

運行期則有:自動化監控(心跳檢測、監控效能指標與應用關鍵資料指標)、自動化報警(超出預設閾值就向相關人員發送警訊)、自動化失效轉移(把失效伺服器從叢集隔離出去)、自動化失效恢復(故障消除後重啟服務、同步資料保證一致性)、自動化降級(存取高峰超出最大處理能力時,拒絕部分請求及關閉部分不重要的服務,把負載降到安全水平)、自動化分配資源(把閒置資源分配給重要的服務,擴大其部署規模)。

9. 安全(2.1.9) —— 書中列出的手法:透過密碼和手機校驗碼進行身分認證;登入、交易等操作需要對網路通訊加密,伺服器上儲存的敏感資料(如使用者資訊)也做加密處理;為防止機器人程式濫用網路資源攻擊網站,使用驗證碼識別;對於常見的 XSS 攻擊、SQL 注入,進行編碼轉換等相應處理;對垃圾資訊、敏感資訊進行過濾;對交易轉帳等重要操作根據交易模式和交易資訊進行風險控制

第二部分:五大核心架構要素(第 3 章)

除了當前的系統功能需求外,軟體架構還需要關注性能、可用性、伸縮性、擴展性、安全性這 5 個架構要素;架構設計過程中需要平衡這 5 個要素之間的關係,也可以透過考察這些要素來衡量一個軟體架構設計的優劣。

性能(3.1) —— 使用者無法忍受回應緩慢的網站,打開緩慢會導致嚴重的使用者流失;很多時候性能問題是網站架構升級最佳化的觸發器。從瀏覽器到資料庫,影響使用者請求的所有環節都可以最佳化:

  • 瀏覽器端:瀏覽器快取、頁面壓縮、合理布局頁面、減少 Cookie 傳輸。
  • CDN:把靜態內容分發至離使用者最近的網路服務商機房,用最短存取路徑取得資料。
  • 反向代理:在網站機房部署,快取熱點檔案,加快回應、減輕應用伺服器負載。
  • 應用伺服器端:本地快取與分散式快取,用記憶體中的熱點資料處理請求。
  • 非同步操作:把請求送到訊息佇列等待後續處理,當前請求直接回傳回應。
  • 叢集:多台應用伺服器組成叢集共同對外服務,提高整體處理能力。
  • 程式碼層面:多執行緒、改善記憶體管理。
  • 資料庫端:索引、快取、SQL 最佳化等手段都已比較成熟;NoSQL 則透過最佳化資料模型、儲存結構、伸縮特性等在效能上的優勢日趨明顯。

衡量指標:回應時間、TPS、系統性能計數器。這些指標也是網站監控的重要參數,可用來分析系統瓶頸、預測網站容量、對異常指標報警。性能符合預期只是必要條件——還必須考察超出負載設計能力的高並發情況下可能出現的性能問題,並保證長時間持續運行且存取壓力不均勻時仍保持穩定的性能特性

可用性(3.2) —— 網站宕掉輕則影響聲譽,重則損失金錢與使用者。幾乎所有網站都承諾 7×24 可用,但沒有網站能做到完全的 7×24;扣除故障時間換算成可用性指標,一些知名大型網站可以做到4 個 9 以上,也就是可用性超過 99.99%。因為網站用的是普通商用伺服器,設計目標本身不保證高可用,大型網站通常有上萬台伺服器、每天必定有一些宕機,所以高可用架構設計的前提是「必然會出現伺服器宕機」,目標是宕機時服務或應用依然可用

  • 主要手段是冗餘:應用部署在多台伺服器上同時提供存取,資料儲存在多台伺服器上互相備份。
  • 應用伺服器:多台透過負載平衡設備組成叢集,任一台宕機只需把請求切換到其他伺服器;前提是應用伺服器上不能保存請求的工作階段(session)資訊,否則宕機會話丟失,轉發也無法完成業務處理。
  • 儲存伺服器:需要對資料即時備份,宕機時把資料存取轉移到可用伺服器,並進行資料恢復,以保證繼續有伺服器宕機時資料依然可用。
  • 除了運行環境,高可用還需要軟體開發過程的品質保證:預發布驗證、自動化測試、自動化發布、灰度發布,減少把故障引入線上環境的可能。

衡量標準:假設系統中任何一台或多台伺服器宕機、以及出現各種不可預期的問題時,系統整體是否依然可用。

伸縮性(3.3) —— 定義:透過不斷向叢集中加入伺服器的手段,來緩解不斷上升的使用者並發存取壓力和不斷增長的資料儲存需求。衡量標準:是否可以用多台伺服器建構叢集、是否容易向叢集中添加新伺服器、加入後是否能提供和原伺服器無差別的服務、叢集中可容納的伺服器總數是否有限制。

  • 應用伺服器叢集:只要伺服器上不保存資料,所有伺服器都是對等的,用合適的負載平衡設備就可以不斷加入伺服器。
  • 快取伺服器叢集:加入新伺服器可能導致快取路由失效,進而使叢集中大部分快取資料無法存取;雖然可從資料庫重新載入,但若應用已嚴重依賴快取,可能導致整個網站崩潰,需要改進快取路由演算法保證快取資料的可存取性。
  • 關聯式資料庫:雖支援資料複製、主從熱備等機制,但很難做到大規模叢集的可伸縮性,伸縮性方案必須在資料庫之外實現,透過路由分區等手段把部署有多個資料庫的伺服器組成叢集。
  • NoSQL:先天為海量資料而生,對伸縮性的支援通常非常好,可在較少運維參與下實現叢集規模的線性伸縮。

擴展性(3.4) —— 不同於其他架構要素主要關注非功能性需求,擴展性直接關注網站的功能需求:如何設計架構使其能快速回應需求變化。衡量標準:增加新的業務產品時,是否可以對現有產品透明無影響,不需要任何改動或很少改動既有業務功能就能上線新產品;不同產品之間是否很少耦合,一個產品改動對其他產品無影響。主要手段是事件驅動架構分散式服務(書中此處原文寫作「網站可伸縮架構的主要手段」,依上下文屬 3.4 擴展性一節):

  • 事件驅動架構:通常利用訊息佇列實現,把使用者請求和其他業務事件構造成訊息發布到訊息佇列,處理者作為消費者取得訊息處理。訊息產生與訊息處理分離,可以透明地增加新的訊息生產者任務或新的訊息消費者任務
  • 分散式服務:把業務和可複用服務分離開來,透過分散式服務框架呼叫。新增產品可透過呼叫可複用服務實現自身業務邏輯,對現有產品沒有任何影響;可複用服務升級變更時,也可以提供多版本服務對應用實現透明升級,不需要強制應用同步變更。
  • 大型網站為保持市場地位還會吸引第三方開發者呼叫網站服務、使用網站資料開發周邊產品,主要途徑是開放平台介面

安全性(3.5) —— 網站的安全架構就是保護網站不受惡意存取和攻擊,保護網站的重要資料不被竊取。衡量標準:針對現存和潛在的各種攻擊與竊密手段,是否有可靠的應對策略。(書中本節僅此兩句層級的內容,具體手法見 2.1.9 安全模式。)

🧪 我實際套用的紀錄

  • (待填)

⚠️ 注意 / 什麼時候不適用

  • 書中 2.1.3 明講:「分散式設計要根據具體情況量力而行,切莫為了分散式而分散式。」分散式會帶來網路效能損耗、宕機機率上升、資料一致性困難、依賴錯綜複雜四個代價,不要把它當成預設答案。
  • 2.1.6:非同步可能影響使用者體驗與業務流程,需要產品設計方面的支援,不是純技術決定。
  • 2.1.5:快取有兩個前提(熱點不均衡、時間段內有效),不成立時快取只會帶來髒讀。
  • 2.3 小結:「模式受其適用場景限制,對系統的要求和約束也很多,不恰當地使用模式只會畫虎不成反類犬」;好的設計不是生搬硬套某個模式,而是對問題深刻理解之上的創造與創新

🔗 相關工具

🎯 什麼情境該想到我

當你要評估或設計一個資料/後端系統,想有一套「該顧哪些面向」的總框架時。

⚙️ 怎麼用(三個評估軸)

  1. 可靠性(Reliability):即使硬體/軟體/人為出錯,仍能正確運作。→ 設計容錯,主動注入故障測試。
  2. 可擴展性(Scalability):先定義負載參數(QPS、讀寫比、資料量),再看負載成長時效能如何。用百分位(p95/p99)談延遲,別只看平均。
  3. 可維護性(Maintainability):可運維性、簡單性(控制複雜度)、可演進性。

面對任何系統,逐軸問一遍,就不會漏掉非功能面。

🧪 我實際套用的紀錄

  • 2026-07-15:(待填)

⚠️ 注意

  • 「可擴展」不是布林值;一定要問「隨『哪個負載參數』成長」。

🔗 相關工具

  • 工具-資料複製 —— 可靠性那一面的主要手段,也是引入「讀到舊資料」問題的來源
  • 工具-資料分區 —— 可擴展性那一面的主要手段,單機裝不下時的第一個答案
  • 工具-管理複雜度 —— 可維護性那一面的最高準則,設計取捨拿不定主意時回到它

⚡ 性能

🎯 什麼情境該想到我

當使用者「重複造訪網站卻還是慢」、資源每次都重新下載時。

⚙️ 怎麼用

  1. 設快取標頭:對靜態資源加長 Cache-Control/Expires,讓瀏覽器重複造訪直接用本地副本。
  2. 內容雜湊檔名(cache busting):檔名帶 hash(如 app.9f3c.js),內容一改檔名就變 → 可放心設「永久快取」,更新自動失效。(本站 Quartz 就是這樣。)
  3. 善用多層快取:瀏覽器 → CDN → 反向代理 → 應用快取,越外層命中越省。
  4. 壓縮與合適格式:圖片用適當格式/尺寸,別傳過大資源。

🧪 我實際套用的紀錄

  • 2026-07-15:(待填)

⚠️ 注意

  • 快取最難的是「失效」;用內容雜湊檔名可一併解掉「更新了卻還吃到舊檔」的問題。

🔗 相關工具

🛡 可用性

🎯 什麼情境該想到我

當你要讓網站/服務「扛住高流量、少當機、能加機器就變強」時。

⚙️ 怎麼用(兩大目標的核心手法)

高可用(少當機):

  1. 消除單點:關鍵元件都要有冗餘備援 + 自動故障切換。
  2. 服務無狀態:狀態外置(快取/DB),任一台掛了流量可轉到別台。
  3. 故障隔離:艙壁、限流、降級(見 工具-服務容錯設計),別讓局部拖垮全局。

伸縮性(能水平擴展):
4. 無狀態 + 負載均衡 → 加機器就能分攤(見 工具-透明多級分流)。
5. 資料層靠分片 + 讀寫分離(見 工具-資料分區工具-資料複製)。
6. 非同步削峰:用訊息佇列把尖峰流量緩衝、削峰填谷。

🧪 我實際套用的紀錄

  • 2026-07-15:(待填)

⚠️ 注意

  • 高可用靠「冗餘」換來,成本上升;按業務對停機的容忍度決定要做到幾個 9。

🔗 相關工具

🎯 什麼情境該想到我

當你「覺得這種小事不會出問題」的時候——高併發與海量資料下,很多平常根本不是問題的問題都會冒出來。

⚙️ 怎麼用(九個真實故障 × 教訓)

  1. 寫日誌也會引發故障 —— 現象:某應用伺服器叢集發布後不久,多台伺服器相繼報警,硬碟可用空間低於警戒值,很快有伺服器宕機;登入線上伺服器發現 log 資料夾檔案迅速增加,不斷吃掉磁碟空間。/原因:這是普通應用伺服器叢集,不需要儲存資料,因此配的是一塊 100GB 的小硬碟,裝完作業系統、Web 伺服器、Java 虛擬機、應用程式後只剩幾十 GB,正常情況夠用;但開發人員把 log 輸出的 level 全域配置為 Debug,一次簡單的 Web 請求就產生大量 log 輸出,高併發下很快耗盡磁碟。/教訓:應用程式自己的日誌輸出配置和第三方元件日誌輸出要分別配置;檢查 log 配置檔,日誌輸出級別至少為 Warn,並檢查 log 輸出的程式碼呼叫,呼叫級別要符合其真實日誌級別;有些開源第三方元件也會不恰當地輸出太多 Error 日誌,需要關掉這些第三方庫的日誌輸出——至於哪些第三方庫有問題,只有在遇到問題時才知道。

  2. 高併發存取資料庫引發的故障 —— 現象:某應用發布後,資料庫 Load 居高不下,遠超過正常水準,持續報警。/原因:檢查資料庫,發現報警是某條 SQL 引起的;這條 SQL 只是一條簡單的、有索引的資料查詢,本來不該引發報警。繼續查,發現這條 SQL 執行頻率非常高,遠遠超過正常水準;追查下去,發現它被網站首頁應用呼叫——首頁是被存取最頻繁的網頁,這條 SQL 被首頁呼叫,也就被頻繁執行了。/教訓:首頁最好是靜態的;首頁不應該存取資料庫,首頁需要的資料可以從快取伺服器或者搜尋引擎伺服器獲取。

  3. 高併發情況下鎖引發的故障 —— 現象:某應用伺服器不定時因為回應逾時而報警,但很快又逾時解除、恢復正常,如此反覆,讓維運人員非常苦惱。/原因:程式中某個單例物件(singleton object)裡多處使用了 synchronized(this),由於 this 物件只有一個,所有併發請求都要排隊獲得這唯一的一把鎖。一般情況下都是簡單操作,獲得鎖、迅速完成、釋放鎖,不會引起執行緒排隊;但某個需要遠端呼叫的操作也被加了 synchronized(this),這個操作只是偶爾被執行,但每次執行都需要較長時間才能完成,這段時間鎖被佔用,所有使用者執行緒都要等待,於是回應逾時;等這個操作執行完釋放鎖,其他執行緒迅速執行,逾時就解除了。/教訓:使用鎖操作要謹慎。

  4. 快取引發的故障 —— 現象:沒有新應用發布,但資料庫伺服器突然 Load 飆升,並很快失去回應;DBA 把資料庫存取切換到備機,Load 也很快飆升並失去回應,最終引發網站全部癱瘓。/原因:快取伺服器在網站伺服器叢集中地位一直比較低,伺服器配置和管理級別都比其他伺服器低一些。大家都認為快取是改善效能的手段,丟失一些快取也沒什麼問題,有時候關閉一兩台快取伺服器也確實對應用沒有明顯影響,所以長期疏於管理快取伺服器。結果這次一個缺乏經驗的工程師關閉了快取伺服器叢集中全部十幾台 Memcached 伺服器,導致網站全部癱瘓的重大事故。/教訓:當快取已經不僅僅是改善效能、而是成為網站架構不可或缺的一部分時,對快取的管理就需要提高到和其他伺服器一樣的級別。

  5. 應用啟動不同步引發的故障 —— 現象:某應用發布後,伺服器立即崩潰。/原因:應用程式 Web 環境使用 Apache + JBoss 的模式,使用者請求透過 Apache 轉發給 JBoss。發布時 Apache 和 JBoss 同時啟動,由於 JBoss 啟動時需要載入很多應用並初始化,花費時間較長,結果 JBoss 還沒完全啟動,Apache 就已經啟動完畢開始接收使用者請求,大量請求阻塞在 JBoss 行程中,最終導致 JBoss 崩潰。網站還有很多類似場景,都需要後台服務準備好、前台應用才能啟動,否則就會導致故障——這種情況被內部人戲稱作「姑娘們還沒穿好衣服,老鴇就開門迎客了」。/教訓:老鴇開門前要檢查一下姑娘們是否穿好了衣服。就本例來說,在應用程式中加入一個特定的動態頁面(比如只回傳 OK 兩個字母),啟動腳本先啟動 JBoss,然後在腳本中不斷用 curl 命令存取這個特定頁面,直到收到 OK,才啟動 Apache。

  6. 大檔案讀寫獨佔磁碟引發的故障 —— 現象:某應用主要功能是管理使用者圖片,接到部分使用者投訴,表示上傳圖片非常慢,原來只需要一兩秒,現在需要幾十秒,有時等半天結果瀏覽器顯示伺服器逾時。/原因:圖片需要使用儲存,最可能出錯的地方是儲存伺服器。檢查儲存伺服器,發現大部分檔案只有幾百 KB,而有幾個檔案非常大、有數百 MB,讀寫這些大檔案一次需要幾十秒,這段時間磁碟基本被這個檔案操作獨佔,導致其他使用者的檔案操作緩慢。/教訓:儲存的使用需要根據不同檔案類型和用途進行管理,圖片都是小檔案,應該使用專用的儲存伺服器,不能和大檔案共用儲存;批次處理用的大檔案可以使用其他類型的分散式檔案系統。

  7. 濫用生產環境引發的故障 —— 現象:監控發現某個時段內,某些應用突然變慢,內部網路存取延遲非常厲害。/原因:檢查發現該時段內網卡流量也下降,但沒找到原因;過了一陣子才知道,原來有工程師在線上生產環境進行效能壓力測試,佔用了大部分交換機頻寬。另一類同樣的濫用:網站資料庫有專門的 DBA 維護,如果發現資料庫存在錯誤記錄、需要進行資料訂正,必須走資料訂正流程、申請 DBA 協助;於是就有工程師為了避免麻煩,直接寫一段資料庫更新操作的程式碼,悄悄放到生產環境應用伺服器上執行,神不知鬼不覺地訂正了資料——但如果不小心寫錯了 SQL,後果可想而知。/教訓:存取線上生產環境要規範,不小心就會導致大事故。

  8. 不規範的流程引發的故障 —— 現象:某應用發布後,資料庫 Load 迅速飆升、超過報警值,回滾發布後報警解除。/原因:發現該應用發布後出現大量資料庫讀取操作,而這些資料本來應該從分散式快取讀取;檢查快取,發現資料已經被快取了;檢查程式碼,發現存取快取的那行程式碼被註解掉了。原來工程師開發的時候為了測試方便,特意註解掉讀取快取的程式碼,結果開發完成後忘記把註解去掉,直接提交到程式碼庫並被發布到線上環境。/教訓:程式碼提交前使用 diff 命令進行程式碼比較,確認沒有提交不該提交的程式碼;加強 code review,程式碼在正式提交前必須被至少一個其他工程師做過 code review,並且共同承擔因程式碼引起的故障責任。

  9. 不好的程式設計習慣引發的故障 —— 現象:某應用更新某功能後,有少量使用者投訴無法正常存取該功能,一點擊就顯示出錯訊息。/原因:分析這些使用者,都是第一次使用該功能;檢查程式碼,發現程式根據歷史使用記錄建構一個物件,如果該物件為 null,就會導致 NullPointException。/教訓:程式在處理一個輸入的物件時,如果不能明確該物件是否為空,必須做空指標判斷;程式在呼叫其他方法時,輸入的物件盡量保證不是 null,必要時建構空物件(使用空物件模式)。

🧪 我實際套用的紀錄

  • (待填)

⚠️ 注意 / 什麼時候不適用

  • 這是一份經驗清單,不是檢查表的全部。書中列的是「網站的典型故障」,價值在於提醒你:在高併發和海量資料的情況下,很多一般情況下不是問題的問題都會湧現出來。照抄九條並不能免疫,重點是養成「這件小事在高併發下會變成什麼樣」的直覺。
  • 別把它讀成「要加更多防護機制」。書中 13.10 小結引一位軟體技術前輩:「軟體設計有兩種風格,一種是將軟體設計得很複雜,以使其缺陷沒那麼明顯;一種是將軟體設計得很簡單,以使其沒有明顯的缺陷。」在網站的快速發展衝擊下,即使是不明顯的缺陷也會很快凸顯出來——所以答案通常是設計得更簡單,問題能很快被發現,解決也相對容易。
  • 這種知識只能靠經歷換。書中開篇說:大型網站的架構師最有價值的地方,不在於他們掌握了多少技術,而在於他們經歷過多少故障;培養一個網站架構師的成本,不單要看付了他多少薪水、給了他多少股票,還要看為他引起的故障買了多少次單。

🔗 相關工具

🎯 什麼情境該想到我

當你想讓資料庫高可用、或用多副本分攤讀取,卻遇到「讀到舊資料」的怪象時。

⚙️ 怎麼用(先選架構,再處理延遲)

  1. 選複製架構
    • 單主(Leader-based):寫主、讀從,最常見;簡單但主是寫入瓶頸/單點。
    • 多主:跨資料中心可寫,但要處理寫衝突。
    • 無主(Dynamo 式):靠 quorum 讀寫。
  2. 同步 vs 非同步:同步保證從庫有最新值但慢/易卡;非同步快但有延遲。
  3. 處理複製延遲的讀取異常
    • 讀自己的寫 → 讀己所寫一致性(read-your-writes)
    • 時光倒流 → 單調讀(monotonic reads)

🧪 我實際套用的紀錄

  • 2026-07-15:(待填)

⚠️ 注意

  • 非同步複製下「主故障切換」可能丟資料;切換策略要想清楚。
  • worker 查從庫可能查不到剛寫的資料 → 見 工具-MQ消費端防禦三原則

🔗 相關工具

📈 伸縮性

🎯 什麼情境該想到我

當你在設計「使用者請求如何一路被導到正確、健康的服務節點」,或思考 CDN/負載均衡/網關該怎麼擺時。

⚙️ 怎麼用(一層層把流量導到對的地方,越前面擋掉越多越好)

  1. DNS:把網域解析到最近/可用的入口。
  2. CDN:靜態內容就近快取,別讓請求都打到源站。
  3. 負載均衡:把流量分散到多個健康節點(四層/七層)。
  4. API 網關:統一入口,做認證、限流、路由、聚合。
  5. 服務發現:讓呼叫端動態找到可用的服務實例(配合健康檢查)。

原則:能在越外層解決/擋掉的流量,就別讓它進到越內層,層層減壓。

🧪 我實際套用的紀錄

  • 2026-07-15:(待填)

⚠️ 注意

  • 每多一層都是複雜度與延遲;按實際規模採用,別一開始就全套。

🔗 相關工具

🎯 什麼情境該想到我

當單一機器裝不下資料/扛不住流量,需要把資料切分到多台機器(水平擴展)時。

⚙️ 怎麼用

  1. 選分區鍵與策略
    • 按範圍分區:範圍查詢方便,但易產生熱點(如全部照時間寫入同一分區)。
    • 按雜湊分區:分佈均勻、避熱點,但失去範圍查詢能力。
  2. 處理熱點:熱鍵可加隨機前綴打散。
  3. 次級索引:本地索引(分區內,查詢要 scatter/gather)vs 全域索引(寫入要跨分區)。
  4. 再平衡(rebalancing):用固定數量分區等策略,避免資料大搬風。

🧪 我實際套用的紀錄

  • 2026-07-15:(待填)

⚠️ 注意

  • 分區鍵選錯(造成熱點或常需跨分區查詢)事後極難改,設計時最關鍵。

🔗 相關工具

🎯 什麼情境該想到我

當你「要辦一場開賣瞬間就湧入數百倍平時流量的限量搶購活動,又不想為了這幾秒鐘去養一整年用不到的伺服器、更不想把正常業務一起拖垮」的時候。

⚙️ 怎麼用(步驟 / 公式)

第一步:先把四個技術挑戰列出來(以「一件商品、預計 1 萬人參加、最大並發請求數 10,000」為基準)

  1. 對現有網站業務造成衝擊——秒殺是營銷附加活動,時間短、並發訪問量大,如果和原有應用部署在一起,稍有不慎可能導致整個網站癱瘓。
  2. 高並發下的應用、資料庫負載——使用者在秒殺開始前會不停刷新瀏覽器頁面以確保不錯過,這些請求若走一般架構去訪問應用伺服器、連資料庫,會對應用伺服器和資料庫伺服器造成極大負載壓力。
  3. 突然增加的網路及伺服器頻寬——假設商品頁面大小 200K(主要是商品圖片),需要的網路和伺服器頻寬就是 200K × 10,000 = 2G,這是活動新增的、超過平時使用的頻寬。
  4. 直接下單——遊戲規則是到了秒殺時間才能下單,但下單頁面也只是一個普通的 URL,拿到這個 URL 就可以不等活動開始直接下單。

第二步:套四項應對策略(一項對一個挑戰)

  1. 秒殺系統獨立部署——不與正常網站交易業務共用伺服器。如果需要,還可以使用獨立的域名,使其與網站完全隔離;即使秒殺系統崩潰了,也不會對網站造成任何影響。
  2. 秒殺商品頁面靜態化——重新設計頁面,不用原本的商品詳情頁,把商品描述、商品參數、成交記錄、使用者評價全部寫入一個靜態頁面。使用者請求不需經過應用伺服器的業務邏輯處理,也不需訪問資料庫,所以秒殺商品服務不需要部署動態的 Web 伺服器和資料庫伺服器
  3. 租借秒殺活動網路頻寬——新增的頻寬必須和運營商重新購買或租借;並把秒殺商品頁面快取在 CDN,同樣要和 CDN 服務商臨時租借新增的出口頻寬。
  4. 動態生成隨機下單頁面 URL——在下單頁面 URL 加入由伺服器端生成的隨機數作為參數,秒殺開始的時候才能得到,讓即使是秒殺系統的開發者也無法在開始前訪問下單頁面 URL。

第三步:頁面與表單一律砍到最簡

  1. 商品頁面盡可能簡單(只有商品圖片、商品資訊、購買按鈕、商品描述)——參與者關心的是「怎麼快速刷新頁面、開始時搶先進入下單頁」,而不是商品詳情等體驗細節。購買按鈕只有在活動開始時才變亮,在此之前及商品賣出後都是灰色不可點擊。
  2. 下單表單盡可能簡單:購買數量只能是一個且不可修改;送貨地址與付款方式都用使用者預設設定,沒有預設也可以不填,允許等訂單提交後再修改;只有第一個提交的訂單發送給網站的訂單子系統,其餘使用者提交後只能看到秒殺結束頁面。

第四步:解掉兩個額外問題

  1. 問題一:怎麼控制購買按鈕的點亮?
    頁面已被設計成靜態頁、快取在 CDN/反向代理伺服器甚至使用者瀏覽器上,秒殺開始時使用者刷新頁面,請求根本不會到達應用伺服器,所以不能靠伺服器端構造回應頁面來控制。
    解法是用 JavaScript 腳本控制:在秒殺商品靜態頁面中加入一個 JavaScript 檔案引用,該檔案中放入「秒殺是否開始的標誌」與「下單頁面 URL 的隨機數參數」;秒殺開始的時候生成一個新的 JavaScript 檔案推送到 JavaScript 伺服器並被使用者瀏覽器載入,控制商品頁面的展示。
    關鍵條件:這個 JavaScript 檔案使用隨機版本號,並且不被瀏覽器、CDN 和反向代理伺服器快取;因為檔案非常小,即使每次刷新都去訪問它,也不會對伺服器集群和網路頻寬造成太大壓力。
  2. 問題二:怎麼只讓第一個提交的訂單進到訂單子系統?
    為了減輕下單頁面伺服器的負載壓力,控制進入下單頁面的入口,只有少數使用者能進入下單頁面,其他人直接進入秒殺結束頁面
    具體門檻:假設下單伺服器集群有 10 台伺服器,每台伺服器只接受最多 10 個下單請求。下單流程為——活動開始 → 點擊購買按鈕 → 請求發送至下單伺服器 → 下單伺服器檢查本機處理下單請求數目(已超過 10 → 顯示秒殺活動已結束頁面;未超過 10 → 放行)→ 使用者填寫訂單、點擊提交 → 檢查全域已提交訂單數目(已超過秒殺商品總數 → 顯示秒殺活動已結束頁面;未超過 → 提交到訂單子系統)。

第五步:照這份清單佈署(本書給出的整體架構)

  1. 網站機房秒殺伺服器集群:
    • 秒殺商品伺服器集群:10 台 Apache 伺服器
    • JavaScript 伺服器集群:5 台 Lighttpd 伺服器
    • 定時任務伺服器:1 台 Linux 伺服器(秒殺開始前生成新的 JavaScript 檔案並推送到 JavaScript 伺服器)
    • 全域計數器伺服器:1 台 Memcached 伺服器
    • 下單伺服器集群:10 台 Jetty 伺服器
  2. 外圍:使用者瀏覽器 → CDN 伺服器(承接刷新秒殺商品頁面,每次刷新都會載入一次 JavaScript 檔案);下單伺服器把通過檢查的訂單提交到網站機房業務伺服器集群的訂單處理子系統

🧪 我實際套用的紀錄

  • (待填)

⚠️ 注意 / 什麼時候不適用

  • 不要追求完美的公平。秒殺是對網站架構的極大考驗,在難以預計和控制的高並發訪問衝擊下稍有不慎,系統就會「被使用者秒殺」導致整個系統宕機、活動失敗、構成重大事故。因此在遵循秒殺活動遊戲規則的基礎上,為了保證系統的安全,保持適度的公平公正即可——上面「每台伺服器只收 10 個請求」這種做法本來就會篩掉絕大多數使用者,這是刻意的取捨。
  • 故障也不准顯示錯誤頁。書中明講:即使系統出了故障,也不應該給使用者顯示出錯頁面,而是顯示秒殺活動結束頁面,避免不必要的困擾。
  • 這套架構是為秒殺而設計的專用系統,不同於一般網購行為,不能拿正常的網站業務流程來套,也不能和正常的網站交易業務共用伺服器。
  • 除了本卡列的架構設計,書中第 10 章提到的許多效能最佳化設計都可以用於秒殺系統的最佳化。

🔗 相關工具

  • 工具-容量估算 —— 本卡的起點就是一次容量估算:1 萬人 → 10,000 並發 → 200K × 10,000 = 2G 頻寬,數字算出來才知道要租多少頻寬、佈幾台機器
  • 工具-快取與資源優化 —— 頁面靜態化 + CDN 快取是秒殺的主力手段,而「JavaScript 檔案帶隨機版本號且不被快取」正是快取失效控制的典型應用
  • 工具-透明多級分流 —— 秒殺把絕大多數請求擋在瀏覽器、CDN、反向代理這幾層,根本不讓它們到達應用伺服器與資料庫
  • 工具-限流器設計 —— 「每台下單伺服器只接受最多 10 個請求」+「全域計數器檢查商品總數」就是一組本機加全域的兩層限流
  • 工具-網站高可用與伸縮性設計 —— 秒殺系統獨立部署、獨立域名、與網站完全隔離,讓秒殺系統即使崩潰也不影響網站
  • 大型網站技術架構 —— 來源書

🧩 擴展性

🎯 什麼情境該想到我

當你在猶豫「現在就該上分散式/微服務/複雜中間件嗎,還是先簡單做」時。

⚙️ 怎麼用

  1. 在痛點真的出現時才演進:DB 撐不住才分庫分表、單體真的擋路才拆服務。別為「想像中的未來規模」預先過度設計。
  2. 每次升級對準一個真實瓶頸:先量測、確認瓶頸,再針對它升級(呼應 工具-找出並管理約束點)。
  3. 保留演進空間,但不預先實作:介面/邊界留好(工具-限界上下文),讓未來好改,但現在保持簡單。
  4. 把共通難題沉澱成平台/中間件:等同類需求重複出現,再抽象共用,而非一開始就造框架。

🧪 我實際套用的紀錄

  • 2026-07-15:(待填)

⚠️ 注意

  • 兩個極端都要避免:過早複雜化(YAGNI)與拖到系統崩潰才動。用「真實痛點 + 數據」判斷時機。

🔗 相關工具

🔒 安全性

🎯 什麼情境該想到我

當你「開放使用者輸入或上傳任何東西給網站」的時候。

⚙️ 怎麼用(三大攻擊 × 防禦手段)

書中開宗明義:全球大約 70% 的 Web 應用攻擊都來自 XSS 攻擊和 SQL 注入攻擊,此外常用的手段還包括 CSRF、Session 劫持等。

1. XSS 攻擊(跨站點腳本 Cross Site Script)

黑客竄改網頁、注入惡意 HTML 腳本,在使用者瀏覽網頁時控制其瀏覽器做惡意操作。可用來偷 Cookie、密碼,進而偽造交易、盜竊財產、竊取情報。

兩種型態:

  • 反射型:誘使使用者點一個嵌了惡意腳本的連結。新浪微博那次就是反射型——微博裡有一個含惡意腳本 URL,點了會自動關注攻擊者的 ID 並再發一篇含同樣 URL 的微博,攻擊就擴散了。
  • 持久型:黑客提交含惡意腳本的請求,存進被攻擊站點的資料庫,其他使用者瀏覽時腳本被包在正常頁面裡執行。常見於論壇、部落格這類應用。

兩種防禦:

  • 消毒:對某些 HTML 危險字元轉義(> 轉為 &gt< 轉為 &lt)。關鍵細節:要文字比對後再轉義,避免把「3<5」裡的 < 誤轉;只有像 <img src= 這種上下文中的 < 才轉。消毒幾乎是所有網站最必備的 XSS 防護手段。
  • HttpOnly:最早由微軟提出,瀏覽器禁止頁面 JavaScript 存取帶 HttpOnly 屬性的 Cookie。注意它不是直接對抗 XSS,而是防止 XSS 攻擊者竊取 Cookie;存放使用者認證等敏感資訊的 Cookie 應加上此屬性。

2. 注入攻擊(SQL 注入 / OS 注入)

攻擊者在 HTTP 請求中注入惡意 SQL(例如 drop table users;),伺服器用請求參數拼出 SQL 命令時,惡意 SQL 被一起拼進去並在資料庫執行。

攻擊者取得資料庫表結構的三種途徑:

  1. 開源——網站用開源軟體搭建(如用 Discuz! 搭論壇),資料庫結構本來就公開。
  2. 錯誤回顯——網站開著錯誤回顯,伺服器內部 500 錯誤直接顯示到瀏覽器;攻擊者故意構造非法參數,讓例外訊息輸出到瀏覽器端,方便猜表結構。
  3. 盲注——網站關掉錯誤回顯,攻擊者靠頁面變化判斷 SQL 執行情況據以猜測,難度較大。

防禦: 首先要避免被猜到表名等結構資訊,此外

  • 消毒:透過正則比對,過濾請求資料中可能注入的 SQL(如 drop table)。簡單粗暴但有效。
  • 參數綁定:使用預編譯手段,綁定參數是最好的防 SQL 注入方法。iBatis、Hibernate 等資料存取層框架都實作了 SQL 預編譯與參數綁定,攻擊者的惡意 SQL 會被當成 SQL 的參數而非命令執行。

除了 SQL,攻擊者也會視應用注入 OS 命令、程式語言程式碼。

3. CSRF 攻擊(跨站點請求偽造 Cross Site Request Forgery)

攻擊者透過跨站請求,在使用者不知情下以其合法身分做非法操作(轉帳交易、發表評論等)。核心是利用了瀏覽器 Cookie 或伺服器 Session 策略來盜用身分。防禦主軸是「識別請求者身分」

  • 表單 Token:在頁面表單中加一個隨機數當 Token,每次回應頁面的 Token 都不同;正常頁面提交的請求會帶上,偽造的請求拿不到這個值,伺服器檢查 Token 存在且正確才放行。
  • 驗證碼:更簡單有效,但書中明講輸入驗證碼是一個糟糕的使用者體驗,所以請在必要時使用,如支付交易等關鍵頁面
  • Referer check:HTTP 請求頭的 Referer 域記錄請求來源,檢查來源是否合法。很多網站用這個做圖片防盜鏈。

4. 其他攻擊和漏洞(8.1.4)

  • Error Code(錯誤回顯):許多 Web 伺服器預設打開例外訊息輸出,未處理的例外堆疊直接吐到瀏覽器,黑客可故意製造非法輸入來找漏洞。防禦很簡單——設定 Web 伺服器參數,把 500 頁面跳轉到專門的錯誤頁;常用的 MVC 框架也有這功能。
  • HTML 註釋:開發人員為了除錯,在 PHP、JSP 等伺服器頁面程式中用 HTML 註釋語法寫註解,這些註釋會顯示在客戶端瀏覽器。發布前要做 code review 或自動掃描。
  • 檔案上傳:若上傳的是可執行程式並藉此取得伺服器端命令執行能力,攻擊者幾乎能為所欲為,還能當跳板打叢集內其他機器。最有效的防禦是設上傳檔案白名單,只允許可靠的檔案類型;此外可修改檔名、使用專門的儲存。
  • 路徑遍歷:攻擊者在 URL 中用相對路徑,遍歷系統未開放的目錄與檔案。防禦是把 JS、CSS 等資源檔部署在獨立伺服器、用獨立網域,其他檔案不用靜態 URL 存取,動態參數不包含檔案路徑資訊。

5. Web 應用防火牆:ModSecurity(8.1.5)

理想的產品要能統一攔截請求、過濾惡意參數、自動消毒、加 Token,並根據最新攻擊與漏洞情報不斷升級對策。ModSecurity 就是這樣的東西:

  • 開源的 Web 應用防火牆,可嵌入 Web 應用伺服器,也可當獨立應用程式啟動。最早只是 Apache 的一個模組,現在有 Java、.NET 多個版本並支援 Nginx。
  • 架構重點:處理邏輯與攻擊規則集合分離。處理邏輯(執行引擎)負責請求/回應的攔截過濾、規則載入執行;攻擊規則集合負責描述具體攻擊的規則定義、模式識別、防禦策略(可用文字方式描述)。處理邏輯比較穩定,規則集合則需針對漏洞不斷升級——這是一種可擴展的架構設計。
  • 商業產品也有實作此功能者,如 NEC 的 SiteShell。

6. 網站安全漏洞掃描(8.1.6)

和電腦安全漏洞掃描一樣,網站也需要。掃描工具根據內建規則構造具有攻擊性的 URL 請求,模擬黑客攻擊行為,用以發現漏洞。許多大型網站的安全團隊都有自己開發的掃描工具,不定期掃描伺服器查漏補缺;市場上也有商用的掃描平台。

🧪 我實際套用的紀錄

  • (待填)

⚠️ 注意 / 什麼時候不適用

  • 沒有「百毒不侵、固若金湯」的網站。書中反問「有沒有百毒不侵、固若金湯的網站呢?」,而 XSS 這種「古老」手段歷久彌新、不斷變化出新花樣,許多以前認為不可能用來攻擊的漏洞也逐漸被利用——防禦是持續升級的過程,不是一次性的驗收項目
  • 這也是 ModSecurity 把規則集合獨立出來的理由:新型漏洞不斷被報告,只有規則能持續升級的架構才跟得上。
  • 驗證碼雖有效但傷體驗,別無差別地套在所有表單上。

🔗 相關工具

🎯 什麼情境該想到我

當你「要保護敏感資料,得決定用哪一類加密、以及那把金鑰到底該放哪裡」的時候。

⚙️ 怎麼用(步驟 / 公式)

  1. 先問「明文有沒有偷偷躺在某處」。2011 年 12 月被曝的 CSDN 密碼洩漏事故,網站安全措施不力導致使用者資料庫被駭客「拖庫」並不稀奇,令人錯愕的是資料庫中的使用者密碼竟然是明文保存,導致密碼洩漏、成為地下黑市交易的商品。動手加密前,先把所有明文落地點盤一遍。

  2. 選加密類型。書中把資訊加密技術分成三類:

    • 單向散列加密:對不同輸入長度的資訊做散列計算,得到固定長度的輸出,過程是單向的——不能從固定長度的輸出反算回輸入。
    • 對稱加密:加密和解密使用的是同一把金鑰(或可互相推算)。
    • 非對稱加密:加解密用的不是同一把金鑰,一把對外公開叫公鑰,另一把只有所有者知道叫私鑰;公鑰加密的只有私鑰能解,反之亦然。理論上不可能由公鑰計算得到私鑰。
  3. 密碼保存用單向散列。使用者註冊時輸入的密碼不直接存進資料庫,而是先做單向散列加密、把密文存入資料庫;登入時同樣算出輸入密碼的密文,與資料庫中的密文比較,一致才驗證成功。這樣即使資料庫被「拖庫」也不會洩漏密碼資訊。

    • 一定要加鹽(salt):雖然不能用演算法把散列密文反算成明文,但人們設定密碼有一定模式,透過彩虹表(常用密碼與對應密文的關係表)等手段可以做猜測式破解。加 salt 相當於加密的金鑰,增加破解難度。
    • 常用單向散列演算法:MD5、SHA
    • 附帶特性:輸入的任何微小變化都會導致輸出完全不同——因此也用來產生資訊摘要、計算高離散程度的隨機數。
  4. 大量資料加密用對稱加密。常用在資訊需要安全交換或儲存的場合,如 Cookie 加密、通訊加密。

    • 優點:演算法簡單、加解密效率高、系統開銷小,適合對大量資料加密。
    • 缺點:加解密同一把金鑰,遠端通訊時如何安全交換金鑰是個難題;金鑰一旦遺失,所有加密資訊也就無密可言。
    • 常用演算法:DES、RC。書中稱對稱加密是傳統也是最常用的加密手段,適用於絕大多數需要加密的場合。
  5. 安全傳輸與數位簽章用非對稱加密,注意兩者方向相反

    • 安全傳輸:發送者 A 從公開渠道取得接收者 B 的公鑰加密,經非安全通道送出;B 用自己的私鑰解密。密文被竊取者拿到也還原不出明文。
    • 數位簽章:簽名者用自己的私鑰加密後發出,接收方用簽名者的公鑰解密。由於私鑰只有簽名者擁有,該資訊不可抵賴,具有簽名性質。
    • 常用演算法:RSAHTTPS 傳輸中瀏覽器使用的數位憑證,實質上就是經權威機構認證的非對稱加密公鑰。
  6. 實務上混合使用:先用非對稱加密技術對對稱金鑰進行安全傳輸,再用對稱加密技術做資訊加解密與交換。有時對同一份資料兩次使用非對稱加密,可同時達成安全傳輸與數位簽章。

  7. 回頭管好金鑰——這才是前提。不管是散列的 salt、對稱加密的金鑰還是非對稱加密的私鑰,一旦洩漏,所有基於它加密的資訊都失去秘密性。書中直接點名的壞習慣:有的工程師把金鑰直接寫在原始碼中,稍好一點的寫在設定檔中,線上與開發環境用不同金鑰——但金鑰本身仍以明文保存,而且很多人接觸得到,至少在公司內部金鑰不是秘密。

  8. 兩種改善方案,二選一

    • (a) 金鑰與演算法都獨立部署:放在一台獨立伺服器上,甚至做成專用硬體設施,對外提供加解密服務,應用系統呼叫這個服務完成加解密。由專人維護,金鑰洩漏機率大大降低。缺點:成本較高、有可能成為應用的瓶頸、每次加解密都要一次遠端服務呼叫,系統效能開銷也較大。
    • (b) 演算法留在應用系統、金鑰放獨立伺服器:兼顧安全性與效能。實際儲存時,金鑰被切分成數片,加密後分別保存在不同儲存介質中。應用程式呼叫加解密服務介面,介面向密鑰伺服器的密鑰服務取得金鑰並在本地快取(定時更新);密鑰伺服器的金鑰則來自多台密鑰儲存伺服器,每台都有專人負責管理。密鑰申請者、密鑰管理者、安全稽核人員透過密鑰管理控制台管理更新金鑰,每個人各司其職,沒有人能查看完整的密鑰資訊

🧪 我實際套用的紀錄

  • (待填)

⚠️ 注意 / 什麼時候不適用

  • 單向散列不可逆,只能用來驗證、不能用來取回。要能還原原始資料的場合(Cookie 內容、通訊內容)得用對稱或非對稱加密。
  • 只加密不管金鑰等於沒加密。書中明說,前述幾種加密技術能達到保密效果的重要前提就是金鑰的安全。
  • 獨立加解密服務會變成瓶頸:每次加解密都是一次遠端呼叫,高併發路徑上要先評估開銷;書中方案 (b) 就是為此而生。
  • 非對稱加密不適合拿來加密大量資料:書中的定位是資訊安全傳輸與數位簽章,大量資料交給對稱加密。

🔗 相關工具

🎯 什麼情境該想到我

當你「要用機器擋掉垃圾內容或高風險交易,而人工審核已經審不動」的時候。

⚙️ 怎麼用(步驟 / 公式)

A. 文字比對(擋敏感詞)

  1. 網站維護一份敏感詞列表,若使用者發表的資訊含有列表中的敏感詞,就做消毒處理(把敏感詞轉義為 ***)或拒絕發表
  2. 選比對方法
    • 敏感詞比較少、使用者提交的文字長度也短 → 直接用正則表達式比對。
    • 但正則的效率一般較差;當敏感詞很多、發布資訊也很長、網站並發量較高時要換方法。公開演算法基本上都是 Trie 樹的變種,空間與時間複雜度都比較好的有雙陣列 Trie 演算法。
    • Trie 演算法的本質是確定一個有限狀態自動機,根據輸入資料進行狀態轉移。雙陣列 Trie 用兩個稀疏陣列儲存樹結構:base 陣列存 Trie 樹的節點,check 陣列進行狀態檢查。需要依業務場景與經驗決定陣列大小,避免陣列過大或衝突過多。
    • 更簡單的實作是多級 Hash 表過濾樹:例如敏感詞表含「阿拉伯、阿拉汗、阿油、北京、北大荒、北風」,就構造一棵過濾樹,使用者提交的資訊逐字依序在樹中比對;過濾樹分支可能較多,把同一層中相同父節點的字放進 Hash 表以提高比對速度。處理速度較快、稍加變形即可適應各種過濾場景,缺點是用 Hash 表會浪費部分記憶體空間(敏感詞數量不多時可以接受)。
  3. 加降噪預處理:為了繞過敏感詞檢查,某些輸入會做手腳,例如「阿拉_伯」,這時要先對資訊做降噪預處理再比對。

B. 分類演算法(識別垃圾資訊)

  1. 早期主要靠人工審核,但大型網站(如 Facebook、LinkedIn 這類 Web2.0 社交網站)每天使用者提交的資訊數千萬計;B2B 撮合網站的站內信也常被廣告淹沒正常詢盤——海量資訊人工審核不現實。
  2. 訓練流程:先把批量已分類的樣本(書中舉例為 50000 封正常郵件、2000 封垃圾郵件)輸入分類演算法訓練,得到垃圾郵件分類模型;再用分類演算法結合分類模型辨識待處理郵件。
  3. 從貝氏開始:貝氏分類演算法是用機率統計方法進行分類。根據已分類樣本取得一組特徵值的機率——例如「茶葉」這個詞出現在垃圾郵件中的機率為 20%、出現在非垃圾郵件中的機率為 1%,即得到分類模型;對待處理郵件擷取特徵值後結合模型即可判斷分類。
  4. 演算法升級路線:貝氏假設特徵值之間互相獨立,所以又叫樸素貝氏(書中寫作 Native Bayes);但這個假設很多時候不成立,特徵值之間具有關聯性——對樸素貝氏增加特徵值的關聯依賴處理,得到 TAN 演算法;更進一步,對關聯規則做聚類挖掘,得到更強大的 ARCS(Association Rule Clustering System)演算法。
  5. 但先別急著升級:書中明說,由於貝氏分類演算法簡單、處理速度快,仍是許多即時線上系統反垃圾的首選
  6. 同一套也能拿來分類資訊:入口網站可用它把採集來的新聞稿件自動分類、分發到不同頻道;郵箱服務商也用它依郵件內容推送個人化廣告以提高投遞相關度。

C. 黑名單(擋已知的壞來源)

  1. 把被舉報的垃圾郵箱地址放進黑名單,再針對郵件的發件人在黑名單中查找,找到就過濾。黑名單也可用於資訊去重,例如把文章標題或關鍵段落記入黑名單,減少搜尋引擎收錄重複資訊。
  2. 先用 Hash 表:實作簡單、時間複雜度小,滿足一般場景。
  3. 算一下記憶體再決定——書中算例:處理 10 億個黑名單郵件地址、每個地址需要 8 個位元組的資訊指紋,即需要 8GB 記憶體;為減少 Hash 衝突還需要空間冗餘,假如空間利用率為 50%,則需要 16GB 記憶體。列表越大一般伺服器越無法承受,而且衝突越多、檢索速度越慢。
  4. 過濾需求不要求完全精確時,改用布隆過濾器(Bloom Filter,以發明者巴頓・布隆命名):由一個二進位列表與一組隨機數映射函數實現。仍以 10 億郵件地址黑名單為例,在記憶體中建立一個 2GB 大小的儲存空間並全部初始化為 0;
    • 加入黑名單:用 **8 個隨機映射函數(F1, F2, …, F8)**得到 8 個隨機數,把該郵箱地址映射到二進位儲存空間的 8 個位置,然後把這些位置置 1。
    • 檢查是否在黑名單:用同樣的映射函數取得 8 個位置上的 bit,如果這些值都為 1,那麼該郵箱地址在黑名單中
    • 書中結論:處理同樣數量的資訊,布隆過濾器只使用 Hash 表所需記憶體的 1/8

D. 電子商務風險控制

  1. 先分清楚在防哪一類風險(書中四類):
    • 帳戶風險:帳戶被駭客盜用、惡意註冊帳號。
    • 買家風險:買家惡意下單占用庫存進行不正當競爭;黃牛利用促銷搶購低價商品;此外還有良品拒收、欺詐退款,以及常見於 B2B 交易的虛假詢盤。
    • 賣家風險:不良賣家惡意欺詐,例如貨不對板、虛假發貨、炒作信用;此外還有出售違禁商品、侵權產品。
    • 交易風險:信用卡盜刷、支付欺詐、洗錢套現。
  2. 機器 + 人工雙軌:大型電商網站都配備專門的風控團隊,風控手段包括自動與人工兩種。機器自動識別為高風險的交易與資訊,會送給風控審核人員進行人工審核;機器自動風控的技術與方法,也不斷透過人工發現的新風險類型逐步完善。
  3. 手段一:規則引擎。當交易的某些指標滿足一定條件就被認為有高風險欺詐可能,例如:使用者來自欺詐高發地區、交易金額超過某個數值、與上次登入的地址距離差距很大、使用者登入地與收貨地不符、使用者第一次交易等。大型網站在營運過程中結合業界最新發現,會總結出數以千計的此類高風險交易規則。
    • 若在業務邏輯中用 if-else 寫死,程式碼會非常龐大,而且新風險類型不斷出現、規則要不斷調整,程式碼也得跟著一直改。
    • 規則引擎是一種將業務規則與規則處理邏輯相分離的技術:業務規則檔由營運人員透過管理介面編輯,需要修改規則時無需更改程式碼、發布程式即可即時使用新規則;規則處理邏輯則負責呼叫規則處理輸入的資料。
  4. 手段二:統計模型。規則引擎技術雖簡單,但隨著規則逐漸增加會出現規則衝突、難以維護,而且規則越多效能越差;目前大型網站更傾向使用統計模型做風控。
    • 做法:使用前述分類演算法或更複雜的機器學習演算法做智慧統計——根據歷史交易中的欺詐交易資訊訓練分類演算法,再把採集加工後的交易資訊輸入,即可得到交易風險分值
    • 書中結論:經過充分訓練後的統計模型,準確率不低於規則引擎,分類演算法的即時計算效能更好;由於統計模型使用模糊識別、並不精確比對欺詐類型規則,因此對新出現的交易欺詐還具有一定預測性

🧪 我實際套用的紀錄

  • (待填)

⚠️ 注意 / 什麼時候不適用

  • 布隆過濾器可能誤判:檢查結果說在黑名單中,但實際卻從未放入過——因為一個地址映射的 8 個 bit 可能正好都被其他地址設為 1。這種可能性極小、通常在系統可接受範圍內,但需要精確判斷時就不適合使用布隆過濾器
  • 分類演算法一定會有誤判與漏判:貝氏得到的是機率值,會有誤判(非垃圾郵件判成垃圾郵件)與漏判(垃圾郵件判成非垃圾郵件)。所以高風險結果要接人工審核,而不是直接處決。
  • 正則不要硬撐:敏感詞多、文字長、並發高時,正則的效率會先垮,該換 Trie 變種或多級 Hash 表。
  • 敏感詞比對不做降噪等於白做:「阿拉_伯」這類手腳會直接繞過。
  • 規則引擎不是終點:規則數量上千之後衝突、維護與效能都會惡化。
  • Hash 表黑名單有記憶體天花板:先按 10 億 × 8 位元組 ÷ 50% 利用率 = 16GB 這種方式算一遍,再決定資料結構。

🔗 相關工具