溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

如何處理Java高并發(fā)

發(fā)布時(shí)間:2021-09-29 17:30:23 來(lái)源:億速云 閱讀:103 作者:iii 欄目:開(kāi)發(fā)技術(shù)

本篇內(nèi)容主要講解“如何處理Java高并發(fā) ”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“如何處理Java高并發(fā) ”吧!

目錄
  • 高性能開(kāi)發(fā)十大必須掌握的核心技術(shù)

    • I/O優(yōu)化:零拷貝技術(shù)

    • I/O優(yōu)化:多路復(fù)用技術(shù)

    • 線(xiàn)程池技術(shù)

    • 無(wú)鎖編程技術(shù)

    • 進(jìn)程間通信技術(shù)

  • Scale-out(橫向拓展)

    • 緩存

      • 異步

        • 高性能、高可用、高拓展 解決方案

          • 高性能的實(shí)踐方案

          • 高可用的實(shí)踐方案

          • 高擴(kuò)展的實(shí)踐方案

        • 總結(jié)

        高性能開(kāi)發(fā)十大必須掌握的核心技術(shù)

        我們循序漸進(jìn),從內(nèi)存、磁盤(pán)I/O、網(wǎng)絡(luò)I/O、CPU、緩存、架構(gòu)、算法等多層次遞進(jìn),串聯(lián)起高性能開(kāi)發(fā)十大必須掌握的核心技術(shù)。

        - I/O優(yōu)化:零拷貝技術(shù)
        - I/O優(yōu)化:多路復(fù)用技術(shù)
        - 線(xiàn)程池技術(shù)
        - 無(wú)鎖編程技術(shù)
        - 進(jìn)程間通信技術(shù)
        - RPC && 序列化技術(shù)
        - 數(shù)據(jù)庫(kù)索引技術(shù)
        - 緩存技術(shù) && 布隆過(guò)濾器
        - 全文搜索技術(shù)
        - 負(fù)載均衡技術(shù)

        I/O優(yōu)化:零拷貝技術(shù)

        從磁盤(pán)讀文件、再通過(guò)網(wǎng)絡(luò)發(fā)送數(shù)據(jù),數(shù)據(jù)從磁盤(pán)到網(wǎng)絡(luò),兜兜轉(zhuǎn)轉(zhuǎn)需要拷貝四次,其中CPU親自搬運(yùn)都需要兩次。

        最近在學(xué)習(xí)nginx的底層設(shè)計(jì),正好有看到這個(gè)。后面可以在nginx系列里面補(bǔ)上這個(gè)。

        如何處理Java高并發(fā)

        零拷貝技術(shù),解放CPU,文件數(shù)據(jù)直接從內(nèi)核發(fā)送出去,無(wú)需再拷貝到應(yīng)用程序緩沖區(qū),白白浪費(fèi)資源。

        如何處理Java高并發(fā)

        Linux API:

        ssize_t sendfile(
          int out_fd, 
          int in_fd, 
          off_t *offset, 
          size_t count
        );

        函數(shù)名字已經(jīng)把函數(shù)的功能解釋的很明顯了:發(fā)送文件。指定要發(fā)送的文件描述符和網(wǎng)絡(luò)套接字描述符,一個(gè)函數(shù)搞定!

        I/O優(yōu)化:多路復(fù)用技術(shù)

        每個(gè)線(xiàn)程都要阻塞在recv等待對(duì)方的請(qǐng)求,這來(lái)訪問(wèn)的人多了,線(xiàn)程開(kāi)的就多了,大量線(xiàn)程都在阻塞,系統(tǒng)運(yùn)轉(zhuǎn)速度也隨之下降。

        這個(gè)時(shí)候,你需要多路復(fù)用技術(shù),使用select模型,將所有等待(accept、recv)都放在主線(xiàn)程里,工作線(xiàn)程不需要再等待。

        如何處理Java高并發(fā)

        過(guò)了一段時(shí)間之后,網(wǎng)站訪問(wèn)的人越來(lái)越多了,就連select也開(kāi)始有點(diǎn)應(yīng)接不暇,老板繼續(xù)讓你優(yōu)化性能。

        這個(gè)時(shí)候,你需要升級(jí)多路復(fù)用模型為epoll。

        select有三弊,epoll有三優(yōu)。

        select底層采用數(shù)組來(lái)管理套接字描述符,同時(shí)管理的數(shù)量有上限,一般不超過(guò)幾千個(gè),epoll使用樹(shù)和鏈表來(lái)管理,同時(shí)管理數(shù)量可以很大。
        select不會(huì)告訴你到底哪個(gè)套接字來(lái)了消息,你需要一個(gè)個(gè)去詢(xún)問(wèn)。epoll直接告訴你誰(shuí)來(lái)了消息,不用輪詢(xún)。
        select進(jìn)行系統(tǒng)調(diào)用時(shí)還需要把套接字列表在用戶(hù)空間和內(nèi)核空間來(lái)回拷貝,循環(huán)中調(diào)用select時(shí)簡(jiǎn)直浪費(fèi)。epoll統(tǒng)一在內(nèi)核管理套接字描述符,無(wú)需來(lái)回拷貝。

        用上了epoll多路復(fù)用技術(shù),開(kāi)發(fā)了3.0版本,你的網(wǎng)站能同時(shí)處理很多用戶(hù)請(qǐng)求了。

        之前的方案中,工作線(xiàn)程總是用到才創(chuàng)建,用完就關(guān)閉,大量請(qǐng)求來(lái)的時(shí)候,線(xiàn)程不斷創(chuàng)建、關(guān)閉、創(chuàng)建、關(guān)閉,開(kāi)銷(xiāo)挺大的。這個(gè)時(shí)候,你需要:

        線(xiàn)程池技術(shù)

        我們可以在程序一開(kāi)始啟動(dòng)后就批量啟動(dòng)一波工作線(xiàn)程,而不是在有請(qǐng)求來(lái)的時(shí)候才去創(chuàng)建,使用一個(gè)公共的任務(wù)隊(duì)列,請(qǐng)求來(lái)臨時(shí),向隊(duì)列中投遞任務(wù),各個(gè)工作線(xiàn)程統(tǒng)一從隊(duì)列中不斷取出任務(wù)來(lái)處理,這就是線(xiàn)程池技術(shù)。

        如何處理Java高并發(fā)

        多線(xiàn)程技術(shù)的使用一定程度提升了服務(wù)器的并發(fā)能力,但同時(shí),多個(gè)線(xiàn)程之間為了數(shù)據(jù)同步,常常需要使用互斥體、信號(hào)、條件變量等手段來(lái)同步多個(gè)線(xiàn)程。這些重量級(jí)的同步手段往往會(huì)導(dǎo)致線(xiàn)程在用戶(hù)態(tài)/內(nèi)核態(tài)多次切換,系統(tǒng)調(diào)用,線(xiàn)程切換都是不小的開(kāi)銷(xiāo)。

        在線(xiàn)程池技術(shù)中,提到了一個(gè)公共的任務(wù)隊(duì)列,各個(gè)工作線(xiàn)程需要從中提取任務(wù)進(jìn)行處理,這里就涉及到多個(gè)工作線(xiàn)程對(duì)這個(gè)公共隊(duì)列的同步操作。

        有沒(méi)有一些輕量級(jí)的方案來(lái)實(shí)現(xiàn)多線(xiàn)程安全的訪問(wèn)數(shù)據(jù)呢?這個(gè)時(shí)候,你需要:

        無(wú)鎖編程技術(shù)

        多線(xiàn)程并發(fā)編程中,遇到公共數(shù)據(jù)時(shí)就需要進(jìn)行線(xiàn)程同步。而這里的同步又可以分為阻塞型同步和非阻塞型同步。

        阻塞型同步好理解,我們常用的互斥體、信號(hào)、條件變量等這些操作系統(tǒng)提供的機(jī)制都屬于阻塞型同步,其本質(zhì)都是要加“鎖”。

        如何處理Java高并發(fā)

        與之對(duì)應(yīng)的非阻塞型同步就是在無(wú)鎖的情況下實(shí)現(xiàn)同步,目前有三類(lèi)技術(shù)方案:

        Wait-freeLock-freeObstruction-free

        三類(lèi)技術(shù)方案都是通過(guò)一定的算法和技術(shù)手段來(lái)實(shí)現(xiàn)不用阻塞等待而實(shí)現(xiàn)同步,這其中又以Lock-free最為應(yīng)用廣泛。

        Lock-free能夠廣泛應(yīng)用得益于目前主流的CPU都提供了原子級(jí)別的read-modify-write原語(yǔ),這就是著名的CAS(Compare-And-Swap)操作。在Intel x86系列處理器上,就是cmpxchg系列指令。

        我們常常見(jiàn)到的無(wú)鎖隊(duì)列、無(wú)鎖鏈表、無(wú)鎖HashMap等數(shù)據(jù)結(jié)構(gòu),其無(wú)鎖的核心大都來(lái)源于此。在日常開(kāi)發(fā)中,恰當(dāng)?shù)倪\(yùn)用無(wú)鎖化編程技術(shù),可以有效地降低多線(xiàn)程阻塞和切換帶來(lái)的額外開(kāi)銷(xiāo),提升性能。


        服務(wù)器上線(xiàn)了一段時(shí)間,發(fā)現(xiàn)服務(wù)經(jīng)常崩潰異常,排查發(fā)現(xiàn)是工作線(xiàn)程代碼bug,一崩潰整個(gè)服務(wù)都不可用了。于是你決定把工作線(xiàn)程和主線(xiàn)程拆開(kāi)到不同的進(jìn)程中,工作線(xiàn)程崩潰不能影響整體的服務(wù)。這個(gè)時(shí)候出現(xiàn)了多進(jìn)程,你需要:

        進(jìn)程間通信技術(shù)

        提起進(jìn)程間通信,你能想到的是什么?

        管道
        命名管道
        socket
        消息隊(duì)列
        信號(hào)
        信號(hào)量
        共享內(nèi)存

        以上各種進(jìn)程間通信的方式詳細(xì)介紹和比較,推薦一篇文章再探進(jìn)程間通信,這里不再贅述。

        Scale-out(橫向拓展)

        采用分布式部署的方式把流量分開(kāi),讓每個(gè)服務(wù)器都承擔(dān)一部分并發(fā)和流量。這也是我最喜歡的一種方法。

        緩存

        使用緩存來(lái)提高系統(tǒng)的性能。

        為什么緩存可以大幅度提升系統(tǒng)的性能呢?

        那肯定是要更普通磁盤(pán)進(jìn)行對(duì)比的啊。我們來(lái)看看普通磁盤(pán)的速度:
        普通磁盤(pán)的尋道時(shí)間是 10ms 左右,而相比于磁盤(pán)尋道花費(fèi)的時(shí)間,CPU 執(zhí)行指令和內(nèi)存尋址的時(shí)間都在是 ns(納秒)級(jí)別,從千兆網(wǎng)卡上讀取數(shù)據(jù)的時(shí)間是在μs(微秒)級(jí)別。所以在整個(gè)計(jì)算機(jī)體系中,磁盤(pán)是最慢的一環(huán),甚至比其它的組件要慢幾個(gè)數(shù)量級(jí)。因此,我們通常使用以?xún)?nèi)存作為存儲(chǔ)介質(zhì)的緩存,以此提升性能。

        至于緩存為什么快,因?yàn)樗莾?nèi)置的啊,在內(nèi)存中。不過(guò)也有個(gè)缺點(diǎn),就是燒內(nèi)存。

        異步

        如何處理Java高并發(fā)

        這是業(yè)務(wù)層面的異步。

        內(nèi)核層面的異步,需要調(diào)用內(nèi)核指定的異步函數(shù)(aio族),不然,不論阻塞還是非阻塞都是同步。

        高性能、高可用、高拓展 解決方案

        以下實(shí)踐方案,有些我已經(jīng)試過(guò)了,有些還沒(méi)體驗(yàn)但是知道那么一回事兒,有些則不知道啥時(shí)候能實(shí)踐了。

        高性能的實(shí)踐方案

        1、集群部署,通過(guò)負(fù)載均衡減輕單機(jī)壓力。
        2、多級(jí)緩存,包括靜態(tài)數(shù)據(jù)使用CDN、本地緩存、分布式緩存等,以及對(duì)緩存場(chǎng)景中的熱點(diǎn)key、緩存穿透、緩存并發(fā)、數(shù)據(jù)一致性等問(wèn)題的處理。
        3、分庫(kù)分表和索引優(yōu)化,以及借助搜索引擎解決復(fù)雜查詢(xún)問(wèn)題。
        4、考慮NoSQL數(shù)據(jù)庫(kù)的使用,比如HBase、TiDB等,但是團(tuán)隊(duì)必須熟悉這些組件,且有較強(qiáng)的運(yùn)維能力。
        5、異步化,將次要流程通過(guò)多線(xiàn)程、MQ、甚至延時(shí)任務(wù)進(jìn)行異步處理。
        6、限流,需要先考慮業(yè)務(wù)是否允許限流(比如秒殺場(chǎng)景是允許的),包括前端限流、Nginx接入層的限流、服務(wù)端的限流。
        7、對(duì)流量進(jìn)行削峰填谷,通過(guò)MQ承接流量。
        8、并發(fā)處理,通過(guò)多線(xiàn)程將串行邏輯并行化。
        9、預(yù)計(jì)算,比如搶紅包場(chǎng)景,可以提前計(jì)算好紅包金額緩存起來(lái),發(fā)紅包時(shí)直接使用即可。
        10、緩存預(yù)熱,通過(guò)異步任務(wù)提前預(yù)熱數(shù)據(jù)到本地緩存或者分布式緩存中。
        11、減少I(mǎi)O次數(shù),比如數(shù)據(jù)庫(kù)和緩存的批量讀寫(xiě)、RPC的批量接口支持、或者通過(guò)冗余數(shù)據(jù)的方式干掉RPC調(diào)用。
        12、減少I(mǎi)O時(shí)的數(shù)據(jù)包大小,包括采用輕量級(jí)的通信協(xié)議、合適的數(shù)據(jù)結(jié)構(gòu)、去掉接口中的多余字段、減少緩存key的大小、壓縮緩存value等。
        13、程序邏輯優(yōu)化,比如將大概率阻斷執(zhí)行流程的判斷邏輯前置、For循環(huán)的計(jì)算邏輯優(yōu)化,或者采用更高效的算法。
        14、各種池化技術(shù)的使用和池大小的設(shè)置,包括HTTP請(qǐng)求池、線(xiàn)程池(考慮CPU密集型還是IO密集型設(shè)置核心參數(shù))、數(shù)據(jù)庫(kù)和Redis連接池等。
        15、JVM優(yōu)化,包括新生代和老年代的大小、GC算法的選擇等,盡可能減少GC頻率和耗時(shí)。
        16、鎖選擇,讀多寫(xiě)少的場(chǎng)景用樂(lè)觀鎖,或者考慮通過(guò)分段鎖的方式減少鎖沖突。

        上述方案無(wú)外乎從計(jì)算和 IO 兩個(gè)維度考慮所有可能的優(yōu)化點(diǎn),需要有配套的監(jiān)控系統(tǒng)實(shí)時(shí)了解當(dāng)前的性能表現(xiàn),并支撐你進(jìn)行性能瓶頸分析,然后再遵循二八原則,抓主要矛盾進(jìn)行優(yōu)化。

        高可用的實(shí)踐方案

        1、對(duì)等節(jié)點(diǎn)的故障轉(zhuǎn)移,Nginx和服務(wù)治理框架均支持一個(gè)節(jié)點(diǎn)失敗后訪問(wèn)另一個(gè)節(jié)點(diǎn)。
        2、非對(duì)等節(jié)點(diǎn)的故障轉(zhuǎn)移,通過(guò)心跳檢測(cè)并實(shí)施主備切換(比如redis的哨兵模式或者集群模式、MySQL的主從切換等)。
        3、接口層面的超時(shí)設(shè)置、重試策略和冪等設(shè)計(jì)。
        4、降級(jí)處理:保證核心服務(wù),犧牲非核心服務(wù),必要時(shí)進(jìn)行熔斷;或者核心鏈路出問(wèn)題時(shí),有備選鏈路。
        5、限流處理:對(duì)超過(guò)系統(tǒng)處理能力的請(qǐng)求直接拒絕或者返回錯(cuò)誤碼。
        6、MQ場(chǎng)景的消息可靠性保證,包括producer端的重試機(jī)制、broker側(cè)的持久化、consumer端的ack機(jī)制等。
        7、灰度發(fā)布,能支持按機(jī)器維度進(jìn)行小流量部署,觀察系統(tǒng)日志和業(yè)務(wù)指標(biāo),等運(yùn)行平穩(wěn)后再推全量。
        8、監(jiān)控報(bào)警:全方位的監(jiān)控體系,包括最基礎(chǔ)的CPU、內(nèi)存、磁盤(pán)、網(wǎng)絡(luò)的監(jiān)控,以及Web服務(wù)器、JVM、數(shù)據(jù)庫(kù)、各類(lèi)中間件的監(jiān)控和業(yè)務(wù)指標(biāo)的監(jiān)控。
        9、災(zāi)備演練:類(lèi)似當(dāng)前的“混沌工程”,對(duì)系統(tǒng)進(jìn)行一些破壞性手段,觀察局部故障是否會(huì)引起可用性問(wèn)題。

        高可用的方案主要從冗余、取舍、系統(tǒng)運(yùn)維3個(gè)方向考慮,同時(shí)需要有配套的值班機(jī)制和故障處理流程,當(dāng)出現(xiàn)線(xiàn)上問(wèn)題時(shí),可及時(shí)跟進(jìn)處理。

        高擴(kuò)展的實(shí)踐方案

        1、合理的分層架構(gòu):比如上面談到的互聯(lián)網(wǎng)最常見(jiàn)的分層架構(gòu),另外還能進(jìn)一步按照數(shù)據(jù)訪問(wèn)層、業(yè)務(wù)邏輯層對(duì)微服務(wù)做更細(xì)粒度的分層
        (但是需要評(píng)估性能,會(huì)存在網(wǎng)絡(luò)多一跳的情況)。
        2、存儲(chǔ)層的拆分:按照業(yè)務(wù)維度做垂直拆分、按照數(shù)據(jù)特征維度進(jìn)一步做水平拆分(分庫(kù)分表)。
        3、業(yè)務(wù)層的拆分:最常見(jiàn)的是按照業(yè)務(wù)維度拆(比如電商場(chǎng)景的商品服務(wù)、訂單服務(wù)等),
        也可以按照核心接口和非核心接口拆,還可以按照請(qǐng)求源拆(比如To C和To B,APP和H5)。

        總結(jié)

        1、最簡(jiǎn)單的系統(tǒng)設(shè)計(jì)滿(mǎn)足業(yè)務(wù)需求和流量現(xiàn)狀,選擇最熟悉的技術(shù)體系。

        2、隨著流量的增加和業(yè)務(wù)的變化,修正架構(gòu)中存在問(wèn)題的點(diǎn),如單點(diǎn)問(wèn)題,橫向擴(kuò)展問(wèn)題,性能無(wú)法滿(mǎn)足需求的組件。
        在這個(gè)過(guò)程中,選擇社區(qū)成熟的、團(tuán)隊(duì)熟悉的組件幫助我們解決問(wèn)題,在社區(qū)沒(méi)有合適解決方案的前提下才會(huì)自己造輪子。

        3、當(dāng)對(duì)架構(gòu)的小修小補(bǔ)無(wú)法滿(mǎn)足需求時(shí),考慮重構(gòu)、重寫(xiě)等大的調(diào)整方式以解決現(xiàn)有的問(wèn)題。

        到此,相信大家對(duì)“如何處理Java高并發(fā) ”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢(xún),關(guān)注我們,繼續(xù)學(xué)習(xí)!

        向AI問(wèn)一下細(xì)節(jié)

        免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

        AI