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

Fasthttp 為什么比標(biāo)準(zhǔn)庫(kù)快 10 倍 ?

開(kāi)發(fā) 前端
本文不會(huì)講解 fasthttp 的應(yīng)用方法,而是會(huì)重點(diǎn)分析 fasthttp 高性能的背后實(shí)現(xiàn)原理。

概述

fasthttp? 是一個(gè)使用 Go 語(yǔ)言開(kāi)發(fā)的 HTTP 包,主打高性能,針對(duì) HTTP 請(qǐng)求響應(yīng)流程中的 hot path? 代碼進(jìn)行了優(yōu)化,達(dá)到零內(nèi)存分配,性能比標(biāo)準(zhǔn)庫(kù)的 net/http 快 10 倍。

上面是來(lái)自官方 Github 主頁(yè)的項(xiàng)目介紹,拋開(kāi)其介紹內(nèi)容不談,光從名字本身來(lái)看,作者對(duì)項(xiàng)目代碼的自信程度可見(jiàn)一斑。

本文不會(huì)講解 fasthttp? 的應(yīng)用方法,而是會(huì)重點(diǎn)分析 fasthttp 高性能的背后實(shí)現(xiàn)原理。

基準(zhǔn)測(cè)試

我們可以通過(guò)基準(zhǔn)測(cè)試看看 fasthttp? 是否真的如描述所言,吊打標(biāo)準(zhǔn)庫(kù)的 net/http,下面是官方提供的基準(zhǔn)測(cè)試結(jié)果:

net/http

$ GOMAXPROCS=4 go test -bench='HTTPClient(Do|GetEndToEnd)' -benchmem -benchtime=10s
BenchmarkNetHTTPClientDoFastServer-4 2000000 8774 ns/op 2619 B/op 35 allocs/op
BenchmarkNetHTTPClientGetEndToEnd1TCP-4 500000 22951 ns/op 5047 B/op 56 allocs/op
BenchmarkNetHTTPClientGetEndToEnd10TCP-4 1000000 19182 ns/op 5037 B/op 55 allocs/op
BenchmarkNetHTTPClientGetEndToEnd100TCP-4 1000000 16535 ns/op 5031 B/op 55 allocs/op
BenchmarkNetHTTPClientGetEndToEnd1Inmemory-4 1000000 14495 ns/op 5038 B/op 56 allocs/op
BenchmarkNetHTTPClientGetEndToEnd10Inmemory-4 1000000 10237 ns/op 5034 B/op 56 allocs/op
BenchmarkNetHTTPClientGetEndToEnd100Inmemory-4 1000000 10125 ns/op 5045 B/op 56 allocs/op
BenchmarkNetHTTPClientGetEndToEnd1000Inmemory-4 1000000 11132 ns/op 5136 B/op 56 allocs/op

fasthttp

$ GOMAXPROCS=4 go test -bench='kClient(Do|GetEndToEnd)' -benchmem -benchtime=10s
BenchmarkClientDoFastServer-4 50000000 397 ns/op 0 B/op 0 allocs/op
BenchmarkClientGetEndToEnd1TCP-4 2000000 7388 ns/op 0 B/op 0 allocs/op
BenchmarkClientGetEndToEnd10TCP-4 2000000 6689 ns/op 0 B/op 0 allocs/op
BenchmarkClientGetEndToEnd100TCP-4 3000000 4927 ns/op 1 B/op 0 allocs/op
BenchmarkClientGetEndToEnd1Inmemory-4 10000000 1604 ns/op 0 B/op 0 allocs/op
BenchmarkClientGetEndToEnd10Inmemory-4 10000000 1458 ns/op 0 B/op 0 allocs/op
BenchmarkClientGetEndToEnd100Inmemory-4 10000000 1329 ns/op 0 B/op 0 allocs/op
BenchmarkClientGetEndToEnd1000Inmemory-4 10000000 1316 ns/op 5 B/op 0 allocs/op

基準(zhǔn)結(jié)果對(duì)比

從基準(zhǔn)測(cè)試結(jié)果來(lái)看,fasthttp? 的執(zhí)行速度要比標(biāo)準(zhǔn)庫(kù)的 net/http? 快很多,此外,fasthttp? 的內(nèi)存分配方面優(yōu)化到了 0?, 完勝 net/http。

核心優(yōu)化點(diǎn)

筆者選擇的 valyala/fasthttp[1] 版本為 v1.45.0。

對(duì)象復(fù)用

workerPool

workerpool? 對(duì)象表示 連接處理? 工作池,這樣可以控制連接建立后的處理方式,而不是像標(biāo)準(zhǔn)庫(kù) net/http? 一樣,對(duì)每個(gè)請(qǐng)求連接都啟動(dòng)一個(gè) goroutine? 處理, 內(nèi)部的 ready? 字段存儲(chǔ)空閑的 workerChan? 對(duì)象,workerChanPool? 字段表示管理 workerChan 的對(duì)象池。

// workerpool.go
type workerPool struct {
ready []*workerChan

workerChanPool sync.Pool
}

type workerChan struct {
lastUseTime time.Time
ch chan net.Conn
}

請(qǐng)求/響應(yīng) 對(duì)象

請(qǐng)求對(duì)象 Request? 和響應(yīng)對(duì)象 Response 都是通過(guò)對(duì)象池進(jìn)行管理的,對(duì)應(yīng)的代碼如下:

// client.go

var (
requestPool sync.Pool
responsePool sync.Pool
)

// 從對(duì)象池中獲取 Request 對(duì)象
func AcquireRequest() *Request {
...
}

// 歸還 Request 對(duì)象到對(duì)象池中
func ReleaseRequest(req *Request) {
...
}

// 從對(duì)象池中獲取 Response 對(duì)象
func AcquireResponse() *Response {
...
}

// 歸還 Response 對(duì)象到對(duì)象池中
func ReleaseResponse(resp *Response) {
...
}

Cookie 對(duì)象

Cookie 對(duì)象也是通過(guò)對(duì)象池進(jìn)行管理的,對(duì)應(yīng)的代碼如下:

// cookie.go

var cookiePool = &sync.Pool{
New: func() interface{} {
return &Cookie{}
},
}

// 從對(duì)象池中獲取 Cookie 對(duì)象
func AcquireCookie() *Cookie {
...
}

// 歸還 Cookie 對(duì)象到對(duì)象池中
func ReleaseCookie(c *Cookie) {
...
}

其他對(duì)象復(fù)用

$ grep -inr --include \*.go "sync.Pool" $(go list -f {{.Dir}} github.com/valyala/fasthttp) | wc -l

# 輸出如下
38

通過(guò)輸出結(jié)果可以看到,fasthttp? 中一共有 38 個(gè)對(duì)象是通過(guò)對(duì)象池進(jìn)行管理的,可以說(shuō)幾乎復(fù)用了所有對(duì)象,So Crazy!

[]byte 復(fù)用

fasthttp? 中復(fù)用的對(duì)象在使用完成后歸還到對(duì)象池之前,需要調(diào)用對(duì)應(yīng)的 Reset? 方法進(jìn)行重置,如果對(duì)象中包含 []byte? 類(lèi)型的字段, 那么會(huì)直接進(jìn)行復(fù)用,而不是初始化新的 []byte?, 例如 URI? 對(duì)象的 Reset 方法:

// 重置 URI 對(duì)象
// 從方法的內(nèi)部實(shí)現(xiàn)中可以看到,類(lèi)型為 []byte 的所有字段都被復(fù)用了
func (u *URI) Reset() {
u.pathOriginal = u.pathOriginal[:0]
u.scheme = u.scheme[:0]
u.path = u.path[:0]
u.queryString = u.queryString[:0]
u.hash = u.hash[:0]
u.username = u.username[:0]
u.password = u.password[:0]

u.host = u.host[:0]
...
}

此外,涉及到單個(gè)字段的修改,如果字段是 []byte? 類(lèi)型,還是會(huì)直接復(fù)用,例如 Cookie 對(duì)象的這幾個(gè)方法:

func (c *Cookie) SetValue(value string) {
c.value = append(c.value[:0], value...)
}

func (c *Cookie) SetValueBytes(value []byte) {
c.value = append(c.value[:0], value...)
}

func (c *Cookie) SetKey(key string) {
c.key = append(c.key[:0], key...)
}

func (c *Cookie) SetKeyBytes(key []byte) {
c.key = append(c.key[:0], key...)
}

上面幾個(gè)方法的內(nèi)部實(shí)現(xiàn)中,無(wú)一例外,都對(duì) []byte 類(lèi)型的參數(shù)進(jìn)行了復(fù)用。

[]byte 和 string 轉(zhuǎn)換

fasthttp? 專(zhuān)門(mén)提供了 []byte? 和 string? 這兩種常見(jiàn)的數(shù)據(jù)類(lèi)型相互轉(zhuǎn)換的方法 ,避免了 內(nèi)存分配 + 復(fù)制,提升性能。

// s2b_new.go
func b2s(b []byte) string {
return *(*string)(unsafe.Pointer(&b))
}

// b2s_new.go
func s2b(s string) (b []byte) {
bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
bh.Data = sh.Data
bh.Cap = sh.Len
bh.Len = sh.Len
return b
}

高性能的 bytebufferpool

fasthttp? 并沒(méi)有直接使用標(biāo)準(zhǔn)庫(kù)中的 bytes.Buffer? 對(duì)象,而是引用了作者的另外一個(gè)包 valyala/bytebufferpool[2], 這個(gè)包的核心優(yōu)化點(diǎn)是 避免內(nèi)存拷貝 + 底層 byte 切片復(fù)用,感興趣的讀者可以看看官方給出的 基準(zhǔn)測(cè)試結(jié)果[3]。

避免反射

fasthttp? 中的所有 對(duì)象深拷貝? 內(nèi)部實(shí)現(xiàn)中都沒(méi)有使用 反射?,而是手動(dòng)實(shí)現(xiàn)的,這樣可以完全規(guī)避 反射? 帶來(lái)的影響,例如 Cookie 對(duì)象的拷貝實(shí)現(xiàn):

// cookie.go
// Cookie 對(duì)象拷貝實(shí)現(xiàn)
func (c *Cookie) CopyTo(src *Cookie) {
c.Reset()
c.key = append(c.key, src.key...)
c.value = append(c.value, src.value...)
c.expire = src.expire
c.maxAge = src.maxAge
c.domain = append(c.domain, src.domain...)
c.path = append(c.path, src.path...)
c.httpOnly = src.httpOnly
c.secure = src.secure
c.sameSite = src.sameSite
}

從上面的代碼中可以看到,拷貝? 的內(nèi)部實(shí)現(xiàn)就是手動(dòng)挨個(gè)復(fù)制字段,非常 原始 的解決方案。

另外,請(qǐng)求對(duì)象 Request? 和響應(yīng)對(duì)象 Response? 的拷貝實(shí)現(xiàn)和 Cookie 有異曲同工之處:

// client.go
func (req *Request) CopyTo(dst *Request) {
...
}

func (resp *Response) CopyTo(dst *Response) {
...
}

fasthttp 的問(wèn)題

軟件工程沒(méi)有銀彈,高性能的背后必然是以某些條件作為代價(jià)的,fasthttp 的主要問(wèn)題有:

  • ? 降低了代碼可讀性 (如果不了解 fasthttp 的設(shè)計(jì)理念,貿(mào)然讀代碼很可能無(wú)法理解各種方法實(shí)現(xiàn))
  • ? 增加了開(kāi)發(fā)復(fù)雜性,代碼開(kāi)發(fā)量要比使用標(biāo)準(zhǔn)庫(kù)高,對(duì)象復(fù)用導(dǎo)致了 申請(qǐng)/歸還 流程彷佛回到了 C/C++ 語(yǔ)言手動(dòng)管理內(nèi)存模式
  • ? 增加了開(kāi)發(fā)者心智負(fù)擔(dān),如果已經(jīng)習(xí)慣了標(biāo)準(zhǔn)庫(kù)的開(kāi)發(fā)模式,很容易寫(xiě)出 Bug
  • ? 如果業(yè)務(wù)中有 異步? 處理場(chǎng)景,框架核心的 對(duì)象復(fù)用 機(jī)制可能導(dǎo)致各種問(wèn)題,如對(duì)象提前歸還、對(duì)象指針 hang 起、還有更嚴(yán)重的對(duì)象字段被重置后繼續(xù)引用 (這類(lèi)業(yè)務(wù)邏輯問(wèn)題比較難排查)

多核系統(tǒng)的性能優(yōu)化技巧

  • ? 使用 reuseport 監(jiān)聽(tīng) (SO_REUSEPORT 允許在多核服務(wù)器上線(xiàn)性擴(kuò)展服務(wù)器性能,詳細(xì)信息請(qǐng)參閱 這個(gè)鏈接[4] )
  • ? 使用 GOMAXPROCS=1 為每個(gè) CPU 核運(yùn)行一個(gè)單獨(dú)的服務(wù)器實(shí)例 (進(jìn)程和 CPU 綁定)
  • ? 確保多隊(duì)列網(wǎng)卡的中斷均勻分布在 CPU 內(nèi)核之間,詳細(xì)信息請(qǐng)參閱 [這個(gè)鏈接](https://blog.cloudflare.com/how-to-achieve-low-latency/

fasthttp 最佳實(shí)踐

  • ? 盡可能復(fù)用對(duì)象和 []byte buffers, 而不是重新分配
  • ? 使用 []byte 特性技巧
  • ? 使用 sync.Pool 對(duì)象池
  • ? 在生產(chǎn)環(huán)境對(duì)程序進(jìn)行性能分析,go tool pprof --alloc_objects app mem.pprof 通常比 go tool pprof app cpu.pprof 更容易體現(xiàn)性能瓶頸
  • ? 為 hot path 上的代碼編寫(xiě)測(cè)試和基準(zhǔn)測(cè)試
  • ? 避免 []byte 和 string 直接進(jìn)行類(lèi)型轉(zhuǎn)換,因?yàn)檫@可能會(huì)導(dǎo)致 內(nèi)存分配 + 復(fù)制,可以參考 fasthttp 包內(nèi)的 s2b 方法和 b2s 方法
  • ? 定期對(duì)代碼進(jìn)行 競(jìng)態(tài)檢測(cè)[5], 一般會(huì)直接集成到 CI 中
  • ? 使用 quicktemplate 而非 html/template 模板

是否采用 fasthttp

fasthttp? 是為一些高性能邊緣場(chǎng)景設(shè)計(jì)的,如果你的業(yè)務(wù)需要支撐較高的 QPS? 并且保持一致的低延遲時(shí)間,那么采用 fasthttp? 是非常合理的, 反之 fasthttp? 可能并不適合 (增加開(kāi)發(fā)復(fù)雜度和開(kāi)發(fā)者心智負(fù)擔(dān))。大多數(shù)情況下,標(biāo)準(zhǔn)庫(kù) net/http? 是更好的選擇,因?yàn)樗?jiǎn)單易用并且兼容性很高。 如果你的業(yè)務(wù)流量很少,那么兩者之間的 所謂性能差異 幾乎可以忽略。

Reference

  • ? Go 高性能代碼的 30 個(gè) Tips
  • ? valyala/fasthttp[6]
  • ? fasthttp中運(yùn)用哪些go優(yōu)化技巧?
  • ? fasthttp 快在哪里[7]
  • ? fasthttp剖析[8]

引用鏈接

[1]? valyala/fasthttp: ??https://github.com/valyala/fasthttp??

[2]? valyala/bytebufferpool: ??https://github.com/valyala/bytebufferpool??

[3]? 基準(zhǔn)測(cè)試結(jié)果: ??https://omgnull.github.io/go-benchmark/buffer/??

[4]? 這個(gè)鏈接: ??https://www.nginx.com/blog/socket-sharding-nginx-release-1-9-1/??

[5]? 競(jìng)態(tài)檢測(cè): ??https://go.dev/doc/articles/race_detector??

[6]? valyala/fasthttp: ??https://github.com/valyala/fasthttp??

[7]? fasthttp 快在哪里: ??https://xargin.com/why-fasthttp-is-fast-and-the-cost-of-it/??

[8]? fasthttp剖析: https://www.jianshu.com/p/a0e766f8dcb0

責(zé)任編輯:武曉燕 來(lái)源: 洋芋編程
相關(guān)推薦

2024-03-08 07:58:13

QPShttpsync

2016-12-14 12:02:01

StormHadoop大數(shù)據(jù)

2017-02-14 14:20:02

StormHadoop

2022-11-02 08:12:47

TurbopackVite

2017-03-23 14:37:19

WebAssemblyasm.js編程

2011-06-29 09:31:58

3G4G5G

2021-07-28 14:20:13

正則PythonFlashText

2022-10-27 08:31:31

架構(gòu)

2015-01-16 10:43:09

WiGigWiFi

2021-01-21 07:53:29

面試官Promis打印e

2024-03-26 10:13:54

日志引擎SigLens

2025-01-22 08:29:18

索引查詢(xún)優(yōu)化

2025-02-04 17:24:22

2016-08-09 21:18:31

5G4G5G網(wǎng)絡(luò)

2021-03-08 09:05:47

數(shù)據(jù)傳輸新線(xiàn)纜數(shù)據(jù)中心

2020-02-12 15:02:15

人工智能機(jī)器學(xué)習(xí)技術(shù)

2020-02-27 15:44:41

Nginx服務(wù)器反向代理

2024-02-26 21:15:20

Kafka緩存參數(shù)

2023-06-08 18:25:40

Doris場(chǎng)景查詢(xún)

2020-02-27 21:03:30

調(diào)度器架構(gòu)效率
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 毛片网在线观看 | 午夜影院在线免费观看视频 | 深爱激情综合 | 亚洲综合精品 | 国产精品久久777777 | 国产精品成人一区二区三区吃奶 | 国产成人福利在线 | 四虎永久免费影院 | 国产高清久久 | 久久久精品国产 | 日韩和的一区二在线 | 69精品久久久久久 | 国产不卡视频在线 | 黄色片在线观看网址 | 国产精品99久久久久久久久久久久 | 久久精品国产精品青草 | 国产福利精品一区 | 九九爱这里只有精品 | 国产91久久精品一区二区 | 免费精品在线视频 | 91私密视频 | 久久综合一区 | 精品国产一区探花在线观看 | 麻豆久久久久久 | 国产一区 | jav成人av免费播放 | 国产美女网站 | 亚洲精品9999| 久久久久久国产精品免费免费 | 国产一区二区电影网 | 久久精品综合 | 五月天婷婷狠狠 | 欧美一级视频在线观看 | 91资源在线 | 欧美日韩精品在线免费观看 | 国产日韩一区二区三区 | 精品一二 | 国产精品一区二区av | 欧美日韩高清一区二区三区 | 毛片免费观看 | 网络毛片 |