国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
淺談長(zhǎng)連接?;顧C(jī)制

在日常工作中,我們經(jīng)常會(huì)接觸到長(zhǎng)連接這個(gè)概念,例如一些RPC框架(如Dubbo)、網(wǎng)絡(luò)通信框架(Netty)等,都會(huì)涉及到長(zhǎng)連接的概念,我們來(lái)探究一下長(zhǎng)連接是如何?;畹?。

長(zhǎng)連接&短連接

首先我們要知道,TCP本身是沒(méi)有長(zhǎng)連接和短連接的區(qū)分的,長(zhǎng)短與否完全取決于我們?cè)趺从盟?/p>

長(zhǎng)連接和短連接的簡(jiǎn)單區(qū)分如下:

  • 短連接:每次通信時(shí),創(chuàng)建新的socket;一次通信結(jié)束,調(diào)用 socket.close()關(guān)掉socket。這就是一般意義上的短連接,短連接的好處是管理起來(lái)比較簡(jiǎn)單,存在的連接都是可用的連接,不需要額外的控制手段。

  • 長(zhǎng)連接:每次通信完畢后,不會(huì)關(guān)閉連接,這樣可以做到連接的復(fù)用。長(zhǎng)連接的好處是省去了創(chuàng)建連接的耗時(shí)。

短連接和長(zhǎng)連接的優(yōu)勢(shì),分別是對(duì)方的劣勢(shì)。想要圖簡(jiǎn)單,不追求高性能,使用短連接合適,這樣我們就不需要操心連接狀態(tài)的管理;想要追求性能,使用長(zhǎng)連接,我們就需要擔(dān)心各種問(wèn)題:比如端對(duì)端連接的維護(hù),連接的?;睢?/p>

長(zhǎng)連接還常常被用來(lái)做數(shù)據(jù)的推送,我們大多數(shù)時(shí)候?qū)νㄐ诺恼J(rèn)知還是 request/response 模型,但 TCP 雙工通信的性質(zhì)決定了它還可以被用來(lái)做雙向通信。在長(zhǎng)連接之下,可以很方便的實(shí)現(xiàn)push模型,我們的手機(jī)消息push,就是通過(guò)建立一條手機(jī)與服務(wù)器的連接鏈路(長(zhǎng)連接),當(dāng)有消息需要發(fā)送到手機(jī)時(shí),通過(guò)此鏈路發(fā)送即可。 比如iOS的APNS。

長(zhǎng)連接的維護(hù)

在一個(gè)分布式系統(tǒng)中,客戶端請(qǐng)求的服務(wù)可能分布在多個(gè)服務(wù)器上,客戶端自然需要跟對(duì)端創(chuàng)建多條長(zhǎng)連接,我們遇到的第一個(gè)問(wèn)題就是如何維護(hù)這些長(zhǎng)連接。

/** * 客戶端 */public class NettyHandler extends SimpleChannelHandler {// <ip:port, channel>private final Map<String, Channel> channels = new ConcurrentHashMap<String, Channel>();}/** * 服務(wù)端 */public class NettyServer extends AbstractServer implements Server {// <ip:port, channel>private Map<String, Channel> channels;}
  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

在dubbo中,客戶端和服務(wù)端都使用ip:port維護(hù)了端對(duì)端的長(zhǎng)連接,在連接建立完成后,會(huì)將Channel存放到集合中,Channel便是對(duì)連接的抽象。我們主要關(guān)注NettyHandler中的長(zhǎng)連接,服務(wù)端同時(shí)維護(hù)一個(gè)長(zhǎng)連接的集合是Dubbo的額外設(shè)計(jì),我們將在后面提到。

這里解釋下為什么我們主要關(guān)注NettyHandler中的長(zhǎng)連接。TCP是一個(gè)雙向通信的協(xié)議(全雙工),任一方都可以是發(fā)送者,接收者,那為什么還抽象了Client和Server呢?因?yàn)榻⑦B接需要有主動(dòng)發(fā)起的一方,Client可以理解為主動(dòng)建立連接的一方,實(shí)際上兩端的地位可以理解為是對(duì)等的。

連接的保活

首先我們要理解,為什么需要連接的?;睿慨?dāng)雙方已經(jīng)建立了連接,但因?yàn)榫W(wǎng)絡(luò)問(wèn)題,鏈路不通,這樣長(zhǎng)連接就不能使用了。需要明確的一點(diǎn)是,通過(guò)netstat,lsof 等指令查看到連接的狀態(tài)處于ESTABLISHED狀態(tài)并不是一件非常靠譜的事,因?yàn)檫B接可能已死,但沒(méi)有被系統(tǒng)感知到,更不用提假死這種疑難雜癥了。如何保證長(zhǎng)連接可用是一個(gè)比較復(fù)雜的事情。

KeepAlive

首先想到的是TCP中的KeepAlive機(jī)制。KeepAlive并不是TCP協(xié)議的一部分,但是大多數(shù)操作系統(tǒng)都實(shí)現(xiàn)了這個(gè)機(jī)制(所以需要在操作系統(tǒng)層面設(shè)置KeepAlive的相關(guān)參數(shù))。KeepAlive機(jī)制開(kāi)啟后,在一定時(shí)間內(nèi)(一般時(shí)間為7200s,參數(shù)tcp_keepalive_time)在鏈路上沒(méi)有數(shù)據(jù)傳送的情況下,TCP層將發(fā)送相應(yīng)的KeepAlive探針以確定連接可用性,探測(cè)失敗后重試10(參數(shù) tcp_keepalive_probes)次,每次間隔時(shí)間75s(參數(shù) tcp_keepalive_intvl),所有探測(cè)失敗后,才認(rèn)為當(dāng)前連接已經(jīng)不可用。

在Netty中開(kāi)啟KeepAlive:

bootstrap.option(ChannelOption.SO_KEEPALIVE, true)
  • 1

Linux操作系統(tǒng)中設(shè)置KeepAlive相關(guān)參數(shù),修改/etc/sysctl.conf文件:

net.ipv4.tcp_keepalive_time=90net.ipv4.tcp_keepalive_intvl=15net.ipv4.tcp_keepalive_probes=2
  • 1

  • 2

  • 3

KeepAlive機(jī)制是在網(wǎng)絡(luò)層面保證了連接的可用性,但站在應(yīng)用框架層面我們認(rèn)為這還不夠。主要體現(xiàn)在三個(gè)方面:

  • KeepAlive的開(kāi)關(guān)是在應(yīng)用層開(kāi)啟的,但是具體參數(shù)(如重試測(cè)試,重試間隔時(shí)間)的設(shè)置卻是操作系統(tǒng)級(jí)別的,位于操作系統(tǒng)的/etc/sysctl.conf配置中,這對(duì)于應(yīng)用來(lái)說(shuō)不夠靈活。

  • KeepAlive的保活機(jī)制只在鏈路空閑的情況下才會(huì)起到作用,假如此時(shí)有數(shù)據(jù)發(fā)送,且物理鏈路已經(jīng)不通,操作系統(tǒng)這邊的鏈路狀態(tài)還是ESTABLISHED,這時(shí)會(huì)發(fā)生什么?自然會(huì)走TCP重傳機(jī)制,要知道默認(rèn)的TCP超時(shí)重傳,指數(shù)退避算法也是一個(gè)相當(dāng)長(zhǎng)的過(guò)程。

  • KeepAlive本身是面向網(wǎng)絡(luò)的,并不面向于應(yīng)用,當(dāng)連接不可用,可能是由于應(yīng)用本身的GC頻繁,系統(tǒng)load高等情況,但網(wǎng)絡(luò)仍然是通的,此時(shí),應(yīng)用已經(jīng)失去了活性,連接應(yīng)該被認(rèn)為是不可用的。

我們已經(jīng)為應(yīng)用層面的連接?;钭隽俗銐虻匿亯|,下面就來(lái)一起看看,怎么在應(yīng)用層做連接?;?。

心跳

以Dubbo為例,支持應(yīng)用層的心跳,客戶端和服務(wù)端都會(huì)開(kāi)啟一個(gè) HeartBeatTask,客戶端在HeaderExchangeClient中開(kāi)啟,服務(wù)端將在 HeaderExchangeServer開(kāi)啟。文章開(kāi)頭留了一個(gè)懸念:Dubbo為什么在服務(wù)端同時(shí)維護(hù)Map<String,Channel>呢?主要就是為了給心跳做貢獻(xiàn),心跳定時(shí)任務(wù)在發(fā)現(xiàn)連接不可用時(shí),會(huì)根據(jù)當(dāng)前是客戶端還是服務(wù)端走不同的分支,客戶端發(fā)現(xiàn)不可用,是重連;服務(wù)端發(fā)現(xiàn)不可用,是直接 close。

// HeartBeatTaskif (channel instanceof Client) {((Client) channel).reconnect();} else {channel.close();}
  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

Dubbo 2.7.x 相比 2.6.x 做了定時(shí)心跳的優(yōu)化,使用 HashedWheelTimer 更加精準(zhǔn)的控制了只在連接閑置時(shí)發(fā)送心跳。

Netty提供了IdleStateHandler可以讓我們更加優(yōu)雅的實(shí)現(xiàn)應(yīng)用層心跳的機(jī)制。熟悉其他 RPC 框架的同學(xué)會(huì)發(fā)現(xiàn),不同框架的心跳機(jī)制真的是差距非常大。心跳設(shè)計(jì)還跟連接創(chuàng)建,重連機(jī)制,黑名單連接相關(guān),還需要具體框架具體分析。

除了定時(shí)任務(wù)的設(shè)計(jì),還需要在協(xié)議層面支持心跳。最簡(jiǎn)單的例子可以參考 nginx 的健康檢查,而針對(duì) Dubbo 協(xié)議,自然也需要做心跳的支持,如果將心跳請(qǐng)求識(shí)別為正常流量,會(huì)造成服務(wù)端的壓力問(wèn)題,干擾限流等諸多問(wèn)題。


其中 Flag 代表了 Dubbo 協(xié)議的標(biāo)志位,一共 8 個(gè)地址位。低四位用來(lái)表示消息體數(shù)據(jù)用的序列化工具的類(lèi)型(默認(rèn) hessian),高四位中,第一位為1表示是 request 請(qǐng)求,第二位為 1 表示雙向傳輸(即有返回response),第三位為 1 表示是心跳事件。

心跳請(qǐng)求應(yīng)當(dāng)和普通請(qǐng)求區(qū)別對(duì)待。

注意和HTTP的KeepAlive區(qū)別對(duì)待
  • HTTP協(xié)議的KeepAlive意圖在于連接復(fù)用,同一個(gè)連接上串行方式傳遞請(qǐng)求-響應(yīng)數(shù)據(jù)

  • TCP的KeepAlive機(jī)制意圖在于?;?、心跳,檢測(cè)連接錯(cuò)誤。

這壓根是兩個(gè)概念。

KeepAlive常見(jiàn)錯(cuò)誤

啟用TCP KeepAlive的應(yīng)用程序,一般可以捕獲到下面幾種類(lèi)型錯(cuò)誤:

  1. ETIMEOUT 超時(shí)錯(cuò)誤,在發(fā)送一個(gè)探測(cè)保護(hù)包經(jīng)過(guò) (tcp_keepalive_time tcp_keepalive_intvl * tcp_keepalive_probes)時(shí)間后仍然沒(méi)有接收到 ACK 確認(rèn)情況下觸發(fā)的異常,套接字被關(guān)閉

    java.io.IOException: Connection timed out

  2. EHOSTUNREACH host unreachable(主機(jī)不可達(dá))錯(cuò)誤,這個(gè)應(yīng)該是 ICMP 匯報(bào)給上層應(yīng)用的。

    java.io.IOException: No route to host

  3. 連接被重置,終端可能崩潰死機(jī)重啟之后,接收到來(lái)自服務(wù)器的報(bào)文,然物是人非,前朝往事,只能報(bào)以無(wú)奈重置宣告之。

    java.io.IOException: Connection reset by peer

KeepAlive實(shí)踐方案
  1. 默認(rèn)情況下使用 KeepAlive 周期為 2 個(gè)小時(shí),如不選擇更改,屬于誤用范疇,造成資源浪費(fèi):內(nèi)核會(huì)為每一個(gè)連接都打開(kāi)一個(gè)?;钣?jì)時(shí)器,N 個(gè)連接會(huì)打開(kāi) N 個(gè)?;钣?jì)時(shí)器。 優(yōu)勢(shì)很明顯:

    • TCP 協(xié)議層面?;钐綔y(cè)機(jī)制,系統(tǒng)內(nèi)核完全替上層應(yīng)用自動(dòng)給做好了

    • 內(nèi)核層面計(jì)時(shí)器相比上層應(yīng)用,更為高效

    • 上層應(yīng)用只需要處理數(shù)據(jù)收發(fā)、連接異常通知即可

    • 數(shù)據(jù)包將更為緊湊

  2. 關(guān)閉 TCP 的 KeepAlive,完全使用應(yīng)用層心跳保活機(jī)制。由應(yīng)用掌管心跳,更靈活可控,比如可以在應(yīng)用級(jí)別設(shè)置心跳周期,適配私有協(xié)議。

  3. 業(yè)務(wù)心跳 TCP KeepAlive 一起使用,互相作為補(bǔ)充,但 TCP ?;钐綔y(cè)周期和應(yīng)用的心跳周期要協(xié)調(diào),以互補(bǔ)方可,不能夠差距過(guò)大,否則將達(dá)不到設(shè)想的效果。

各個(gè)框架的設(shè)計(jì)都有所不同,例如 Dubbo 使用的是方案三,這和框架整體的設(shè)計(jì)相關(guān)。

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
dubbo之心跳機(jī)制
白話TCP/IP原理
TCP如何保持長(zhǎng)連接,并識(shí)別不同請(qǐng)求的?
字節(jié)一面:HTTP 長(zhǎng)連接和 TCP 長(zhǎng)連接有區(qū)別?
TCP協(xié)議長(zhǎng)連接和短連接詳解
『互聯(lián)網(wǎng)架構(gòu)』軟件架構(gòu)
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服