Go 自帶的 http/server.go 的連線解析 與 如何結合 master-worker 併發模式,提高單機併發能力
作者:林冠巨集 / 指尖下的幽靈
關於
server.go
原始碼的解析可以去搜下,已經有很多且還不錯的文章。
正文:
從我們啟動http.ListenAndServe(port,router)
開始,server.go
內部最終在一個for
迴圈中的 accept
方法中不停地等待客戶端
的連線到來。
每接收到一個accept
就啟動一個 gorutine
去處理當前ip
的連線。也就是原始碼裡的go c.serve(ctx)
。這一個步驟在 c.serve(ctx)
它並不是簡單的形式:
請求-->處理請求-->返回結果-->斷開這個連線-->結束當前的 gorutine
根據我的除錯結果
與原始碼分析
顯示,正確的形式是下面這樣的:
為每一個連線的使用者啟動了一個長連線,
serve
方法內部有個超時的設定是c.rwc.SetReadDeadline(time.Time{})
,這樣子的情況,如果內部不出錯,當前的連線斷開的條件是客戶端
自己斷開,或nat
超時。這個連線建立後,以
ip
為單位,當前的客戶端
,此時它的所有http請求
,例如get
,post
,它們都會在這個啟動的gorutine
內進行分發
與被處理
。也就是說,同一個
ip
,多個不同的
請求,這裡不會觸發另一個accept
,不會再去啟動一個go c.serve(ctx)
上述我們得出結論:
如果有
100萬
accept
,就證明有100萬
個連線,100萬
個ip
與當前server
連線。即是我們說的百萬連線
百萬連線
不是百萬請求
每一個連線,它可以進行多個
http請求
,它的請求都在當前啟動這個連線的gorutine
裡面進行。c.serve(...)
原始碼中的for 死迴圈
就是負責讀取每個請求再分發
for {
w, err := c.readRequest(ctx) // 讀取一個 http 請求
//...
ServeHTTP(...)
}
- 我們的
100萬
連線裡面,有可能併發更多的請求,例如幾百萬請求,一個客戶端
快速呼叫多個請求api
圖解總結
結合 master-worker 併發模式
根據我們上面的分析,每一個新連線到來,go 就會啟動一個 gorutine
,在原始碼裡面也沒有看到有一個量級的限制,也就是達到多少連線就不再接收。我們也知道,伺服器是有處理瓶頸的。
所以,在這裡插播一個優化點
,就是在server.go
內部做一個連線數目的限制。
master-worker
模式本身是啟動多個worker
執行緒,去併發讀取
有界佇列裡面的任務,並執行。
我自身已經實現了一個go版本
的master-worker
,做過下面的嘗試:
- 在
go c.serve(ctx)
處做修改,如下。
if srv.masterWorkerModel {
// lgh --- way to execute
PoolMaster.AddJob(
masterworker.Job{
Tag:" http server ",
Handler: func() {
c.serve(ctx)
fmt.Println("finish job") // 這一句在當前 ip 斷開連線後才會輸出
},
})
}else{
go c.serve(ctx)
}
func (m Master) AddJob(job Job) {
fmt.Println("add a job ")
m.JobQueue <- job // jobQueue 是具備緩衝的
}
// worker
func (w Worker) startWork(master *Master) {
go func() {
for {
select {
case job := <-master.JobQueue:
job.doJob(master)
}
}
}()
}
// job
func (j Job) doJob(master *Master) {
go func() {
fmt.Println(j.Tag+" --- doing job...")
j.Handler()
}()
}
不難理解它的模式。
現在我們使用生產者--消費者模式
進行假設,連線的產生
是生產者
,<-master.JobQueue
是消費者
,因為每一次消費就是啟動一個處理的gorutine
。
因為我們在accept
一個請求到<-master.JobQueue
,管道輸出一個的這個過程中,可以說是沒有耗時操作的,這個job
,它很快就被輸出了管道。也就是說,消費很快
,那麼實際的生產環境
中,我們的worker
工作協程
啟動5~10
個就有餘了。
考慮如果出現了消費跟不上
的情況,那麼多出來的job
將會被緩衝到channel
裡面。這種情況可能出現的情景是:
短時間十萬+級別連線的建立,就會導致
worker
讀取不過來。不過,即使發生了,也是很快就取完的。因為間中的耗時幾乎可以忽略不計!
也就說,短時間
大量連線的建立,它的瓶頸在佇列的緩衝數
。但是即使瓶頸發生了,它又能很快被分發處理掉。所以說:
我的這個第一點的嘗試的意義事實上沒有多大的。只不過是換了一種方式去分發
go c.serve(ctx)
。
- 這個是第二種結合方式,把
master-worker
放置到ServeHTTP
的分發階段。例如下面程式碼,是常見的http handler
寫法,我們就可以巢狀進去。
func (x XHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
//...
if x.MasterWorker {
poolMaster.AddJob(master_worker.Job{
Tag:"normal",
XContext:xc,
Handler: func(context model.XContext) {
x.HandleFunc(w,r)
},
})
return
}
x.HandleFunc(w,r)
//...
}
這樣的話,我們就能控制所有連線的併發請求最大數。超出的將會進行排隊,等待被執行,而不會因為短時間 http 請求數目不受控暴增
而導致伺服器
掛掉。
此外上述第二種
還存在一個:讀,過早關閉問題
,這個留給讀者嘗試解決。
相關推薦
Go 自帶的 http/server.go 的連線解析 與 如何結合 master-worker 併發模式,提高單機併發能力
作者:林冠巨集 / 指尖下的幽靈 關於 server.go 原始碼的解析可以去搜下,已經有很多且還不錯的文章。 正文: 從我們啟動http.ListenAndServe(port,router)開始,server.go 內部最終在一個for 迴圈中的 accept 方法中不停地等待客戶端的連
VS2010自帶SQL Server 2008 允許遠端連線的解決方法
使用者在使用SQL Server 2008遠端連結時,可能會彈出如下對話方塊: “在連結SQL伺服器時發生網路連結錯誤或特定例項錯誤。SQL伺服器不存在或者連結不成功。請驗證使用者名稱是否正確或SQL伺服器是否已經配置遠端連結功能。
Mac 上自帶TFTP Server 軟件的使用
comm 執行 連接服務器 ttys0 app chmod mac htm link 1、TFTP協議 簡單文件傳輸協議Trivial File Transfer Protocol (TFTP)是一個基於UDP協議的簡單的、低開銷的文件傳輸協議,允許客戶端get或者put文
如何使用windows10自帶的遠端桌面連線工具控制樹莓派
1.準備 安裝好最新版的樹莓派官方系統映象,準備一臺顯示器,一套滑鼠鍵盤,HDMI轉VGA線(一端連線樹莓派的HDMI一端連線顯示器的VGA介面)。 進入官網https://www.raspberrypi.org/downloads/下載Raspbian系統(下載系統時推薦下載RASPBIAN JES
myeclipse自帶刪除server方法
第一步: 檢視server中是否存在myeclipse tomcat; 第二步 開啟“Window”——“perferences”; 第三步:
JSON介紹及Android最全面解析方法(Gson、AS自帶org.son、Jackson解析)
前言 今天,我們來介紹一下現今主流的資料交換格式-JSON! 目錄 定義 JavaScript Object Notation,JavaScript的物件表示法,是一種輕量級的文字資料交換格式。 作用 用於資料的標記、儲存
Android開發:JSON簡介及最全面解析方法(Gson、AS自帶org.json、Jackson解析)
目錄 JSON簡介&解析方法介紹.png 定義 JavaScript Object Notation,JavaScript的物件表示法,是一種輕量級的文字資料交換格式。 作用 用於資料的標記、儲存和傳輸。 特點 輕量級的文字資料交換格式 獨立於語言和平臺 具有自我描述性 讀寫速度快,解析簡單 語法
VS 2013 用自帶SQL Server開啟已有資料庫
1.連結SQL Server伺服器 在SQL Server物件資源管理器中,右擊SQL Server,點選新增SQL Server 選擇其中一個如:(LocalDB)\v11.0 點選 Connect 2.連結本地已有SQL資料庫檔案 在伺服器資源管理器中右擊資料
eclipse項目轉移至IDEA與IDEA tomcat報錯(idea自帶tomcat版本太高)與war包部署到win服務器與idea提交git的總結
image push under 正常 回來 env acc nvi 雲上 eclipse導出項目到idea時,不要導出target; idea打開eclipse項目後,出現junit找不到的問題,原因是jar包缺失,而maven配置的低版本的junit
遠端連線區域網內的sql server 無法連線 錯誤與解決方法
第一個錯誤"SQL Server 不存在或訪問被拒絕"通常是最複雜的,錯誤發生的原因比較多,需要檢查的方面也比較多 。一般說來,有以下幾種可能性: 1、SQL Server名稱或IP地址拼寫有誤; 2、伺服器端網路配置有誤; 3、客戶端網路配置有誤。 要解決這個問題,我們一般要遵循以
HTTP的請求報文解析 與 響應報文解析 、 HTTP請求報文中 GET 和 POST的區別 和 URL解析
一、什麼是HTTP? HTTP是超文字傳輸協議 二、HTTP特點? (1)HTTP是無狀態協議; (2)HTTP是web服務使用的協議; (3)HTTP是基於TCP協議的; (4)HTTP的通訊方式是客戶端-伺服器模式,即C/S
go http client, http server
only lock nan ret str net con iou main Go語言中的HTTP client, server非常簡單。具體如下。 HTTP Server package main import ( "fmt" "htm
Go Web:自帶的ServeMux multiplexer
ServeMux簡介 ServeMux扮演的角色是Multiplexer,它用來將將請求根據url路由給已註冊的handler。如下圖: 上圖中為3個路徑註冊了handler,一個是"/",另外兩個是"/hello"和"/world"。這表示訪問http://hostname/hello時,multi
Go語言net/http包解析
首先來看一個用net/http包寫的web伺服器:兩個函式實現http伺服器package main import ( "fmt" "net/http" "strings" "log" ) func sayhelloName(w http.ResponseWrit
系統自帶的Sql server連線測試工具
系統有一種檔案是可以在設定引數後測試是否能正確連結到對應的資料庫上的,很方便簡單,不過不太好的就是如果連線的是ms sqlserver資料庫時,通過“連線”選項卡,只能讀取預設的例項顯示在伺服器名稱下拉列表,不能顯示其他例項名稱,需要到“所有”選項卡去手動編輯“Data Source”的值。也不能自動生成連線
go語言net/http包解析http body之坑
在Server端解析HTTP請求的時候, func ProcScaleOutReq(rsp http.ResponseWriter, req *http.Request) { req.ParseForm() //bodyStr := [1024]byte{
xml解析工具mashaller javaee自帶解析類
for writer length star 工具 進行 去掉m comm err 1.怎樣去掉Marshaller的格式化? : JAXBContext context = JAXBContext.newInstance(Entity.class);
安裝好SQL Server 2016,沒有自帶SSMS 工具
sqlhttps://docs.microsoft.com/zh-cn/sql/ssms/sql-server-management-studio-changelog-ssms?view=sql-server-2016#previous-ssms-releases 安裝:SQL Server Manageme
關於CDH5.11.0自帶kafka 0.10 bootstrap-server 無法消費
出現 指定 pre hit tst apache 10.2.2 來看 min 近日需要在項目用到kafka,然後本地使用cdh集成的kafka 進行安裝調試,以及些樣例代碼,sparkstreaming 相關調用kafka 的代碼使用的原始的api 而沒有走zook
關於 MongoDB 與 SQL Server 通過本身自帶工具實現數據快速遷移 及 註意事項 的探究
數據遷移工具 文件中 文件導入 原本 修改字段 信息 字符 變化 是否 背景介紹 隨著業務的發展、需求的變化,促使我們追求使用不同類型的數據庫,充分發揮其各自特性。如果決定采用新類型的數據庫,就需要將既有的數據遷移到新的數據庫中。在這類需求中,將SQL Server中的數據