您好,登錄后才能下訂單哦!
我曾不止一次聽說過這句話:
“十個女人無法在一個月內生出孩子”
我明白這句話的意思,用來形容我們的開發工作需要循序漸進,沒有辦法簡單的增加人員就能加快研發速度。
這句話也經常被用于反駁產品經理或者老板,試圖讓他們明白我們內心所表達的觀點,老實說我也說過這樣的話,當時還覺得挺有道理,現在想來可能有些一廂情愿了。
沒錯,在現實世界中,當然不可能在一個月內生出孩子,但我們畢竟是做產品寫代碼的,而不是真的要去生孩子,所以這種說法未免有點偷換概念。
我并不是較真,如果只是想讓產品經理明白我們所要表達的觀點,我們完全可以用其他的比喻,如實反饋存在的困難與問題即可。
言歸正傳,這句話與本文有什么關系呢?本文想要就“并發”所帶來的問題進行探討,相信看完后你會對此有一個感覺。
與我之前寫的幾篇文章一樣,并發一詞在本文中所表達的意思是:
“在分布式環境下,超過一個線程同時對同一個狀態進行訪問和變更所導致的一致性問題和可用性問題”
我無法給出一個百分比數據用以說明到底有多少后端應用程序在使用數據庫,但我想國內涉及到增刪查改之類的各種“管理系統”應該不在少數。
說到底,增刪改查是落地,而怎么落地則取決于業務的需要,也就是說,業務規則以及流程表達了我們的邏輯,但終究離不開柴米油鹽(增刪改查)。
那么什么是狀態?
它可以是文件,也可以是數據庫,可以是一個變量,也可以是緩存,它代表了計算的結果或者依賴(中間結果),由于它是可變的,并且可以被超過1個以上的程序同時訪問或者修改。
所以由此產生了兩個問題:
一致性要求是必須的,無法滿足一致性的情況要么是業務邏輯本身有問題,要么就是我們在編碼過程中出現了BUG,而如果是我們的編碼出現問題,很明顯就不符合驗收標準。
可用性要求則取決于運營的實際情況,隨著系統使用規模的上升,我們需要保證系統始終處于用的狀態下,因為業務方不希望服務被中斷或者超時。
我來描述一下完整的邏輯:
接下來,我會分別就狀態的一致性和可用性進行討論。
在上一節中,我們說狀態一致證明我們最終落地的數據是正確的,符合業務邏輯的。不一致是由于我們對業務的理解或者編碼出現了BUG,而BUG是我們必須要解決的。
這里有兩個層面的問題,我們分別來看一下。
如果在業務邏輯的層面上本身就存在悖論,存在漏洞,經驗豐富的開發人員會在進行系統設計或者編碼的時候就能察覺出來,道理很簡單,因為無法被實現,不管怎么樣都會存在BUG,而這種BUG是我們技術人員無法解決的,我們不能夠去猜業務方到底想要什么,因為這極有可能不符合他們的期望,最后仍然有可能會導致返工,造成成本的上升。
就像我們拿本文開頭的那個例子去懟產品經理一樣,很多時候是由于我們不善表達,沒有清楚表達出我們的疑惑,從而造成尷尬的場面。
溝通和管理是困難的,眾口難調。如何跟業務人員進行高效的溝通一直以來都是一個難題,但我們必須要清楚一點的是:
“只有我們充分洞悉和理解所要實現的業務領域,才能夠使我們更加輕松和增強信心,**因為只有這樣,我們才能夠選擇最適合的技術和模型幫助我們靈活的完成任務。”**
我的意思并不是讓咱們都成為該領域的專家,因為術業有專攻,分工配合才是重中之重,如果我們沒有跟業務需求方達成緊密的一致,就有可能造成浪費。
有關這一塊的內容,建議大家看一本書,叫做《領域驅動設計》,英文名是《Domain Driven Design》,簡稱DDD。
技術層面出現不一致的問題一般有兩種情況:
如果是第一種,這個沒什么好說的,返回業務層面與業務專家進行真誠層面的溝通,獲取真正的需求。
如果是第二種,那么我們首先應該找出不一致的原因,分析不一致的原因有助于我們加深理解和避免此類問題。
如果是由于小失誤造成的問題我們直接修復即可,這其實很常見,我們寫的代碼或多或少都要經過測試與修復。
如果是由于并發競爭造成的問題,那我們就需要用到相關的解決方案了,最常見的是使用數據庫事務來保證狀態落地的時候不會產生不一致,因為不一致會導致事務的回滾。
還有就是使用鎖來限制資源的訪問以及修改,這些都是很常見的技術,鑒于本文的重點是想說明產生這些問題的原因,所以不會這些解決方案進行詳細的講述,有興趣的朋友可以翻看一下我之前的文章或者查閱相關資料文檔。
可用性往往決定了系統架構的實現方式,可用性導致了我們最終將不得不使用分布式集群來應對大規模的訪問需求。
可以說,產生并發問題的直接原因就是可用性,因為它讓我們對狀態的管理變得十分復雜。
如果沒有可用性要求,最簡單的我們甚至可能都不需要數據庫,但現實中,對于一款成功的產品,我們不可能告訴我們的老板咱們無法實現對不對?
“量變導致質變,當可用性要求越來越高,系統規模越來越大,即便是再簡單的增刪改查都將不會再簡單”
如何在提升可用性的同時還能保證狀態的一致性?這真的不是技術能夠解決的。
先冷靜一下,我的意思是,由于網絡分區的存在,狀態的強一致會導致可用性降低,而可用性的提高又會造成分區狀態的不一致,從而降低了一致性。
這就是著名CAP定理[1],我們要么取CP,降低系統的可用性,要么取AP,降低狀態的一致性。
那么我們有沒有什么辦法來達到一個比較好的平衡呢?
答案是當然可以,但是,就如我一開始所說的,這并不是技術一個人就能夠解決的問題。
事實已經很明顯了,我們不可能取CP來降低系統的可用性,那樣就沒得玩了,所以我們只能夠選擇AP。
“在業務可以允許范圍內,設計一種最終一致的中間流程步驟,來提高系統的可用性,同時,又得以讓業務可以正常不受影響,處于預期的運轉。”
因此基于BASE理論[2][3]的最終一致更貼近于現實與業務,CAP定理只是證明和告訴我們,哪些事情行不通,但是BASE理論告訴我們,上有政策下有對策,使用柔性事務,反脆弱的系統才能讓我們更加的靈活。
所以我們要怎么做呢?我們要告訴產品經理,系統的可用性瓶頸必須要更改業務的流程才能得以實現。
我們要學會表達,告訴產品經理,這不是能不能做的問題,或者我能不能行的問題。
而是計算機科學目前的發展水平就是如此,也會存在極限,我們必須要學會相互適應,才能保證健康的發展。
盡量避免使用分布式事務,這是由衷的建議,事實證明分布式事務不僅不會提高性能,反而會拖垮高可用場景的系統。
如果你遇到了這個問題,那么說明狀態分區隔離以及事務場景有可能存在不合理的地方。
如果你確實有這種需求,那么盡量避免使用分布式事務,或者將分布式改為本地事務,也就是說不要將它們放到不同的地方進行事務處理。
如果這樣也不行的話,那就必須讓事務這個概念被明確包含進業務范圍,作為一個獨立的實體存在,不要讓它隱藏在技術細節中。
這樣的話,我們就能夠對這個定義明確的事務“句柄”或者“鉤子”進行補償或者回滾等最終一致冪等操作。
這也是我一直強調表達的,不要僅僅從技術層面來看待分布式事務,它可能是一個潛在的業務需求,存在生命周期的潛在概念。
就像我們對接支付寶一樣,根據訂單號來確保冪等,返回明確的信息給支付寶表明處理成功或失敗,實現最終一致的交易處理。
這個問題要從兩個方面來看,如果并行運行的程序沒有相互依賴,沒有狀態、資源競爭,那么水平拓展是非常容易的。
比如MapReduce,將大規模的數據分發并行處理,最后并歸計算結果,速度肯定快于串行執行。
相反,如果狀態特征在進行并歸的時候,前后依賴就產生了耦合,并行處理導致的切換加載開銷就變得沒有意義。
什么意思呢?
比如將一個個事件進行存儲,因為狀態本質上來講就是就是一系列事件施加計算后的快照而已(詳見https://www.cnblogs.com/xingxueliao/p/11561263.html#event_and_state)
所以如果我們想要計算某一個時間點上的快照,就需要從頭將事件播放到指定的位置上,事件對狀態的影響是嚴格按照先后順序來的。
因為事件導致的狀態結果是前后依賴的關系,因此并行運算并不會得到什么幫助,反而會因為切換導致無必要的狀態加載以及卸載開銷。
這種情況下,串行處理是唯一的方式,我們應該在這個上下文中,對輸入的事件流進行持久批量的計算,而且不用考慮并發所帶來的一致性問題。
因此,盲目的使用多線程或者多實例集群不僅不會讓可用性得以提升,反倒因為競爭的關系導致可用性被降低。
對數據特征進行分析,如何隔離狀態才是我們需要關注的重點,因為只有將沒有依賴關系的狀態隔離后我們才有可能提高整個系統的可用性。
這就完了?好像你沒有提到任何關于如何解決這些問題“具體方案”。
沒有具體的方案,因為這超出了本文的范疇,本文只是簡單的講述問題產生的原因,試圖以比較清晰的一個視角來發現和看待問題是為什么存在的。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。