概述#
在軟體工程的歷史中,效能(Performance) 長期以來一直是架構設計的首要驅動力。當電腦既慢又昂貴、待處理的任務遠超運算能力時,效能經常犧牲其他所有品質屬性。隨著硬體價格持續下降,其他品質屬性逐漸受到重視,但效能始終具有根本重要性——總是存在我們知道如何用電腦解決、但無法快到足以實用的重要問題。
所有系統都有效能需求,即使沒有明確表述。例如,文字處理工具可能沒有明確的效能需求,但沒有人能接受打字後等待一小時(甚至一分鐘、一秒鐘)才看到字元出現在螢幕上。
效能通常與 可擴展性(Scalability) 緊密相關——增加系統工作容量的同時維持良好效能。從技術上講,可擴展性是一種特定方向的可修改性(Modifiability),使系統容易在特定方面變更。雲端服務的可擴展性在第 17 章有更詳細的討論。
效能改善往往發生在系統建構之後。透過預先考慮效能的架構設計(例如可擴展的資源池),可以為未來的效能調校預留空間。利用 instrumentation 記錄時間資訊,能幫助找出實際的效能瓶頸。花大量時間最佳化僅佔總時間很小百分比的系統部分是不划算的。
Performance General Scenario#
效能情境始於一個 事件(event) 到達系統。正確回應該事件需要消耗資源(包括時間),且系統可能同時在處理其他事件。
並行性(Concurrency) 是架構師必須深刻理解、但在電腦科學課程中鮮少被充分教授的重要概念。並行性出現在多執行緒、多處理器、平行演算法、Map-Reduce 等平行化基礎設施、NoSQL 資料庫,以及各種並行排程演算法中。
並行性在擁有多個 CPU 或可利用等待狀態時是好事——允許操作平行發生可以提升效能,因為一個執行緒引入的延遲允許處理器在另一個執行緒上前進。但並行性也帶來 競爭條件(Race Condition) 的風險。例如,兩個執行緒都執行
x = 1; x++;,最終 x 的值可能是 2 或 3。管理並行性的核心在於管理狀態的共享方式:使用 鎖(Lock) 強制對狀態的循序存取,或 分區狀態(Partition State) 使每個執行緒擁有獨立的狀態副本。競爭條件是最難發現的 Bug 類型之一——其發生是偶發的,取決於極微小的時序差異。
效能通用情境的組成部分:
- 來源(Source):刺激可來自使用者(或多個使用者)、外部系統、或系統內部的某個部分
- 外部:使用者請求、外部系統請求、感測器或其他系統的資料
- 內部:元件間的請求、計時器產生的通知
- 刺激(Stimulus):事件的到達,可以是服務請求或狀態通知
- 週期性(Periodic) 事件以可預測的間隔到達
- 隨機性(Stochastic) 事件依照某種機率分佈到達
- 偶發性(Sporadic) 事件的到達模式既非週期性也非隨機性
- 製品(Artifact):整個系統或系統中的特定元件。例如開機事件可能刺激整個系統,而使用者請求可能到達(刺激)使用者介面
- 環境(Environment):系統運行時的狀態——正常模式、緊急模式、錯誤修正模式、尖峰負載、過載模式、降級運作模式。異常模式(錯誤模式、過載模式)會影響回應
- 回應(Response):系統處理刺激。處理需要時間,可能因運算而消耗時間,也可能因共用資源的競爭而被阻塞。回應包括回傳結果、回傳錯誤、不產生回應、忽略過載請求、變更服務模式或等級、處理較高優先權事件
- 回應量測(Response Measure):
- 回應所需的最大、最小、平均、中位數時間(延遲,Latency)
- 在某時間區間內滿足的請求數量或百分比(吞吐量,Throughput)
- 未被滿足的請求數量或百分比
- 回應時間的變異(抖動,Jitter)
- 運算資源的使用率

Figure 9.1: Sample performance scenario
具體情境範例:500 位使用者在 30 秒的間隔內發起 2,000 個請求,在正常運作環境下,系統處理所有請求,平均延遲為 2 秒。此情境完整展示了來源(500 位使用者)、刺激(2,000 個請求)、環境(正常運作)、回應(處理所有請求)和回應量測(平均延遲 2 秒)。
Tactics for Performance#
效能策略的目標是在 時間或資源限制 下,對到達系統的事件產生回應。事件可以是單一事件或事件流,是觸發運算的要素。效能策略控制產生回應所使用的時間或資源。

Figure 9.2: The goal of performance tactics
在事件到達到系統回應完成的期間,系統不是在主動處理事件,就是因某種原因被阻塞。這導出回應時間的兩個基本貢獻因子:
- 處理時間(Processing Time):系統主動消耗資源來回應事件。事件由一個或多個元件執行處理,其消耗的時間即為資源。硬體資源包括 CPU、資料存儲、網路頻寬、記憶體;軟體資源包括執行緒池、緩衝區等。例如,一個訊息從元件產生、放上網路、到達另一個元件、放入緩衝區、轉換、處理、再轉換輸出——每一步都貢獻了整體延遲。不同資源在接近飽和時的行為也不同——CPU 負載增加時效能漸進下降,而記憶體耗盡時效能可能因分頁交換(Page Swapping)而突然崩潰。
- 阻塞時間(Blocked Time):運算可能因以下原因被阻塞:
- 資源競爭(Contention):許多資源一次只能由單一客戶端使用,其他客戶端必須等待。多個串流爭用同一資源時,延遲會持續增長。
- 資源不可用(Unavailability):即使沒有競爭,若資源離線或故障,運算也無法進行。
- 依賴其他運算(Dependency):運算可能需要等待與另一個運算的結果同步,當被呼叫的元件在網路另一端或負載很重時,等待時間可能很可觀。
Control Resource Demand#
提升效能的一種方式是謹慎管理資源需求。可以減少處理的事件數量、限制系統回應事件的速率,或確保明智地運用現有資源:
- 管理工作請求(Manage Work Requests):減少進入系統的工作請求數量。
- 管理事件到達(Manage Event Arrival):從外部系統管理事件到達的常見方式是制定 服務等級協議(SLA),指定你願意支援的最大事件到達率。SLA 的形式為「系統或元件將在每單位時間到達 X 個事件的條件下,以 Y 的回應時間處理」。它同時約束系統(必須提供回應)和客戶端(若發出超過 X 個請求,回應不被保證)。從客戶端角度看,若需要超過 X 個請求被服務,就必須使用多個處理請求的元素實例。SLA 是管理網際網路系統可擴展性的方法之一。
- 管理取樣率(Manage Sampling Rate):當系統無法維持足夠的回應水準時,可降低刺激的取樣頻率(例如感測器資料接收率或影片幀率)。代價是保真度降低,但結果可能「夠好」。例如在訊號處理系統中,可選擇不同取樣率和資料格式的編解碼器。此設計選擇旨在維持可預測的延遲水準;你必須決定較低保真度但一致的資料流是否優於不穩定的延遲。某些系統會根據延遲量測或精確度需求動態調整取樣率。
- 限制事件回應(Limit Event Response):當離散事件到達系統(或元件)過快而無法處理時,事件必須排入佇列等待處理,或直接丟棄。可選擇僅以設定的最大速率處理事件,確保被處理事件的可預測性。此策略可由佇列大小或處理器使用率超過某警告水準觸發,也可由違反 SLA 的事件速率觸發。若採用此策略且無法接受丟失任何事件,必須確保佇列大到足以處理最壞情況。若選擇丟棄事件,需建立政策:是否記錄丟棄的事件?是否通知其他系統、使用者或管理員?
- 優先處理事件(Prioritize Events):若非所有事件都同等重要,可施加優先權方案,依重要性排序。資源不足時可忽略低優先權事件——忽略事件消耗的資源極少(包括時間),因此與服務所有事件的系統相比可提升效能。例如:建築管理系統可能觸發各種警報,危及生命的火災警報應獲得比房間過冷等資訊警報更高的優先權。
- 降低計算開銷(Reduce Computational Overhead)
- 減少間接層(Reduce Indirection):中介層(對可修改性很重要)會增加計算開銷,移除它們可改善延遲。這是典型的 可修改性/效能權衡。巧妙的程式碼最佳化可在保留封裝性的同時減少或消除執行時的間接成本。
- 共置通訊資源(Co-locate Communicating Resources):將合作的元件放在同一處理器上以避免網路延遲;或放在同一執行時元件中以避免子程式呼叫開銷;或將多層架構放在同一資料中心機架上。
- 週期性清理(Periodic Cleaning):定期清理變得低效的資源,如重新計算雜湊表和虛擬記憶體映射。
- 限制執行時間(Bound Execution Times):對迭代式、資料相依的演算法限制迭代次數,以限制回應事件所消耗的執行時間。代價是通常會得到較不精確的計算結果。若採用此策略,需評估其對精確度的影響並判斷結果是否「夠好」。此策略經常與管理取樣率策略搭配使用。
- 提高資源使用效率(Increase Efficiency of Resource Usage):改善關鍵區域的演算法效率可降低延遲、提升吞吐量並改善資源消耗。對某些程式設計師而言,這是他們的首要效能策略——但正如本節所示,這實際上只是眾多可用策略之一。
Manage Resources#
即使資源需求不可控,仍可有效管理現有資源。有時一種資源可以換取另一種——例如中間資料可以保留在快取中,也可以重新產生,取決於時間、空間或網路頻寬哪個更關鍵:
- 增加資源(Increase Resources):更快的處理器、更多處理器、更多記憶體、更快的網路——這些都有潛力改善效能。成本通常是選擇資源時的考量因素,但在許多情況下,增加資源是獲得立即改善 最便宜 的方式。
- 引入並行(Introduce Concurrency):如果請求可以平行處理,阻塞時間就能減少。可以在不同執行緒上處理不同事件流,或建立額外執行緒處理不同活動集。一旦引入並行,可以透過排程資源策略選擇合適的排程策略來達成目標。
- 維護多個運算副本(Maintain Multiple Copies of Computations):減少所有請求集中在單一實例時的競爭。例如微服務架構中的複製服務或伺服器池中的複製 Web 伺服器。負載平衡器(Load Balancer) 是一種將新工作分配到可用重複伺服器的軟體,分配標準可以簡單如 Round-robin,也可以是將下一個請求分配給最閒的伺服器。
- 維護多個資料副本(Maintain Multiple Copies of Data):兩種常見方式:
- 資料複製(Data Replication):保持獨立的資料副本以減少多個同時存取的競爭。需承擔保持副本一致和同步的責任。
- 快取(Caching):在不同存取速度的儲存上保持資料副本(可能是子集)。速度差異可能來自記憶體 vs. 次級儲存,或本地 vs. 遠端通訊。快取策略可以簡單地保留最近請求的資料,也可以根據行為模式預測未來請求並預先計算或預取。
- 限制佇列大小(Bound Queue Sizes):控制最大排隊到達數量,從而限制處理所需的資源。若採用此策略,需建立佇列溢出時的處理政策,並決定不回應丟失的事件是否可接受。此策略經常與限制事件回應策略搭配使用。
- 排程資源(Schedule Resources):當資源競爭發生時,資源必須被排程。處理器需要排程、緩衝區需要排程、網路也需要排程。架構師需要理解每種資源使用的特性,並選擇與之相容的排程策略。
排程策略 概念上由兩部分組成:優先權指派 和 調度(Dispatching)。排程策略的競爭標準包括最佳資源使用率、請求重要性、最小化資源使用數量、最小化延遲、最大化吞吐量、防止飢餓以確保公平性等。常見策略包括:
- 先進先出(FIFO):所有請求平等處理。但若某些請求優先權較高,可能被卡在長時間處理的請求之後。
- 固定優先權排程(Fixed-priority):依靜態優先權排序,確保高優先權請求獲得更好的服務。但低優先權請求可能因被一連串高優先權請求阻擋而花費任意長的時間。三種常見優先權策略:
- 語義重要性(Semantic Importance):根據任務的領域特性靜態指派
- 截止時間單調(Deadline Monotonic):截止時間越短,優先權越高
- 速率單調(Rate Monotonic):週期越短,優先權越高(Deadline Monotonic 的特例)
- 動態優先權排程(Dynamic-priority):
- 輪詢(Round-robin):依序分配資源,特殊形式為固定時間間隔的 Cyclic Executive
- 最早截止時間優先(Earliest-deadline-first, EDF):根據最早截止時間指派優先權
- 最少鬆弛優先(Least-slack-first, LSF):將最高優先權指派給鬆弛時間(剩餘執行時間與截止時間的差距)最少的工作
- 對於單處理器和可搶占的程序,EDF 和 LSF 都是 最佳 選擇——若任務集可被排程使所有截止時間都被滿足,這些策略一定能成功排程
- 靜態排程(Static Scheduling):離線確定搶占點和指派順序(如 Cyclic Executive),消除排程器的執行時開銷

Figure 9.3: Performance tactics
Tactics-Based Questionnaire for Performance#
根據前述策略,可以建立一組策略導向的問題。為了取得架構在支持效能方面所做選擇的概覽,分析者提出每個問題並記錄答案。這些答案隨後可成為進一步活動的焦點:文件調查、程式碼或其他製品的分析、程式碼逆向工程等。
問卷以策略群組分類,主要問題包括:
Control Resource Demand 相關問題:
- 是否有 SLA 指定最大事件到達率?
- 是否能管理事件取樣率?
- 如何限制事件的處理量?
- 是否定義了不同的請求類別與優先權?
- 是否能透過共置、資源清理或減少間接層來降低計算開銷?
- 是否能限制演算法的執行時間?
- 是否透過演算法選擇提高計算效率?
Manage Resources 相關問題:
- 是否能配置更多資源給系統或其元件?
- 是否採用並行處理?若請求可以平行處理,阻塞時間可以減少。
- 運算是否能在不同處理器上複製?
- 資料是否能快取(維護可快速存取的本地副本)或複製(減少競爭)?
- 佇列大小是否有上限,以限制處理刺激所需的資源?
- 所使用的排程策略是否適合效能需求?
分析者應將問卷答案記錄在結構化的表格中,包含策略群組、策略問題、是否支援(Y/N)、風險評估、設計決策與位置、以及理由與假設等欄位。這些答案將成為後續深入活動的焦點。
Patterns for Performance#
效能問題困擾軟體工程師數十年,因此發展出豐富的模式集合來管理效能的各個方面。值得注意的是,某些模式具有多重用途——例如第四章的 Circuit Breaker 模式既是可用性模式,也透過減少等待無回應服務的時間而有益於效能。
以下介紹四種效能模式:Service Mesh、Load Balancer、Throttling 和 Map-Reduce。
Service Mesh#
Service Mesh 用於微服務架構。其核心特性是 Sidecar——一種伴隨每個微服務的代理(proxy),處理所有跨服務通訊與協調。Sidecar 提供應用無關的功能,如驗證與授權、服務發現、負載平衡、加密和可觀測性。它與微服務一起部署(通常打包在 Pod 中),大幅減少了因網路傳輸造成的延遲。
這種方法讓開發者將微服務的 核心業務邏輯 與 跨領域關注點 的實作、管理和維護分離。
- 優點:跨領域關注點的軟體可以購買現成的或由專門團隊維護,讓業務邏輯開發者專注於單一關注點;強制將工具函式部署在同一處理器上以減少通訊時間(不需使用網路訊息);可依據上下文配置通訊(支援 Canary 部署和 A/B 測試)
- 權衡:Sidecar 引入額外的執行程序,每個都會消耗一些處理能力,增加系統開銷;Sidecar 通常包含多種功能,但並非所有服務或每次呼叫都需要全部功能
Load Balancer#
負載平衡器(Load Balancer) 是一種中介,處理來自客戶端的訊息並決定由哪個服務實例回應。關鍵在於:負載平衡器作為 單一入口點(例如單一 IP 位址),但將請求分配到提供者池(伺服器或服務)。它實作了某種形式的 排程資源 策略——排程演算法可以很簡單(如 Round-robin),也可以考慮每個提供者的負載或待處理請求數。
- 優點:伺服器故障對客戶端不可見(只要還有剩餘處理資源);透過分攤負載維持較低且可預測的延遲;新增資源(更多伺服器、更快伺服器)相對簡單,客戶端無需感知
- 權衡:負載平衡演算法必須非常快速,否則本身可能導致效能問題;負載平衡器是潛在的瓶頸或單點故障,因此本身也經常被複製(甚至被負載平衡)
Throttling#
節流(Throttling) 模式是 管理工作請求(Manage Work Requests) 策略的封裝。用於限制對重要資源或服務的存取。在此模式中,通常有一個中介——節流器(Throttler)——監控(針對某服務的)請求並決定傳入的請求是否可以被服務。
- 優點:透過節流傳入請求,可以優雅處理需求波動,使服務永不過載,保持在效能「甜蜜點」高效處理請求
- 權衡:節流邏輯必須非常快速,否則本身可能導致效能問題;若客戶端需求經常超過容量,緩衝區需要非常大,否則有丟失請求的風險;此模式難以加入客戶端與伺服器緊密耦合的現有系統
Map-Reduce#
與其他與應用無關的效能模式不同,Map-Reduce 模式是專門為特定類型的重複問題設計的:排序和分析大型資料集。處理海量資料的任何組織都會遇到此問題——Google、Facebook、Yahoo、Netflix 等都實際使用 Map-Reduce。此模式有效地透過大規模平行處理對大型資料集執行分散式排序與分析,同時為程式設計師提供簡單的方式來指定所需的分析。
此模式有三個部分:
- 專用基礎設施:負責將軟體分配到大規模平行運算環境的硬體節點(虛擬機器、獨立處理器或多核心晶片中的核心),並處理資料排序
- Map 函式:接受鍵值和資料集,使用鍵將資料雜湊到桶(bucket)中,並可過濾資料。例如,若資料集是撲克牌,鍵可以是花色——Map 將每張牌分到對應花色的桶中。輸入檔被分成多個部分,多個 Map 實例平行處理不同分區,彼此無需通訊。處理完畢後,桶被 shuffle 並分配到新的處理節點進行 Reduce 階段。
- Reduce 函式:所有重要的分析都在此階段進行。Reduce 實例數對應 Map 輸出的桶數。Reduce 執行程式指定的分析並輸出結果,輸出集通常遠小於輸入集——這就是「reduce」之名的由來。
Map 實例是 無狀態 的且彼此不通訊。Map 與 Reduce 之間唯一的通訊是 Map 產出的
<key, value>對。
優點:
- 透過平行處理,可有效分析超大型未排序資料集
- 任何實例的故障對整體處理的影響都很小,因為 Map-Reduce 通常將大型輸入資料集分割為許多較小的資料集進行處理,每個分配到自己的實例
權衡:
- 若資料集不夠大,Map-Reduce 產生的開銷不划算
- 若資料集無法分割為大小相似的子集,平行處理的優勢將喪失
- 需要多次 Reduce 的操作編排複雜
效能與其他品質屬性之間經常存在 權衡(Tradeoff)。最典型的是效能與可修改性的權衡——減少間接層可改善延遲但犧牲可修改性;共置資源可改善效能但降低部署彈性。架構師需要在這些競爭性需求之間找到平衡點。
效能策略與道路系統的類比:交通工程師使用的設計「技巧」與效能策略如出一轍——高速公路入口匝道的紅綠燈就是管理事件到達率;救護車和警車的優先通行就是優先處理事件;增加車道就是維護多個副本;買法拉利就是增加資源。效能就是效能——工程師數百年來一直在使用相同的設計策略來最佳化複雜系統。
總結#
效能是最基本的品質屬性之一。架構師需要理解 處理時間 和 阻塞時間 這兩個影響回應時間的因素,並運用 控制資源需求(管理工作請求、限制事件回應、優先處理事件、降低計算開銷、限制執行時間、提高效率)與 管理資源(增加資源、引入並行、維護多個副本、限制佇列大小、排程資源)兩大策略類別來達成效能目標。在實踐中,Service Mesh、Load Balancer、Throttling 和 Map-Reduce 等模式提供了成熟的解決方案。另外值得注意的是,某些模式跨越多個品質屬性——例如 Circuit Breaker 既是可用性模式,也透過減少等待無回應服務的時間而有益於效能。關鍵在於先透過 instrumentation 識別瓶頸,再有針對性地應用策略,而非盲目最佳化。