1. 程式人生 > >大白話聊聊Java併發面試問題之微服務註冊中心的讀寫鎖優化【石杉的架構筆記】

大白話聊聊Java併發面試問題之微服務註冊中心的讀寫鎖優化【石杉的架構筆記】

歡迎關注個人公眾號:石杉的架構筆記(ID:shishan100)

週一至週五早8點半!精品技術文章準時送上!


一、讀寫鎖的介紹

上一篇文章大白話聊聊Java併發面試問題之公平鎖與非公平鎖是啥?,聊了一下java併發包的公平鎖和非公平鎖。

這篇文章來聊一下讀寫鎖。所謂的讀寫鎖,就是將一個鎖拆分為讀鎖和寫鎖兩個鎖,然後你加鎖的時候,可以加寫鎖,也可以加讀鎖。如下面程式碼所示:


如果有一個執行緒加了寫鎖,那麼其他執行緒就不能加寫鎖了,同一時間只能允許一個執行緒加寫鎖。因為加了寫鎖就意味著有人要寫一個共享資料,那同時就不能讓其他人來寫這個資料了。

同時如果有執行緒加了寫鎖,其他執行緒就不能加讀鎖了,因為既然都有人在寫資料了,你其他人當然不能來讀資料了!

如果有一個執行緒加了讀鎖,別的執行緒是可以隨意同時加讀鎖的,因為只是有執行緒在讀資料而已,此時別的執行緒也是可以來讀資料的!

同理,如果一個執行緒加了讀鎖,此時其他執行緒是不可以加寫鎖的,因為既然有人在讀資料,那就不能讓你隨意來寫資料了!

好了!這個就是初步介紹一下讀寫鎖的使用方法,相信很多同學應該之前都知道了,因為這個是java開發中非常基礎的一塊知識。


二、微服務註冊中心的讀寫鎖優化

現在進入主題,我們主要聊一下微服務註冊中心裡面的讀寫鎖優化。

為什麼要聊一下這個問題呢?

因為如果你出去面試,很可能被問到讀寫鎖的問題,此時你可以自然而然的帶出來,你之前瞭解過Spring Cloud微服務技術架構,同時對裡面的微服務註冊中心的登錄檔讀寫鎖優化有一些自己的感悟和看法。

這樣的話,相比於你簡單的給面試官聊聊讀寫鎖的基本概念和使用方法,要增色不少!

首先,大家需要了解一點微服務的整體架構知識,可以參考之前寫過的一篇文章:拜託!面試請不要再問我Spring Cloud底層原理!

同時還需要了解一下Spring Cloud Eureka(即微服務註冊中心)的核心原理。這個可以參考之前寫過的一篇文章微服務註冊中心如何承載大型系統的千萬級訪問?的。

好,瞭解了這些前置知識之後,我們正式開始。

先來看看下面的圖,現在我們知道一個微服務註冊中心(可以是Eureka或者Consul或者你自己寫的一個微服務註冊中心),他肯定會在記憶體中有一個服務登錄檔的概念。

這個服務登錄檔中就是存放了各個微服務註冊時傳送過來的自己的地址資訊,裡面儲存了每個服務有多少個服務例項,每個服務例項部署在哪臺機器上監聽哪個埠號,主要是這樣的一些資訊。


OK,那現在問題來了,這個服務登錄檔的資料,其實是有人讀也有人寫的。

舉個例子,比如有的服務啟動的時候會來註冊,此時就會修改服務登錄檔的資料,這個就是寫的過程。

接著,別的服務也會來讀這個服務登錄檔的資料,因為每個服務都需要感知到其他服務在哪些機器上部署。

所以,這個記憶體裡的服務登錄檔資料,天然就是有讀寫併發問題的!可能會有多個執行緒來寫,也可能會有多個執行緒來讀!

如果你對同一份記憶體中的登錄檔資料不加任何保護措施,那麼可能會有多執行緒併發修改共享資料的問題,可能導致資料錯亂,對吧?

上述過程,大家看看下面的圖,就明白了。


此時,如果對服務登錄檔的服務註冊和讀取服務登錄檔的方法,都加一個synchronized關鍵字,是不是就可以了呢?

或許你會想,加上synchronized,直接讓所有執行緒對服務登錄檔的讀寫操作,全部序列化。那不就可以保證記憶體中的服務登錄檔資料安全了嗎?

下面是一段虛擬碼,大家來感受一下:


在上面的程式碼中直接給寫(服務註冊)讀(讀取服務登錄檔)兩個方法,都暴力的加上了synchronized關鍵字,確實是可以保證服務登錄檔的資料不錯亂,但是這樣肯定是不太合適的。

因為這麼搞的話,相當於是所有的執行緒讀寫服務登錄檔資料,全部序列化了。

大家思考一下,我們想要的效果是什麼?其實不就是在有人往服務登錄檔裡寫資料的時候,就不讓其他人寫了,同時也不讓其他人讀!

然後,有人在讀服務登錄檔的資料的時候,其他人都可以隨便同時讀,但是此時不允許別人寫服務登錄檔資料了!

對吧,我們想要的,其實不就是這個效果嗎?

想清楚了這點,我們就不應該暴力的加一個synchronized,讓所有讀寫執行緒全部序列化,那樣會導致併發性非常的低。

大家看看下面的圖,我們想要的第一個效果:一旦有人在寫服務登錄檔資料,我們加個寫鎖,此時別人不能寫,也不能讀。


那麼如果有人在讀資料呢?此時就可以讓別人都可以讀,但是不允許任何人寫。大家看下面的圖。


關鍵點來了,這樣做有什麼好處呢?其實大部分時候都是讀操作,所以使用讀鎖可以讓大量的執行緒同時來讀資料,不需要阻塞不需要排隊,保證高併發讀的效能是比較高的。

然後少量的時候是有服務上線要註冊資料,寫資料的場景是比較少的,此時寫資料的時候,只能一個一個的加寫鎖然後寫資料,同時寫資料的時候就不允許別人來讀資料了。

所以讀寫鎖是非常適合這種讀多寫少的場景的。

另外,我們能不能儘量在寫資料的期間還保證可以繼續讀資料呢?大量加讀鎖的時候,會阻塞人家寫資料加寫鎖過長時間,這種情況能否避免呢?

可以的,採用多級快取的機制,具體可以參加之前的一篇文章:微服務註冊中心如何承載大型系統的千萬級訪問?、。裡面分析了Spring Cloud Eureka微服務註冊中心裡的多級快取機制。

最後看下上面那段虛擬碼如果用讀寫鎖來優化是怎麼樣的?





併發系列文章,正在更新中,歡迎關注:
大白話聊聊Java併發面試問題之volatile到底是什麼?
大白話聊聊Java併發面試問題之Java 8如何優化CAS效能?
大白話聊聊Java併發面試問題之談談你對AQS的理解?
《大白話聊聊Java併發面試問題之公平鎖與非公平鎖是啥?》
《大白話聊聊Java併發面試問題之微服務註冊中心的讀寫鎖優化?》 敬請期待


END


如有收穫,請幫忙轉發,您的鼓勵是作者最大的動力,謝謝!


一大波微服務、分散式、高併發、高可用的原創系列文章正在路上

歡迎掃描下方二維碼,持續關注:


石杉的架構筆記(id:shishan100)

十餘年BAT架構經驗傾囊相授


推薦閱讀:

1、拜託!面試請不要再問我Spring Cloud底層原理

2、【雙11狂歡的背後】微服務註冊中心如何承載大型系統的千萬級訪問?

3、【效能優化之道】每秒上萬併發下的Spring Cloud引數優化實戰

4、微服務架構如何保障雙11狂歡下的99.99%高可用

5、兄弟,用大白話告訴你小白都能聽懂的Hadoop架構原理

6、大規模叢集下Hadoop NameNode如何承載每秒上千次的高併發訪問

7、【效能優化的祕密】Hadoop如何將TB級大檔案的上傳效能優化上百倍

8、拜託,面試請不要再問我TCC分散式事務的實現原理坑爹呀!

9、【坑爹呀!】最終一致性分散式事務如何保障實際生產中99.99%高可用?

10、拜託,面試請不要再問我Redis分散式鎖的實現原理!

11、【眼前一亮!】看Hadoop底層演算法如何優雅的將大規模叢集效能提升10倍以上?

12、億級流量系統架構之如何支撐百億級資料的儲存與計算

13、億級流量系統架構之如何設計高容錯分散式計算系統

14、億級流量系統架構之如何設計承載百億流量的高效能架構

15、億級流量系統架構之如何設計每秒十萬查詢的高併發架構

16、億級流量系統架構之如何設計全鏈路99.99%高可用架構

17、七張圖徹底講清楚ZooKeeper分散式鎖的實現原理

18、大白話聊聊Java併發面試問題之volatile到底是什麼?

19、大白話聊聊Java併發面試問題之Java 8如何優化CAS效能?

20、大白話聊聊Java併發面試問題之談談你對AQS的理解?

21、大白話聊聊Java併發面試問題之公平鎖與非公平鎖是啥?