作者:編碼專家
部落格:https://www.codingbrick.com
寄語:就算終其一生是個平凡人,那也不算什麼失敗。
在軟體系統裡面,功能性需求是面向使用者、詳細明確的需求,由產品人員根據市場的需要提煉出來,是產品生命週期裡最重要的一環。比如電商系統裡面的優惠券功能,通常包含需求:優惠券分類、細分領券人群、核銷優惠券等等。一旦需求透過技術評審,開發人員必須依照文件實現功能,不允許輕易變更。
非功能性需求是什麼呢?保障系統持續健康運轉的輔助需求。依然以電商系統的優惠券為例,在促銷活動期間發放大量優惠券,如何防止使用者集中領券時系統不崩盤呢?活動結束後,如何收縮伺服器,節省伺服器資源呢? 非功能性需求是面向運維的,重要但是不太緊迫,有時候可以沒有操作介面,由架構師提出解決方案,再推動各個業務開發部門去接入相應元件。這些輔助系統對業務系統效能影響很小,並且長期處於最佳化狀態。
1 可伸縮性
可伸縮性是指系統根據外部負載自動調節計算能力,常見的做法是水平擴充套件和垂直擴充套件。
- 水平擴充套件
當系統負載很高時,增加服務端的節點數量,也叫做擴容;當負載很低時,釋放閒置的機器,也叫做縮容。這兩個過程有幾個重要的思考點:
(1)節點越多,承載能力越高嗎:任何事情都有兩面性,為了解決問題引入一個方案,就必然帶來新的問題。節點越多,協調節點的開銷就越大,額外增加的計算資源抵不上協調節點的開銷,併發能力不升反降。
(2)擴容多少節點才夠用:資源總是有限的,用有限的資源做更多的事情,才能得到資本家的歡心。合理擴容的數量根據壓測的結果來定。在日常的運維中,要求系統能夠自動化擴容少量機器處理突發流量,如果超出負載再發出警報。
- 垂直擴充套件
垂直擴充套件是指增強單機處理能力,比如增加記憶體、升級CPU、更換固態硬碟等等。這個做法的好處是簡單快速,無需調整系統設計;缺點是單機的處理能力始終有限,不可能無限升級,而且更換硬體必須停機,影響系統可用性。
2 可用性
系統可用性是指系統在規定的時間內正常執行的能力,是衡量系統質量和穩定性的重要指標之一。例如,一個系統的可用性為99.9%,表示在一年中的時間裡,系統正常執行的時間佔據了99.9%。以下是計算公式:
Availability = (Total Time - Downtime) / Total Time * 100%
Total Time表示總的時間,Downtime表示系統的停機時間。
除了自然災害如水災、地震等不可抗因素,降低可用性的主要原因是:
- 系統錯誤:系統程式碼邏輯存在BUG或者服務端配置錯誤等,導致使用者無法正常訪問。2019年2月22日,京東金融App中的理財資產被系統清零,故障持續約20分鐘。京東客服表示,故障原因是系統升級導致的。
- 基礎設施:通常是硬體故障,比如機房故障、網路故障。2022 年 12 月 18 日,阿里雲香港 Region 可用區 C 機房部分伺服器當機了超過 15 小時,原因是機房水冷裝置的故障。
- 惡意攻擊:駭客攻擊。常用的攻擊方式是DDoS(Distributed Denial of Service Attack),向目標伺服器傳送大量惡意請求來使目標伺服器不可用,合法使用者無法訪問線上服務。
- 系統過載:沒有合理規劃計算節點,訪問量超出系統可以承載的範圍,無法響應使用者的正常請求。
對於大型網際網路公司尤其是SaaS、雲服務等公司,系統可用性就是生命線,只要出現時間過長的服務不可用,會大大影響口碑和品牌。通常這類公司採取的技術措施是異地多活,在不同城市建立獨立的資料中心。“活”是相對於冷備份而言的,冷備份是備份全量資料,平時不支撐業務需求,只有在主機房出現故障的時候才會切換到備用機房,而多活,是指這些機房在日常的業務中也需要做業務支撐。
3 可維護性
可維護性是衡量系統升級的能力,修改或者增加需求,開發週期越短越好,注意與“可伸縮性”區分。
需求變更是無比尋常的事情,可維護性是所有團隊都會關注的重點。一旦系統的可維護性變差,程式設計師的頭髮會迅速脫落。影響可維護性的因素主有三個:
- 業務本身的複雜度,專案成員對業務的熟悉程度。
- 工程程式碼的質量好壞,研發流程的科學與合理性。
- 需求評審等環節的執行質量,技術文件沉澱的質量。
近些年在大型專案開發裡,領域驅動設計(Domain Driven Design)的出鏡率很高。領域驅動設計是一套從系統分析到軟體建模的設計思想和方法論。核心思想是以領域為核心驅動力構建軟體設計體系,並圍繞業務概念抽象出領域模型,透過領域和邊界劃分將複雜的業務模型抽象化、簡單化,最終實現複雜軟體應用系統的拆解和封裝。領域驅動設計並沒有發明新的東西,每個概念都是沿用已久的軟體開發理念。它的實施成本很高,專案程式碼更加繁瑣,人員的溝通成本也較高。
如果團隊規模很小或者開發小型專案,提高可維護性至少要做好兩個事情:
- 開發流程規範化:簡化開發流程但是要嚴格執行重要的節點,比如需求評審;嚴格執行工程程式碼規範;只撰寫重要的技術文件。
- 模組化和可重用性:將重要功能或者工具模組化,能夠重用到新需求上;模組的命名要準確、功能要單一。避免過早做抽象設計,否則陷入過度設計。
4 一致性
資料是系統最重要的資產,資料不能丟也不能錯,保持資料一致性萬分重要。一致性分兩種情況:
- 事務資料一致性:在傳統關聯式資料庫中,事務提交後資料保持一致狀態,即事務的ACID特性。比如同行轉賬,資金從一個賬戶轉移到新的賬戶,兩個賬戶的總額保持不變。
- 副本資料一致性:分散式系統包含多個資料副本,資料可能被同時寫入多個節點,也可能被同時讀取多個節點。最理想的情況是所有副本在任何時刻都具有相同的值。比如跨行轉賬,隸屬不同系統的賬戶,資金從一個賬戶轉移到新的賬戶,兩個賬戶的總額保持不變。
在分散式系統中,保持資料一致性是公認的難題,主要體現在下面幾點:
- 獨立程式:分散式系統無法像單機系統那樣共享記憶體或者程式,需要分別獲得各個程式的本地狀態,再組合成全域性狀態。
- 全域性時鐘:分散式系統沒有全域性時鐘,各個程式無法正確獲得事件訊息的時序關係,狀態的一致性難以保障。
- 網路超時:分散式環境下網路超時狀態的存在,需要具有高度容錯特性的解決辦法。
保持強一致性的成本很高,最好的解決方案就是避免分散式事務,但是在金融、電信領域中的部分業務場景要求資料強一致性,同時要保證服務的可擴充套件性和可靠性。結合實際的業務場景,一致性可以細分五個級別:
- 強一致性(strong consistency):任何時刻、任何使用者或節點都可以讀到最近一次成功更新的副本資料。強一致性是程度最高的一致性要求;
- 單調一致性(monotonic consistency):任何時刻、任何使用者一旦讀到某個資料在某次更新後的值,這個使用者不會再讀到比這個值更舊的值。單調一致性是弱於強一致性卻非常實用的一種級別。通常來說,使用者只關心從自身視角觀察到的一致性,而不會關注其他使用者。
- 會話一致性(session consistency):任何使用者在某一次會話內一旦讀到某個資料在某次更新後的值,這個使用者在這次會話過程中不會再讀到比這個值更舊的值。會話一致性透過引入會話的概念,在單調一致性的基礎上進一步放鬆約束,會話一致性只保證單個使用者單次會話內資料的單調修改,對於不同使用者間的一致性和同一使用者不同會話間的一致性沒有保障。
- 最終一致性(eventual consistency):一旦更新成功,各個副本上的資料最終將達到完全一致的狀態,但達到完全一致狀態所需要的時間不能保障。一個使用者只要始終讀取某一個副本的資料,則可以實現類似單調一致性的效果,但使用者更換讀取的副本,則無法保障任何一致性。
5 彈性
彈性,是指系統可以優雅地處理意外、從故障中恢復過來。故障是不可避免的,甚至不可預測。由於微服務的普及,故障發生的機率與計算節點數量成正比。分散式系統具備一定的容忍故障的能力,故而彈性設計又稱容錯設計,主要的解決方法有如下兩點:
- 故障隔離
系統必須具備防止故障從一個系統傳播到另一個系統的能力,常見場景如下:
(1)系統間強依賴:如果系統間存在強依賴,當一個系統發生故障時,強依賴它的元件將無法正常工作。通常的手段是將強依賴轉化為弱依賴或最弱依賴,比如設定合適的超時、捕獲異常、同步依賴轉非同步依賴、提供備份元件等。
(2)系統共享資源:如果系統間存在共享的資源,如執行緒池、資料庫連線池、網路連線池、記憶體區等等。當一個系統因為故障耗盡了共享的資源後,所有依賴該資源的系統也都會發生故障。通常的手段是對元件的資源使用建立配額體系,或者為重要元件提供專用資源。
- 服務降級、限流、熔斷
(1)服務降級:當出現系統故障後,在有限的資源情況下犧牲某些業務功能或者某些客戶群體,保障更關鍵的業務服務質量。服務降級可以是人工觸發的,也可以是系統自動執行的。所有核心交易場景下的非關鍵服務訪問均應進行服務降級設計,以保證核心交易成功率。
(2)服務限流:當負載超出系統處理能力時,可能會造成系統部分業務失敗,需要透過業務限流來防止系統進一步化。例如在一個分散式系統中,每秒最多隻能處理2000個請求。為了防止系統過載,可以設定規則限制上游服務請求量,當超過2000時隨機拋棄一些請求來實現限流。
(3)服務熔斷:微服務與微服務之間有依賴性,可能導致故障傳播,對整個系統造成災難性的後果,即服務的雪崩效應。熔斷器是透過快速失敗(Fail Fast)的機制,避免請求大量阻塞,從而保護呼叫方。比如:服務A呼叫當下遊B失敗時,會導致請求超時引起堆積佇列,進而加大了B系統的壓力,增加了整個鏈路的請求時間。B系統本身就出現了問題,不斷的請求又把問題加重了。如果使用了A觸發了熔斷,拒絕了上游的請求,會降低下游B服務的壓力,給與B服務恢復的時間。
6 可觀察性
可觀測性是指透過度量、監控和分析系統元件,瞭解系統的狀態、效能和問題的能力。可觀測性可以幫助開發人員快速定位和解決系統中的問題,提高系統的穩定性和可靠性。系統可觀測性設計還有助於最佳化系統效能,幫助研發人員針對性地做出調整和最佳化,提高系統的吞吐量和響應速度。
系統可觀測性設計應遵循幾個重要原則:
- 全面性原則:全域性角度考慮系統的可觀測性,涵蓋系統的各個方面,如效能、錯誤、日誌、指標等。其次是實時性原則,即要確保監測和日誌記錄的資料是實時生成的,這樣可以及時發現問題並做出調整。
- 簡潔性原則:避免過多冗餘的監測資料和日誌資訊,確保資料的準確性和有效性。
- 安全性原則:確保監測資料和日誌資訊的安全儲存和傳輸,防止資訊洩露和資料丟失。
主流的可觀察系統基於三類資料構建,覆蓋了一個應用伺服器產生的大部分資料:
- 日誌:每個應用中產生事件日誌、事務日誌、訊息日誌和伺服器日誌,儲存在日誌資料庫。
- 指標:在單位時間的測量值,包括時間戳、地址等資料。指標資料是固定的結構,以便於系統查詢和儲存,儲存在時序資料庫。
- 鏈路:跟蹤每個請求的來龍去脈,記錄每個處理節點的地址、時間、發起者等等資料,儲存在日誌資料庫。
可觀察性系統是監控系統的超集,監控能夠檢測到系統當前的問題,但是可觀察性系統要幫助研發人員預判故障發生的可能性。
7 安全性
安全性是指保障硬體正常執行,讓使用者只能訪問合法授權的資源。安全是架構設計中很重要的一部分,很多大型企業都因為安全漏洞洩露過資料。廣義的安全性涉及到所有的軟硬體,比如物理機房、伺服器及網路、作業系統、應用系統。架構安全設計可以遵循如下五個原則:
- 認證和授權:使用者透過正確的賬號和密碼等憑證訪問系統,授權決定使用者進入系統後可以做什麼。從最小許可權原則開始,一開始不應該具有任何訪問許可權,根據其工作內容分配許可權。也可以根據工作內容建立訪問組,透過集中式使用者資料庫實現單點登入,進行統一管理授權策略。
- 全方位保障:通常企業主要關注資料中心和物理安全和保護外層網路免受攻擊,其實企業應使用深度防禦方法,將安全防護應用於架構的每一層。例如web應用需要透過保護邊緣網路和域名系統路由來使其免受外部網際網路流量攻擊,在負載均衡和網路層使用安全防護工具組織惡意流量。可以透過限制web應用層和資料層只允許必須的入站、出站流量,來保護應用程式的每一個例項,用防毒軟體保護作業系統。
- 縮小影響半徑:在每一層應用安全措施時,應該始終將系統進行合理的隔離,以減小影響半徑。如果攻擊者獲得了系統某個部分的訪問許可權,應該能夠將安全漏洞限制在應用程式的最小區域內。提供最小的訪問許可權可以確保不會暴露整個系統,提供臨時憑證可以確保訪問許可權不會長期開放,提供開放式介面時要特別謹慎,務必要設定安全令牌,並且定期更換金鑰。
- 監控和審計:將系統中每一項活動都記錄日誌,並定期審計。審計功能要按行業法規要求制定,同時採取主動監控,配備告警能力,從而在使用者受到影響之前對事件進行處理。
- 資料保護:建立一些機制來減少直接訪問資料,透過自動化的工具處理資料,避免人工處理資料,消除人為錯誤。儘可能對資料進行訪問控制,減少資料丟失和資料篡改的風險。資料不僅在靜止狀態下需要保護,在傳輸過程中也要保護。
系統安全等級越高,運作成本越高。為了節省成本,中小型團隊主要聚焦應用系統的安全,其他的交給雲服務。雲服務商負責雲端安全,尤其是用於託管資源的物理基礎設施的安全,包含如下內容:
- 資料中心:全天候安全警衛、雙因子認證、訪問記錄和審查、影片監控、磁碟消磁和銷燬等。
- 硬體基礎設施:伺服器、儲存裝置和其他依賴雲服務的裝置。
- 軟體基礎設施:主機作業系統、服務應用和虛擬化軟體。
- 網路基礎設施:路由器、交換機、負載均衡器、防火牆、佈線等,還包括對外部邊界、安全接入點和冗餘基礎設施的持續網路監控。
開發團隊根據自身人力和財力,酌情實施安全設計,通常可以借鑑的安全措施有5條:
- 作業系統:及時升級服務端作業系統的補丁,避免伺服器遭受外部攻擊。
- 應用程式:主要包含應用程式和它的環境(如開發、測試和生產環境),及其所屬密碼策略和訪問管理的安全措施。
- 防火牆:採用防火牆保護整個系統免受外部攻擊。雲服務提供了這方面的安全保障,但使用者可以考慮增加額外的安全層。
- 網路配置和安全組:雲服務提供了建立網路防火牆的工具,使用者需要設定防火牆規則,以確保其系統免受來自外部和內部的網路流量的破壞。
- 資料加密:透過各種加密機制來保護業務資料,匯出重要資料時要考慮脫敏。