成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Java并發(fā)編程吐血1個(gè)月總結(jié)最全面的100道面試題

開發(fā) 架構(gòu)
這篇文章,給大家聊聊一個(gè)百萬級并發(fā)的中間件系統(tǒng)的內(nèi)核代碼里的鎖性能優(yōu)化。

目錄

  • 一、大部分人對Java并發(fā)仍停留在理論階段
  • 二、中間件系統(tǒng)的內(nèi)核機(jī)制:雙緩沖機(jī)制
  • 三、百萬并發(fā)的技術(shù)挑戰(zhàn)
  • 四、內(nèi)存數(shù)據(jù)寫入的鎖機(jī)制以及串行化問題
  • 五、片機(jī)制 + 分段加鎖機(jī)制
  • 六、緩沖區(qū)寫滿時(shí)的雙緩沖交換
  • 七、且慢!刷寫磁盤不是會(huì)導(dǎo)致鎖持有時(shí)間過長嗎?
  • 八、內(nèi)存 + 磁盤并行寫機(jī)制
  • 九、為什么必須要用雙緩沖機(jī)制?
  • 十、總結(jié)

這篇文章,給大家聊聊一個(gè)百萬級并發(fā)的中間件系統(tǒng)的內(nèi)核代碼里的鎖性能優(yōu)化。

很多同學(xué)都對Java并發(fā)編程很感興趣,學(xué)習(xí)了很多相關(guān)的技術(shù)和知識。比如volatile、Atomic、synchronized底層、讀寫鎖、AQS、并發(fā)包下的集合類、線程池,等等。

一、對Java并發(fā)仍停留在理論階段

很多同學(xué)對Java并發(fā)編程的知識,可能看了很多的書,也通過不少視頻課程進(jìn)行了學(xué)習(xí)。

但是,大部分人可能還是停留在理論的底層,主要是了解理論,基本對并發(fā)相關(guān)的技術(shù)很少實(shí)踐和使用,更很少做過復(fù)雜的中間件系統(tǒng)。

實(shí)際上,真正把這些技術(shù)落地到中間件系統(tǒng)開發(fā)中去實(shí)踐的時(shí)候,是會(huì)遇到大量的問題,需要對并發(fā)相關(guān)技術(shù)的底層有深入的理解和掌握。

然后,結(jié)合自己實(shí)際的業(yè)務(wù)場景來進(jìn)行對應(yīng)的技術(shù)優(yōu)化、機(jī)制優(yōu)化,才能實(shí)現(xiàn)最好的效果。

因此,本文將從筆者曾經(jīng)帶過的一個(gè)高并發(fā)中間件項(xiàng)目的內(nèi)核機(jī)制出發(fā),來看看一個(gè)實(shí)際的場景中遇到的并發(fā)相關(guān)的問題。

同時(shí),我們也將一步步通過對應(yīng)的偽代碼演進(jìn),來分析其背后涉及到的并發(fā)的性能優(yōu)化思想和實(shí)踐,最后來看看優(yōu)化之后的效果。

二、中間件系統(tǒng)的內(nèi)核機(jī)制:雙緩沖機(jī)制

這個(gè)中間件項(xiàng)目整體就不做闡述了,因?yàn)樯婕昂诵捻?xiàng)目問題。我們僅僅拿其中涉及到的一個(gè)內(nèi)核機(jī)制以及對應(yīng)的場景來給大家做一下說明。

其實(shí)這個(gè)例子是大量的開源中間件系統(tǒng)、大數(shù)據(jù)系統(tǒng)中都有涉及到的一個(gè)場景,就是:核心數(shù)據(jù)寫磁盤文件。

比如,大數(shù)據(jù)領(lǐng)域里的hadoop、hbase、elasitcsearch,Java中間件領(lǐng)域里的redis、mq,這些都會(huì)涉及到核心數(shù)據(jù)寫磁盤文件的問題。

而很多大型互聯(lián)網(wǎng)公司自研的中年間系統(tǒng),同樣也會(huì)有這個(gè)場景。只不過不同的中間件系統(tǒng),他的作用和目標(biāo)是不一樣的,所以在核心數(shù)據(jù)寫磁盤文件的機(jī)制設(shè)計(jì)上,是有一些區(qū)別的。

那么我們公司自研的中間件項(xiàng)目,簡單來說,需要實(shí)現(xiàn)的一個(gè)效果是:開辟兩塊內(nèi)存空間,也就是經(jīng)典的內(nèi)存雙緩沖機(jī)制

然后核心數(shù)據(jù)進(jìn)來全部寫第一塊緩沖區(qū),寫滿了之后,由一個(gè)線程進(jìn)行那塊緩沖區(qū)的數(shù)據(jù)批量刷到磁盤文件的工作,其他線程同時(shí)可以繼續(xù)寫另外一塊緩沖區(qū)。

我們想要實(shí)現(xiàn)的就是這樣的一個(gè)效果。這樣的話,一塊緩沖區(qū)刷磁盤的同時(shí),另外一塊緩沖區(qū)可以接受其他線程的寫入,兩不耽誤。核心數(shù)據(jù)寫入是不會(huì)斷的,可以持續(xù)不斷的寫入這個(gè)中間件系統(tǒng)中。

我們來看看下面的那張圖,也來了解一下這個(gè)場景。

如上圖,首先是很多線程需要寫緩沖區(qū)1,然后是緩沖區(qū)1寫滿之后,就會(huì)由寫滿的那個(gè)線程把緩沖區(qū)1的數(shù)據(jù)刷入磁盤文件,其他線程繼續(xù)寫緩沖區(qū)2。

這樣,數(shù)據(jù)批量刷磁盤和持續(xù)寫內(nèi)存緩沖,兩個(gè)事兒就不會(huì)耽誤了,這是中間件系統(tǒng)設(shè)計(jì)中極為常用的一個(gè)機(jī)制,大家看下面的圖。

三、百萬并發(fā)的技術(shù)挑戰(zhàn)

?先給大家說一下這個(gè)中間件系統(tǒng)的背景:這是一個(gè)服務(wù)某個(gè)特殊場景下的中間件系統(tǒng),整體是集群部署。

然后每個(gè)實(shí)例部署的都是高配置機(jī)器,定位是單機(jī)承載并發(fā)達(dá)到萬級甚至十萬級,整體集群足以支撐百萬級并發(fā),因此對單機(jī)的寫入性能和吞吐要求極為高。

在超高并發(fā)的要求之下,上圖中的那個(gè)內(nèi)核機(jī)制的設(shè)計(jì)就顯得尤為重要了。弄的不好,就容易導(dǎo)致寫入并發(fā)性能過差,達(dá)不到上述的要求。

此外在這里多提一句,類似的這種機(jī)制在很多其他的系統(tǒng)里都有涉及。比如之前一篇文章:《降級機(jī)制設(shè)計(jì)不當(dāng),線上系統(tǒng)瞬間崩潰...》,那里面講的一個(gè)系統(tǒng)也有類似機(jī)制。

只不過不同的是,那篇文章是用這個(gè)機(jī)制來做MQ集群整體故障時(shí)的容災(zāi)降級機(jī)制,跟本文的高并發(fā)中間件系統(tǒng)還有點(diǎn)不太一樣,所以在設(shè)計(jì)上考慮的一些細(xì)節(jié)也是不同的。

而且,之前那篇文章的主題是講這種內(nèi)存雙緩沖機(jī)制的一個(gè)線上問題:瞬時(shí)超高并發(fā)下的系統(tǒng)卡死問題。?

四、內(nèi)存數(shù)據(jù)寫入的鎖機(jī)制以及串行化問題

首先我們先考慮第一個(gè)問題,你多個(gè)線程會(huì)并發(fā)寫同一塊內(nèi)存緩沖,這個(gè)肯定有問題啊!

因?yàn)閮?nèi)存共享數(shù)據(jù)并發(fā)寫入的時(shí)候,必須是要加鎖的,否則必然會(huì)有并發(fā)安全問題,導(dǎo)致內(nèi)存數(shù)據(jù)錯(cuò)亂。

所以在這里,我們寫了下面的偽代碼,先考慮一下線程如何寫入內(nèi)存緩沖。

好了,這行代碼弄好之后,對應(yīng)著下面的這幅圖,大家看一下。

看到這里,就遇到了Java并發(fā)的第一個(gè)性能問題了,你要知道高并發(fā)場景下,大量線程會(huì)并發(fā)寫內(nèi)存的,你要是直接這樣加一個(gè)鎖,必然會(huì)導(dǎo)致所有線程都是串行化。

即一個(gè)線程加鎖,寫數(shù)據(jù),然后釋放鎖。接著下一個(gè)線程干同樣的事情。這種串行化必然導(dǎo)致系統(tǒng)整體的并發(fā)性能和吞吐量會(huì)大幅度降低的。

五、內(nèi)存緩沖分片機(jī)制+分段枷鎖機(jī)制

因此在這里必須要對內(nèi)存雙緩沖機(jī)制引入分段加鎖機(jī)制,也就是將內(nèi)存緩沖切分為多個(gè)分片,每個(gè)內(nèi)存緩沖分片就對應(yīng)一個(gè)鎖。

這樣的話,你完全可以根據(jù)自己的系統(tǒng)壓測結(jié)果,調(diào)整內(nèi)存分片數(shù)量,提升鎖的數(shù)量,進(jìn)而允許大量線程高并發(fā)寫入內(nèi)存。

我們看下面的偽代碼,對這塊就實(shí)現(xiàn)了內(nèi)存緩沖分片機(jī)制:

好!我們再來看看,目前為止的圖是什么樣子的:

這里因?yàn)槊總€(gè)線程僅僅就是加鎖,寫內(nèi)存,然后釋放鎖。

所以,每個(gè)線程持有鎖的時(shí)間是很短很短的,單個(gè)內(nèi)存分片的并發(fā)寫入經(jīng)過壓測,達(dá)到每秒幾百甚至上千是沒問題的,因此線上系統(tǒng)我們是單機(jī)開辟幾十個(gè)到上百個(gè)內(nèi)存緩沖分片的。

經(jīng)過壓測,這足以支撐每秒數(shù)萬的并發(fā)寫入,如果將機(jī)器資源使用的極限,每秒十萬并發(fā)也是可以支持的。

六、緩沖區(qū)寫滿時(shí)的雙緩沖交換

那么當(dāng)一塊緩沖區(qū)寫滿的時(shí)候,是不是就必須要交換兩塊緩沖區(qū)?接著需要有一個(gè)線程來將寫滿的緩沖區(qū)數(shù)據(jù)刷寫到磁盤文件中?

此時(shí)的偽代碼,大家考慮一下,是不是如下所示:

同樣,我們通過下面的圖來看看這個(gè)機(jī)制的實(shí)現(xiàn):

七、且慢!刷寫磁盤不是會(huì)導(dǎo)致鎖持有時(shí)間過長嗎?

且慢,各位同學(xué),如果按照上面的偽代碼思路,一定會(huì)有一個(gè)問題:要是一個(gè)線程,他獲取了鎖,開始寫內(nèi)存數(shù)據(jù)。

然后,發(fā)現(xiàn)內(nèi)存滿了,接著直接在持有鎖的過程中,還去執(zhí)行數(shù)據(jù)刷磁盤的操作,這樣是有問題的。

要知道,數(shù)據(jù)刷磁盤是很慢的,根據(jù)數(shù)據(jù)的多少,搞不好要幾十毫秒,甚至幾百毫秒。

這樣的話,豈不是一個(gè)線程會(huì)持有鎖長達(dá)幾十毫秒,甚至幾百毫秒?

這當(dāng)然不行了,后面的線程此時(shí)都在等待獲取鎖然后寫緩沖區(qū)2,你怎么能一直占有鎖呢?

一旦你按照這個(gè)思路來寫代碼,必然導(dǎo)致高并發(fā)場景下,一個(gè)線程持有鎖上百毫秒。刷數(shù)據(jù)到磁盤的時(shí)候,后續(xù)上百個(gè)工作線程全部卡在等待鎖的那個(gè)環(huán)節(jié),啥都干不了,嚴(yán)重的情況下,甚至又會(huì)導(dǎo)致系統(tǒng)整體呈現(xiàn)卡死的狀態(tài)。

八、內(nèi)存 + 磁盤并行寫機(jī)制

所以此時(shí)正確的并發(fā)優(yōu)化代碼,應(yīng)該是發(fā)現(xiàn)內(nèi)存緩沖區(qū)1滿了,然后就交換兩個(gè)緩沖區(qū)。

接著直接就釋放鎖,釋放鎖了之后再由這個(gè)線程將數(shù)據(jù)刷入磁盤中,刷磁盤的過程是不會(huì)占用鎖的,然后后續(xù)的線程都可以繼續(xù)獲取鎖,快速寫入內(nèi)存,接著釋放鎖。

大家先看看下面的偽代碼的優(yōu)化:

按照上面的偽代碼的優(yōu)化,此時(shí)磁盤的刷寫和內(nèi)存的寫入,完全可以并行同時(shí)進(jìn)行。

因?yàn)檫@里核心的要點(diǎn)就在于大幅度降低了鎖占用的時(shí)間,這是java并發(fā)鎖優(yōu)化的一個(gè)非常核心的思路。

大家看下面的圖,一起來感受一下:

九、為什么必須要用雙緩沖機(jī)制?

其實(shí)看到這里,大家可能或多或少都體會(huì)到了一些雙緩沖機(jī)制的設(shè)計(jì)思想了,如果只用單塊內(nèi)存緩沖的話,那么從里面讀數(shù)據(jù)刷入磁盤的過程,也需要占用鎖,而此時(shí)想要獲取鎖寫入內(nèi)存緩沖的線程是獲取不到鎖的。

所以假只用單塊緩沖,必然導(dǎo)致讀內(nèi)存數(shù)據(jù),刷入磁盤的過程,長時(shí)間占用鎖。進(jìn)而導(dǎo)致大量線程卡在鎖的獲取上,無法獲取到鎖,然后無法將數(shù)據(jù)寫入內(nèi)存。這就是必須要在這里使用雙緩沖機(jī)制的核心原因。

十、總結(jié)

最后做一下總結(jié),本文從筆者團(tuán)隊(duì)自研的百萬并發(fā)量級中間件系統(tǒng)的內(nèi)核機(jī)制出發(fā),給大家展示了Java并發(fā)中加鎖的時(shí)候:

  • 如何利用雙緩沖機(jī)制
  • 內(nèi)存緩沖分片機(jī)制
  • 分段加鎖機(jī)制
  • 磁盤 + 內(nèi)存并行寫入機(jī)制
  • 高并發(fā)場景下大幅度優(yōu)化多線程對鎖的串行化爭用問題
  • 長時(shí)間占用鎖的問題

其實(shí)在很多開源的優(yōu)秀中間件系統(tǒng)中,都有很多類似的Java并發(fā)優(yōu)化的機(jī)制,主要就是應(yīng)對高并發(fā)的場景下大幅度的提升系統(tǒng)的并發(fā)性能以及吞吐量。大家如果感興趣,也可以去了解閱讀一下相關(guān)的底層源碼。

責(zé)任編輯:姜華 來源: 今日頭條
相關(guān)推薦

2020-08-06 10:45:30

JavaSpring面試題

2024-04-15 08:34:43

2024-04-28 08:23:18

2020-04-07 14:40:19

Java并發(fā)編程多線程

2024-06-04 14:52:28

2016-01-28 14:41:06

CC++編碼

2010-11-26 10:53:29

戴爾

2024-02-26 15:35:44

2018-03-06 15:30:47

Java面試題

2018-06-28 09:34:26

架構(gòu)師Python面試題

2021-02-23 12:43:39

Redis面試題緩存

2024-04-01 08:34:23

2019-04-12 16:10:32

Python面試題編程

2024-01-01 15:30:59

JavaScriptWeb 應(yīng)用程序開發(fā)

2009-02-21 19:17:54

CCIE Lab面試思科

2018-06-25 14:52:22

編程語言Python面試題

2017-03-29 09:08:25

Spring筆記

2024-04-09 08:32:58

Java面試題線程

2023-02-04 18:24:10

SeataJava業(yè)務(wù)

2021-12-01 09:25:58

SQL數(shù)據(jù)庫數(shù)據(jù)庫基礎(chǔ)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 免费在线精品视频 | 亚洲成人精品在线 | 精品久久久久久久久久久 | 日韩黄| 亚洲视频第一页 | 三级在线免费 | 99久久精品免费看国产免费软件 | 黄色毛片免费看 | 精品国产一区二区三区久久 | 懂色tv | 日韩在线观看视频一区 | 欧美国产精品 | 日韩中文字幕视频 | 国产精品视频免费观看 | 精品欧美一区二区三区久久久 | 国产成人福利 | 久久精品免费 | 污污的网站在线观看 | 男女羞羞视频网站 | 色片在线观看 | 国产日韩精品视频 | 免费成人在线网站 | 国产在线播放一区二区三区 | 日产精品久久久一区二区福利 | 欧美在线一区二区三区 | 97日日碰人人模人人澡分享吧 | 欧美日韩高清在线一区 | 午夜视频在线 | 日韩成人av在线 | 久久黄色网 | 中文字幕一级毛片 | 亚洲精品黄色 | 孕妇一级毛片 | 日韩精品在线网站 | 毛片免费看的 | 伊人二区 | 欧美激情 一区 | 欧美精品一区二区三区在线播放 | 成人一区二区三区视频 | 欧美视频精品 | 久久国产视频一区 |