提高網路效率的總結

2021-09-07 08:32:53 字數 3214 閱讀 8188

以epoll為代表。libevent也是基於epoll而實現的。

是跟非同步化相結合,reactor模式。另有scala的actor模式,是完全的訊息互動。

比如禁掉nagle選項,不要開啟cork演算法,使得發包和ack不要延遲太多。

解決time_wait狀態過多的問題。尤其是短連線。可以參考

如下:不管長連線還是短連線,連線建立->資料傳輸->連線關閉的流程和處理都是一樣的。

正常的tcp客戶端連線在關閉後,會進入乙個time_wait的狀態,持續的時間一般在1~4分鐘,對於連線數不高的場景,1~4分鐘其實並不長,對系統也不會有什麼影響,

但如果短時間內(例如1s內)進行大量的短連線,則可能出現這樣一種情況:客戶端所在的作業系統的socket埠和控制代碼被用盡,系統無法再發起新的連線!

舉例來說:假設每秒建立了1000個短連線(web場景下是很常見的,例如每個請求都去訪問memcached),假設time_wait的時間是1分鐘,則1分鐘內需要建立6w個短連線,

由於time_wait時間是1分鐘,這些短連線1分鐘內都處於time_wait狀態,都不會釋放,而linux預設的本地埠範圍配置是:

net.ipv4.ip_local_port_range = 32768

61000

不到3w,因此這種情況下新的請求由於沒有本地埠就不能建立了

可以通過如下方式來解決這個問題:

1)可以改為長連線,但代價較大,長連線太多會導致伺服器效能問題,而且php等指令碼語言,需要通過proxy之類的軟體才能實現長連線;

2)修改ipv4.ip_local_port_range,增大可用埠範圍,但只能緩解問題,不能根本解決問題;

3)客戶端程式中設定socket的so_linger選項;

4)客戶端機器開啟tcp_tw_recycle和tcp_timestamps選項;

5)客戶端機器開啟tcp_tw_reuse和tcp_timestamps選項;

6)客戶端機器設定tcp_max_tw_buckets為乙個很小的值;

so_linger的學習見:

so_linger選項用於控制close系統呼叫在關閉tcp連線時的行為。預設情況下,當我們使用close系統呼叫來關閉乙個socket時,close將立即返回,tcp模組負責把該socket對應的tcp傳送緩衝區中殘留的資料傳送給對方。

#include struct

linger

;

根據linger結構體中兩個成員變數的不同值,close系統呼叫可能產生如下3種行為之一: 

(1)l_onoff等於0(關閉)。此時so_linger選項不起作用,close用預設行為來關閉socket。 

(2)l_onoff不為0(開啟),l_linger等於0。此時close系統呼叫立即返回,tcp模組將丟棄被關閉的socket對應的tcp傳送緩衝區中殘留的資料,同時給對方傳送乙個復位報文段(rst)。因此,這種情況給伺服器提供了異常終止乙個連線的方法。 

(3)l_onoff不為0(開啟),l_linger大於0。此時close的行為取決於兩個條件:一是被關閉的socket對應的tcp傳送緩衝區是否還有殘留的資料;二是該socket是阻塞的,還是非阻塞的。對於阻塞的socket,close將等待一段長為l_linger的時間,直到tcp模組傳送完所有殘留資料並得到對方的確認。如果這段時間內tcp模組沒有傳送完殘留資料並得到對方的確認,那麼close系統呼叫將返回-1並設定errno為ewouldblock。如果socket是非阻塞的,close將立即返回,此時我們需要根據其返回值和errno來判斷殘留資料是否已經傳送完畢。

注:linux下 ewouldblock貌似就是eagain

除了上面這兩個errno,要注意的是 eintr指操作被中斷喚醒,需要重新讀/寫

eagain不是一種錯誤。在vxworks和windows上,eagain的名字叫做ewouldblock。

另外,如果出現eintr即errno為4,錯誤描述interrupted system call,操作也應該繼續。

最後,如果recv的返回值為0,那表明連線已經斷開,我們的接收操作也應該結束。

另外還有 so_reuseaddr選項:

so_reuseaddr可以用在以下四種情況下。

(摘自《unix網路程式設計》卷一,即unpv1)

1、當有乙個有相同本地位址和埠的socket1處於time_wait狀態時,而你啟動的程式的socket2要占用該位址和埠,你的程式就要用到該選項。

2、so_reuseaddr允許同一port上啟動同一伺服器的多個例項(多個程序)。但每個例項繫結的ip位址是不能相同的。在有多塊網絡卡或用ip alias技術的機器可以測試這種情況。

3、so_reuseaddr允許單個程序繫結相同的埠到多個socket上,但每個socket繫結的ip位址不同。這和2很相似,區別請看unpv1。

4、so_reuseaddr允許完全相同的位址和埠的重複繫結。但這只用於udp的多播,不用於tcp。

還有乙個:so_reuseport選項有如下語義:

此選項允許完全重複**,但僅在想**相同ip位址和埠的套介面都指定了此套介面選項才行。

如果被**的ip位址是乙個多播位址,則so_reuseaddr和so_reuseport等效。

使用這兩個套介面選項的建議:

在所有tcp伺服器中,在呼叫bind之前設定so_reuseaddr套介面選項;

用法如下:

int option = 1

;if (setsockopt ( mastersocket, sol_socket, so_reuseaddr, &option, sizeof(option) ) < 0

)

q: 編寫 tcp/sock_stream 服務程式時,so_reuseaddr到底什麼意思?

a: 這個套接字選項通知核心,如果埠忙,但tcp狀態位於 time_wait ,可以重用埠。如果埠忙,而tcp狀態位於其他狀態,重用埠時依舊得到乙個錯誤資訊,指明"位址已經使用中"。如果你的服務程式停止後想立即重啟,而新套接字依舊使用同一埠,此時 so_reuseaddr 選項非常有用。必須意識到,此時任何非期望資料到達,都可能導致服務程式反應混亂,不過這只是一種可能,事實上很不可能。

乙個套接字由相關五元組構成,協議、本地位址、本地埠、遠端位址、遠端埠。so_reuseaddr 僅僅表示可以重用本地本地位址、本地埠,整個相關五元組還是唯一確定的。所以,重啟後的服務程式有可能收到非期望資料。必須慎重使用 so_reuseaddr 選項。

效率的提高

本篇文章記錄一些提高效率的方法,包括但不限於手機,電腦,辦公軟體等等,後續將在本文基礎上進行更新,歡迎收藏 by葉常落。看文章之前請先思考乙個歷史問題。18世紀的工業革命時期,紡織工人害怕失業而砸掉蒸汽機,你對這個問題怎麼看?是引入蒸汽機的資本家贏了還是那些打砸機器的工人贏了?那些害怕失業的紡織工人...

利用apply提高程式設計效率的方法總結

下面是乙個常見的例子 var dog var cat 例子中分別定義了乙個dog物件和乙個cat物件,它們都有sound變數,但是dog物件有乙個makesound方法,而cat沒有,如果這裡要求cat也要能夠發聲 makesound 有兩種直觀的解決方案 第一,給cat直接賦予乙個makesoun...

提高sql語句查詢效率的方法總結

網上查詢的,自用 做phpexcel 匯出的時候,我的資料庫主表裡記錄的都是一些關聯資料的id,之前的做法是先將資料查詢出來之後,用foreach 迴圈,根據關聯id取出需要的資料。這在資料量小的時候沒有問題,但是當資料超過1000條之後,查詢時間會超過40s,造成超時。所以優化查詢語句,用關聯查詢...