摘要:如果你對異步的了解比較模糊的話,這次可以帶你一次性深入淺出。同步異步任何事物都是有利有弊的。這也導致了在異步環境下做事務的成本更高。但是,異步在跨進程通訊中更合適抽象成事件來進行協作。
如果第二次看到我的文章,歡迎「文末」掃碼訂閱我個人的公眾號(跨界架構師)喲~?
每周五早8點 按時送達到公眾號。當然了,也會時不時加個餐~
Z哥在前面的三篇文章里和你一起聊了「高性能」主題下與「緩存」相關的內容。這次和你來聊聊提高性能的另一個大招——「異步」。
如果你已經對「異步」有所了解的話,這次可以讓你有更深刻的理解。如果你對「異步」的了解比較模糊的話,這次可以帶你一次性深入淺出。
不管我們的思維模式也好,還是平時寫的最習慣的代碼,其實都是以「同步」的方式在進行的。所以,「同步」方式用著也挺好,為啥要「異步」呢?拿你平時去買奶茶、買咖啡的例子來說說你就明白了。
你應該有注意到,一般奶茶店都會分“點單區”和“取餐區”。
然后你去消費的時候都是在“點單區”選擇飲料然后付錢,在“取餐區”拿做好的飲料。其實這個過程就是「異步」的,因為當營業員在做飲料的時候,你是可以去干其它事的,比如在邊上開一局王者榮耀或者吃雞。而他們也可以繼續接受后面顧客的點單。
如果是「同步」會怎樣呢?就是你在點單區點好飲料之后,繼續排著隊干等著營業員做好,直到營業員把飲料做好交給你之后,你就可以走人了,他再繼續服務后面的顧客。
很明顯,如果一個店鋪里有2個或者2個以上的營業員,用這種「異步」的方式“吞吐量“更高。
因為來買飲料的人時間是不規律的,可能有時候一下子來十幾個,可能有時候半小時都不來一個。那么通過這種「異步」的方式,雖然不能縮短制作飲料的時間,但是可以縮短人流量大的時候顧客的等待點單時間,讓顧客可以去做其它事。
其實軟件系統也是如此,如今我們程序所在的服務器幾乎全部是多核多線程的。既然有多個“營業員”在,那么通過「異步」的方式盡可能的發揮多線程的作用,才是物盡其用的辦法,還能提升整體的效率。
不過,這事在軟件系統中要稍微復雜一些,要多考慮一下。因為線程的創建、銷毀、切換成本在很多時候甚至比獲得的收益還要高。所以,只有將「異步」運用于「等待處理的時間」>「創建、銷毀、切換線程的時間」的場景下才有價值。
要滿足這種場景的話,一般就是涉及到「I/O」處理的地方。比如磁盤I/O、網絡I/O。
比如,一旦涉及到數據庫查詢或者RPC調用的時候,如果使用「同步」的方式通信,發起一個調用后,調用方會阻塞自己并等待整個操作的完成(想象一下執行一條耗時10秒鐘的sql)。如果使用「異步」通信的話,調用方不需要等待操作完成就可以返回,甚至可能不需要關心整個操作完成與否。
特別對于如今的移動網絡環境下,通過異步的方式可以在很大程度上保證當網絡很卡的時候APP上的操作依然是流暢的,不會出現卡機。
任何事物都是有利有弊的。「同步」可以立馬知道到底成功與否(比如做奶茶的時候營業員發現珍珠沒了,馬上就可以告訴你),而「異步」不行(這個時候你可能去別的地方溜達了)。這也導致了在「異步」環境下做「事務」的成本更高。
而且,在分布式系統中遍布著RPC調用,如果是「同步」調用的話,還可以配合「短鏈接」做到對連接資源的用完即放。而「異步」的話連接保持的時間要更長一些,至少要等到回調觸發完成后才能釋放。
而且Z哥還要提醒你,在使用「異步」的時候,有兩點特別容易被忽略。
發起請求的線程往往和接收響應的線程不是同一個,所以「線程上下文」是不連續的。(當然可以通過做一些額外的編碼工作達到類似的效果)
雖然請求的順序是由客戶端控制的,但是回調的時候可能就不一定是按照請求時的順序進行的,像下圖這樣。
這么看來,「同步」和「異步」都可以通過「請求/響應」模型來完成。但是,「異步」在跨進程通訊中更合適抽象成「事件」來進行協作。
通過「事件」進行「異步」協作的話,客戶端不是發起請求,而是發布一個「事件」,然后期待其他的協作者接收到該消息,并且知道該怎么處理它,客戶端不用關心其他協作者做了什么,甚至也無需知道有哪些協作者存在。
基于「事件」的協作方式耦合度很低。客戶端發布一個「事件」,但并不需要知道誰或者什么會對此作出響應,這也意味著,你可以在不影響客戶端的情況下對該「事件」添加新的訂閱者。
總的來說,異步雖然能提升效率,但是還是無法在所有場景使用它。在實際工作中,往往我們會同時運用「同步」和「異步」,所以了解清楚它們之間的區別和優缺點是很有必要。
我們以一個電商APP中的“下單”場景來舉個例子。
在電商的業務場景中,下單最常見的就是以下幾個操作(順序隨便排的)。
扣減庫存
核銷優惠券
生成訂單
生成電子發票
這些操作都是由用戶在APP中點擊“提交訂單”按鈕之后觸發的。
那么首先來看APP這邊。一般我們的APP僅僅負責UI層面的展示控制,業務邏輯部分都是下沉到后端的API去做的。而APP和API之間大多都是以Http或者Tcp協議的形式進行通信的,那么在APP層面,我們只要借助一些異步編程的類庫即可(這方面不是特別專業,就不多BB了)。
然后到API層面,先給所有接收請求的Action加上異步支持,java的話可以在注解處增加asyncSupported = true,.net的話增加aysnc關鍵字。如此一來,就是告訴程序所在的宿主(web server或者service)“我這個方法是支持異步的,你接收到請求之后就不要阻塞了,去忙別的吧”。
接下來就輪到處理上面提到的電商下單場景中的4個操作了。理論上,這4個操作可以全部按「請求+回調」的異步模式進行,完全可行。這個過程其實有點像「并行」的意思,最終的處理完成時間是由最晚完成回調的那個操作決定的。
但是,為了避免個別程序的意外情況導致最晚回調的時間被拉的很長,我們就需要來考慮一下,那些無需即時知道甚至無需關心返回結果的操作可以通過「事件」的形式進行「異步」。
比如,像“生成電子發票”這種操作,對當前這個業務場景來說并不需要實時知道它的返回結果。
雖然我們知道它的業務邏輯相比生成訂單這些更簡單,處理起來很快,但是一旦服務出現問題,那就不好說了。
題外話:網絡是不可信的,因為它容易受到攻擊、不穩定,所以在分布式系統中這些“意外情況”格外常見。多一個硬性的依賴,就多一份出錯的可能性。
如果沒有做好前面一些文章中提到的「高可用」保障(文末放傳送門,感興趣的可以看完這篇再去看)的話,一旦所依賴的服務出現問題就會被拖累,導致接收到最晚回調的時間拉長,甚至由于未能及時回調回來導致當前的處理無法繼續下去。
那像這樣的業務點,我們就可以通過「事件」的形式進行「異步」處理,比如在生成完訂單之后發出一個“訂單被創建”的「事件」,然后由訂閱該「事件」的“生成電子發票服務“接收該「事件」并進行處理。如此一來,即提高了“提交訂單”時的處理效率,還使得“電子發票服務“的任何波動都不會影響到“提交訂單”操作的正常進行。
對這個「事件」的處理,你可以在程序中建立一個多帶帶的方法進行,它的入參是一個「事件」基類,返回值是void。具體的「事件」數據你可以選擇持久化到DB,也可以選擇投遞到MQ中。大致是下面這樣的代碼
void SendEvent(BaseEvent event){ //投送到DB或者MQ; } ? ? class BaseEvent{ DateTime OccurredTime; } ? class OrderCreated extend BaseEvent{ Order order; Invoice invoice; ... }
可能你會問事件處理失敗了怎么辦?甚至做持久化和投遞到MQ的s以后就異常了咋辦?可以轉去看之前的文章《分布式系統關注點——「共識」的兄弟「事務」》,以及文末的高可用系列文章。
最后,當你在使用異步的時候,還有一項工作要做,雖然是輔助性的,但是很重要。
就是需要引入一個全局唯一標識將整個異步的請求鏈路“串“起來,否則排查問題的時候夠你頭疼的,完全分不清楚哪是哪。如果條件允許,可以再引入一個日志聚合系統。比如ELK全家桶,讓你可以更高效的篩選日志信息。
好了,我們一起總結一下。
這次呢,Z哥先和你聊了下「異步」的意義,以及它是如何來提升性能的。
然后和你聊了一下「異步」的一些弊端和常見的運用方式。
最后以一個電商下單的例子梳理了一下做「異步」的思路。
希望對你有所啟發。
相關文章:
分布式系統關注點——360°全方位解讀「緩存」
分布式系統關注點——先寫DB還是「緩存」?
分布式系統關注點——緩存背后的“毀滅種子”
分布式系統關注點——「共識」的兄弟「事務」
如何在到處是“雷”的系統中「明哲保身」?這是第一招
想通關「限流」?只要這一篇
讓你的系統“堅挺不倒”的最后一個大招——「降級」
分布式系統關注點——99%的人都能看懂的「補償」以及最佳實踐
作者:Zachary
出處:https://www.cnblogs.com/Zacha...
如果你喜歡這篇文章,可以點一下文末的「贊」。
這樣可以給我一點反饋。: )
謝謝你的舉手之勞。
?關于作者:張帆(Zachary,個人微信號:Zachary-ZF)。堅持用心打磨每一篇高質量原創。歡迎掃描下方的二維碼~。
定期發表原創內容:架構設計丨分布式系統丨產品丨運營丨一些思考。如果你是初級程序員,想提升但不知道如何下手。又或者做程序員多年,陷入了一些瓶頸想拓寬一下視野。歡迎關注我的公眾號「跨界架構師」,回復「技術」,送你一份我長期收集和整理的思維導圖。
如果你是運營,面對不斷變化的市場束手無策。又或者想了解主流的運營策略,以豐富自己的“倉庫”。歡迎關注我的公眾號「跨界架構師」,回復「運營」,送你一份我長期收集和整理的思維導圖。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/74430.html
摘要:確定新的包命名規則為了盡可能避免包的誤植域名現象,將不會再允許使用相似的包命名不過會進一步鼓勵開發者使用自己的命名空間來發布包。本文是對其幾十年來技術之路的回顧與展望,也是一代技術人的青春回憶。 showImg(https://segmentfault.com/img/remote/1460000012846628); 前端每周清單專注前端領域內容,以對外文資料的搜集為主,幫助開發者了...
摘要:本文作者揭開的神秘面紗,用簡單易懂的代碼示例,介紹它的用法優劣點和適用場景。深入生成盒子作者主要介紹了和,兩者的區別和特點。應用可使用文件控制環境變量,這個工具可以幫你自動同步到文件。原文鏈接前端周報第期 精選 JavaScript Proxy 實戰指南 ES6 新引入了 Proxy 對象,它不僅能用在元編程上,還支持了 Vue3.0 新的響應式原理,但除此之外我們對 Proxy 的了...
摘要:終上所述這一切的一切,就是因為你技術不行但使龍城飛將在,不破樓蘭終不還但使雙手兩眼在,不入阿里終不還是的,只要你雙手還能敲代碼,雙眼還能看得見,對于程序員來說,阿里等這些大廠將會是你技術的必達點。 人在屋檐下,哪能不低頭 (記2018年底互聯網大寒潮) showImg(https://segmentfault.com/img/bVbmULW?w=240&h=240); 伴隨著深冬凌冽的...
摘要:終上所述這一切的一切,就是因為你技術不行但使龍城飛將在,不破樓蘭終不還但使雙手兩眼在,不入阿里終不還是的,只要你雙手還能敲代碼,雙眼還能看得見,對于程序員來說,阿里等這些大廠將會是你技術的必達點。 人在屋檐下,哪能不低頭 (記2018年底互聯網大寒潮) showImg(https://segmentfault.com/img/bVbmULW?w=240&h=240); 伴隨著深冬凌冽的...
閱讀 1876·2021-09-28 09:36
閱讀 2426·2021-09-08 09:35
閱讀 3067·2019-08-30 15:53
閱讀 1554·2019-08-30 14:08
閱讀 665·2019-08-29 18:40
閱讀 2843·2019-08-29 13:57
閱讀 2702·2019-08-29 13:55
閱讀 681·2019-08-26 13:45