朱曄的互聯網架構實踐心得S1E8:三十種架構設計模式(下)前端
【下載本文PDF進行閱讀】node
接上文,繼續剩下的15個模式。算法
一直有一個說法就是不到沒路可走的時候不要考慮數據庫分片。有的時候業務量大到單個業務表在通過緩存+隊列削峯等措施以後的平均的TPS超過1萬,單表實在是扛不住,仍是隻能考慮分片手段。數據庫
分片前:後端
分片後:設計模式
相信互聯網公司90%+確定都使用了這個模式。把靜態資源從動態網站中剝離由Nginx等高性能服務器來處理靜態資源,而後使用三方CDN對靜態資源進行加速,不但減輕了動態網站的負載並且數據在邊緣節點加速讓用戶的訪問跟快,使用單獨的一個或多個子域名作靜態資源還能提升下載資源的並行度提升網頁加載的速度。緩存
使用CDN來進行資源加速通常有主動數據傳送到CDN存儲和在CDN配置回源站拉取兩種方式,文件類通常使用主動推送數據,靜態資源類通常使用回源方式。在使用CDN的時候考慮下面的問題:安全
在第三第五兩篇文章中我都提到了索引表的作法。出於下面的緣由,咱們會考慮索引表:服務器
不過須要考慮一點索引只有在數據區分度高的狀況下才能發揮價值,若是90%以上的數據都是相同的值,那麼走索引進行查詢性能會比全表掃還要差一點。網絡
這裏說的是不一樣的前端配以不一樣的專用後端。好比PC網站和APP的後端是兩套程序。這種模式是否適合其實仍是看兩端的後端提供的數據差別有多大,咱們老是但願能夠儘可能統一一套後端,業務邏輯不用重複寫,可是咱們要考慮到PC網站和APP的差別性:
考慮到這些差別,咱們是在一個工程內根據來源作適配,仍是獨立兩套工程來作獨立的後端取決於差別度有多大了。
這個模式從資源節省的角度來講咱們的計算單元任務能夠進行一些合併,減小由於資源限制致使沒必要要的開銷。
對於分佈式服務,咱們趨向於把服務設計爲無狀態能夠任意擴展的,可是在某些業務場景下咱們不得不在服務中選舉出一個Leader(Primary節點,Master節點)來作一些不適合重複作的協調管理工做。這個時候咱們須要有算法來作選舉。
最多見的實現方式是使用Zookeeper來實現,咱們知道ZK的znode有Sequence和NonSequence兩種,前者多個客戶端只有一個可建立成功同名節點,後者建立後會自動加上序列號命名多個客戶端能夠建立多個同名節點,利用這個特性有兩種常見實現方式:
在軟件設計模式中過濾器構成的管道這種模式很常見(圖上的業務邏輯就是Handler,以前的那些Task就是Filter,模式上能夠是Filter+Handler也能夠是Filter+Handler+Filter也能夠是Handler+Filter),無論是Spring MVC框架也好,Netty這種網絡框架也好都提供了這樣的設計。每個過濾器單獨完成一個功能,能夠獨立插拔隨意組合配置成一套管道,不但數據處理的整個過程清晰可見還增長了靈活性。
對於架構上也能夠有這樣的模式,在數據源進入到業務邏輯處理以前(或以後,或先後),咱們能夠配置一系列的數據過濾器完成各類數據轉化和處理的任務。Task和Task之間能夠是同步調用,也可使用MQ作必定的可伸縮性設計。還能夠把過濾器的配置信息保存在配置系統中甚至根據上下文動態構建出管道,實現更靈活的前置或後置流程處理。
這裏說的是消息隊列的消息消費者是一組對等的消費者,經過競爭方式來拉取數據執行。以前提到過這是MQ的最多見的一種模式,通常而言咱們會部署多個消費節點進行負載均衡,在負載較大的時候能夠方便得增長消費者進行消費能力擴容。不過對於這種模式消費者應當是對等的無狀態的,在某個消費者在消費失敗的時候消息從新回到隊列隨後可能會被另外一個消費者進行處理。
重試適用於瞬態故障,以後會提到斷路器模式,兩種模式能夠結合使用。首先說說重試的幾個發起人:
重試也要考慮幾種策略:
這個模式說的是三者的角色:
三個角色相互配合完成複雜的,具備較多遠程服務參與的任務,確保任務的最終有效執行。在以前架構三馬車一文中說到定時任務的時候提到過一種任務驅動表的模式,說到了一些驅動表的實現細節,其實總體和這個模式是相似的思想。當咱們的一個複雜邏輯有多個步驟構成,每一步都依賴外部服務,這個時候咱們能夠選擇全程MQ+補償方式(樂觀方式),也能夠選擇全程任務驅動的被動模式(悲觀方式),具體選擇取決於更看重可靠性仍是及時性。
資源隔離有好幾個層次,能夠在進程內部作線程池或隊列的隔離,在微服務的服務劃分上考慮隔離出單獨的物理服務,或是在服務器層面經過虛擬化技術或Docker技術進行資源隔離。隔離了就不會相互影響,可是會有成本、性能、管理便利性方面的開銷。實現可以根據需求分析出可能的資源相互影響的點,提早規劃隔離每每能夠避免不少問題的發生。以前有遇到過幾個事故是這樣的:
分佈式應用環節多網絡環境複雜,若是遇到依賴服務調用失敗的狀況咱們或許能夠進行重試期待服務立刻能夠恢復,可是在某些時候依賴的服務是完全掛了而不是網絡故障沒法及時恢復,若是不考慮進行熔斷的,可能服務調用方會被服務提供方拖死。這個時候能夠引入斷路器機制,如圖所示斷路器通常採用三態實現,瞬間恢復可能會讓底層服務壓力過大:
實現模式的時候考慮下面注意點:
實現上咱們能夠看一下Netflix的Hystrix進行進一步瞭解。
這個模式說的是失敗時必須進行撤銷的操做,能夠由一組補償程序來作相應的補償。在這裏我想說的更廣一點,在服務調用的時候,調用失敗有幾種可能:
因此在出現服務調用失敗或超時的時候,服務端執行究竟有沒有成功客戶端是不明確的(只有客戶端收到了明確的服務端返回的業務錯誤才真正表明執行失敗),這個時候須要有補償邏輯來同步服務端的執行狀態。若是這樣的補償不可避免並且須要補償的服務特別多,這樣的邏輯逐一來寫是一件很煩的事情,咱們能夠把這個工做封裝成一個補償中間件來處理:
這樣,咱們在服務調用的時候就不須要考慮補償邏輯的實現,只要實現這個標準便可。
這個模式說的是,在訪問敏感資源的時候,咱們能夠沒必要讓應用程序在其中做爲一個代理轉一層作權限控制,而是生成一個密鑰,讓用戶直接拿着密鑰到資源池換數據。
一些CDN在提供資源上傳下載服務的時候通常都會提供相似的安全策略,須要實現生成Token才能去使用下載和上傳服務,避免了CDN數據被非法利用做爲圖牀的可能。
實現上比較簡單,應用程序和資源提供方約定好Token的生成算法,對資源+請求資源的時間+密鑰聯合在一塊兒作簽名,資源提供方若是校驗到簽名不正確或Token過時或資源不匹配都將拒絕服務。
這個模式說的是將身份驗證委託給專門的程序或模塊來作。使用專門的模塊來統一負責登陸受權不只僅能夠提供單點登陸的功能,並且服務實現上更簡單不須要每次都考慮登陸那套東西。實現上能夠看一下Spring Security實現的OAuth 2.0。
總結一下,對於其中的不少模式,咱們能夠發現其實在以前的一些介紹或多或少有一些涉及。這裏提到的30種模式有些體現的是一些設計細節,有些體現的是一種設計理念,它們大多時候是組合使用的,適合的就是最好的,你們能夠細細品味一下每種模式的適合場景,在合適的時候能夠想到它或許會有一種豁然開朗的感受。