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

Go BIO/NIO探討:Gin框架中如何處理HTTP請求

開發 前端
熟悉Java的朋友看到 NIO 這個詞,應該會有莫名的親切感。值得慶幸的是,現在終于有人用Go翻譯一波netty了。

最近看到字節跳動開源了Go語言的Hertz,聲稱使用了 Non-blocking IO 網絡庫 Netpoll,所以性能非常強大,并給出了Echo的性能測試數據。

性能測試

相對于目前業界流行的 gin 框架,QPS提升超過100%,而且單次請求的數據包越大,性能提升越明顯。

熟悉Java的朋友看到 NIO 這個詞,應該會有莫名的親切感。值得慶幸的是,現在終于有人用Go翻譯一波netty了。

在這之前,為了更好地理解Blocking IO,我們從 Web 框架入手,看 Go 內置的 net/http 是如何工作的。

下面這段代碼展示了Gin框架中如何定義一個路由,并啟動Server。代碼來自于 Github:gin-gonic/gin,我們從這段代碼入手,了解 http 的運行機制。

package main

import (
"net/http"
"github.com/gin-gonic/gin"
)

func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"message": "pong",
})
})
r.Run() // 監聽8080端口
}

在這段代碼中,r 是一個 *gin.Engine 對象,它實現了 net/http下的Handler 接口:

type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}

第二步是設置路由和對應的處理函數,*gin.Engine 對象嵌入了 struct RouterGroup,實現路由功能。Web開發中,這是所有業務邏輯的入口。

第三步是運行服務,基本流程是三個tcp系統調用 socket, bind, listen,然后在 for 循環里調用 accept 接收新的tcp連接(更多細節參考Unix網絡編程卷一第四章)。

// 來源于Go源碼 net/http/server.go struct Server
func (srv *Server) ListenAndServe() error {
if srv.shuttingDown() {
return ErrServerClosed
}
addr := srv.Addr
if addr == "" {
addr = ":http"
}
ln, err := net.Listen("tcp", addr)
if err != nil {
return err
}
return srv.Serve(ln)
}

func (srv *Server) Serve(l net.Listener) error {
// ... 省略一部分代碼

origListener := l
l = &onceCloseListener{Listener: l}
defer l.Close()

if err := srv.setupHTTP2_Serve(); err != nil {
return err
}

// ... 省略一部分代碼

ctx := context.WithValue(baseCtx, ServerContextKey, srv)
for {
rw, err := l.Accept()
// ... 省略一部分代碼
c := srv.newConn(rw)
c.setState(c.rwc, StateNew, runHooks) // before Serve can return
go c.serve(connCtx)
}
}

到這里,HTTP還沒有登場,因為HTTP是應用層協議,而TCP是傳輸層協議。我們拿到 tcp connection 以后,HTTP協議體現在對數據包的處理上。

HTTP/1 仍然是一個超文本協議,HTTP/2 是一個基于幀的二進制協議,并且支持了server端主動推送。由于 HTTP/1 仍然是主流,我們這里先說 HTTP/1,它的報文分三部分:

  1. 起始行
  2. Headers 消息頭,以一個空行結束
  3. Body 消息體

應用程序可以方便地解析HTTP 請求和響應。HTTP/1.1 已經支持復用TCP連接,也就是說多個HTTP請求可以在同一個tcp conn上傳輸,那么client端如何把request和response 對應起來呢?會有什么問題?HTTP/2中又是怎么做的?這里先挖個坑。

繼續看 net/http 的代碼,了解HTTP 如何在tcp conn之上工作的。主要邏輯如下:

// Serve a new connection.
func (c *conn) serve(ctx context.Context) {
c.remoteAddr = c.rwc.RemoteAddr().String()
ctx = context.WithValue(ctx, LocalAddrContextKey, c.rwc.LocalAddr())
var inFlightResponse *response
defer func() {... // cleanup

if tlsConn, ok := c.rwc.(*tls.Conn); ok {
// ... 省略部分代碼
}

// HTTP/1.x from here on.
ctx, cancelCtx := context.WithCancel(ctx)
c.cancelCtx = cancelCtx
defer cancelCtx()

c.r = &connReader{conn: c}
c.bufr = newBufioReader(c.r)
c.bufw = newBufioWriterSize(checkConnErrorWriter{c}, 4<<10)

for {
w, err := c.readRequest(ctx)
// ... 省略部分代碼
serverHandler{c.server}.ServeHTTP(w, w.req)
// ... 省略一部分代碼
w.finishRequest()
// ... 省略一部分代碼
}

這段代碼的前半部分是設置cleanup邏輯、初始化conn相關的變量,后半部分是在 for 循環里處理 HTTP 請求,體現為:

  1. 讀取 tcp conn上的數據,并解析&組裝成一個請求,存儲到一個http.response對象里。
  2. 通過 ServeHTTP 調用業務邏輯(路由轉發到特定處理函數),獲取響應。
  3. 把響應報文寫入 tcp conn。

關于Gin框架和net/http 的邏輯到這里就介紹完了,大的流程參考下面這個思維導圖:

為什么 Blocking IO

當我們聊到 Blocking IO 和 Non-blocking IO,通常是指一個線程調用 read 或 write 時,是否被阻塞:

  • BIO: 線程被阻塞直到讀到數據或寫入完成。
  • NIO: 線程不被阻塞,可以去做其他事情,但是有數據到來或者寫入完成時,線程會接收到通知。

這里我們限定到網絡IO的情況,Go net/http 里BIO體現在兩個地方:

  • case 1: listener 在for循環里等待接收新的tcp conn。
  • case 2: conn 等待讀取新的 request。
// case 1
for {
rw, err := l.Accept()
// ... 省略一部分代碼
c := srv.newConn(rw)
c.setState(c.rwc, StateNew, runHooks) // before Serve can return
go c.serve(connCtx)
}

// case 2
for {
w, err := c.readRequest(ctx)
// ... 省略部分代碼
serverHandler{c.server}.ServeHTTP(w, w.req)
// ... 省略一部分代碼
w.finishRequest()
// ... 省略一部分代碼
}

如果把 goroutine 當成操作系統線程,我們可以把這種模式當作BIO。由于在網絡IO上 Go語言對 goroutine 的特殊實現,在細節上可能會有點爭議,有興趣的同學可以自己研究下。

要做到 NIO,典型的方式是通過 reactor 模式,替換上面的兩個for循環。在后面的文章中,我們介紹 hertz 框架的時候,會詳細聊一下這個方案。

責任編輯:姜華 來源: 今日頭條
相關推薦

2023-03-07 08:00:12

netpollGo

2023-03-31 07:49:51

syscall庫Echo Serve

2023-03-09 08:22:57

Go net庫Socket

2023-09-19 22:41:30

控制器HTTP

2011-12-15 12:32:19

JavaNIO

2021-01-18 05:13:04

TomcatHttp

2022-12-26 00:00:01

Go框架前端

2025-01-09 10:20:53

2014-11-10 10:52:33

Go語言

2024-11-04 08:16:08

Go語言Web 框架

2020-04-16 15:20:43

PHP前端BIO

2011-03-31 10:41:49

BIONIOIO

2022-04-16 16:52:24

Netty網絡服務器客戶端程序

2022-10-17 09:02:49

Go自動驗證數據綁定

2023-10-04 07:35:03

2024-02-19 07:40:10

2024-01-30 12:08:31

Go框架停止服務

2024-03-05 07:55:41

框架GINGo

2011-09-02 11:06:28

Oracle服務器進程為事務建立回滾段放入dirty lis

2021-01-25 06:53:59

前端AJAX技術熱點
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 在线色| 伊人网综合在线观看 | 成人av网站在线观看 | 亚洲aⅴ精品| 午夜精品一区二区三区在线观看 | 欧美一区视频在线 | 亚洲成人av在线播放 | 成人免费观看男女羞羞视频 | 欧美一级免费看 | 天天干天天爱天天 | 人人九九精 | 蜜桃精品视频在线 | 91在线视频| 国产在线二区 | 欧美在线精品一区 | 国产精品揄拍一区二区 | 欧美精品一区三区 | 欧美成年人 | 欧美日韩国产精品一区 | 日韩一区二区三区在线视频 | h在线观看| 国产美女一区二区 | 天天干天天操天天射 | 日韩成人免费av | 国产一级片一区二区 | 亚洲精品区 | 亚洲一区二区三区高清 | 欧日韩在线观看 | 亚洲午夜精品久久久久久app | 国产精品www | 毛片一区二区三区 | 国产精品一码二码三码在线 | 全免费a级毛片免费看视频免费下 | 日韩在线小视频 | 日本黄色影片在线观看 | 99在线免费视频 | 最新国产精品视频 | 免费观看一级黄色录像 | 欧美日韩一区二区视频在线观看 | 日本免费在线 | 日本中文字幕在线观看 |