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

Go Udp 的高性能優化

開發 后端
我們知道應用程序之間的網絡傳輸會存在粘包半包的問題。該問題的由來我這里就不描述了,大家去搜吧。使用 tcp 會存在該問題,而 udp 是不存在該問題的。

[[417346]]

本文轉載自微信公眾號「碼農桃花源」,作者峰云就她了。轉載本文請聯系碼農桃花源公眾號。

前段時間(已經是 2 年前了??)優化了 golang udp client 和 server 的性能問題,我在這里簡單描述下 udp 服務的優化過程。

當然,udp 性能本就很高,就算不優化,也輕易可以到幾十萬的 qps,但我們想更好的優化 go udp server 和 client。

UDP 存在粘包半包問題?

我們知道應用程序之間的網絡傳輸會存在粘包半包的問題。該問題的由來我這里就不描述了,大家去搜吧。使用 tcp 會存在該問題,而 udp 是不存在該問題的。

為啥? tcp 是無邊界的,tcp 是基于流傳輸的,tcp 報頭沒有長度這個變量,而 udp 是有邊界的,基于消息的,是可以解決粘包問題的。udp 協議里有 16 位來描述包的大小,16 位決定他的數字最大數字是 65536,除去 udp 頭和 ip 頭的大小,最大的包差不多是 65507 byte。

但根據我們的測試,udp 并沒有完美的解決應用層粘包半包的問題。如果你的 go udp server 的讀緩沖是 1024,那么 client 發送的數據不能超過 server read buf 定義的 1024 byte,不然還是要處理半包了。如果發送的數據小于 1024 byte,倒是不會出現粘包的問題。

  1. // xiaorui.cc 
  2. buf := make([]byte, 1024) 
  3. for { 
  4.     n, _ := ServerConn.Read(buf[0:]) 
  5.     if string(buf[0:n]) != s { 
  6.         panic(...) 
  7. ... 

在 Linux下 借助 strace 發現 syscall read fd 的時候,最大只獲取 1024 個字節。這個 1024 就是上面配置的讀緩沖大小。

  1. // xiaorui.cc 
  2.  
  3. [pid 25939] futex(0x56db90, FUTEX_WAKE, 1) = 1 
  4. [pid 25939] read(3, "Introduction... 隱藏... overview of IPython'", 1024) = 1024 
  5. [pid 25939] epoll_ctl(4, EPOLL_CTL_DEL, 3, {0, {u32=0, u64=0}}) = 0 
  6. [pid 25939] close(3  
  7. [pid 25940] <... restart_syscall resumed> ) = 0 
  8. [pid 25939] <... close resumed> )       = 0 
  9. [pid 25940] clock_gettime(CLOCK_MONOTONIC, {19280781, 509925143}) = 0 
  10. [pid 25939] pselect6(0, NULLNULLNULL, {0, 1000000}, 0  
  11. [pid 25940] pselect6(0, NULLNULLNULL, {0, 20000}, 0) = 0 (Timeout) 
  12. [pid 25940] clock_gettime(CLOCK_MONOTONIC, {19280781, 510266460}) = 0 
  13. [pid 25940] futex(0x56db90, FUTEX_WAIT, 0, {60, 0}  

下面是 golang 里 socket fd read 的源碼,可以看到你傳入多大的 byte 數組,他就 syscall read 多大的數據。

  1. // xiaorui.cc 
  2. func read(fd int, p []byte) (n int, err error) { 
  3.     var _p0 unsafe.Pointer 
  4.     if len(p) > 0 { 
  5.         _p0 = unsafe.Pointer(&p[0]) 
  6.     } else { 
  7.         _p0 = unsafe.Pointer(&_zero) 
  8.     } 
  9.     r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p))) 
  10.     n = int(r0) 
  11.     if e1 != 0 { 
  12.         err = errnoErr(e1) 
  13.     } 
  14.     return 

http2 為毛比 http1 的協議解析更快,是因為 http2 實現了 header 的 hpack 編碼協議。thrift 為啥比 grpc 快?單單對比協議結構體來說,thrift 和 protobuf 的性能半斤八兩,但對比網絡應用層協議來說,thrift 要更快。因為grpc是在 http2 上跑的,grpc server 不僅要解析 http2 header,還要解析 http2 body,這個 body 就是 protobuf 數據。

所以說,高效的應用層協議也是高性能服務的重要的一個標準。我們先前使用的是自定義的 TLV 編碼,t 是類型,l 是 length,v 是數據。一般解決網絡協議上的數據完整性差不多是這個思路。當然,我也是這么搞得。

如何優化 udp 應用協議上的開銷?

上面已經說了,udp 在合理的 size 情況下是不需要依賴應用層協議解析包問題。那么我們只需要在 client 端控制 send 包的大小,server 端控制接收大小,就可以節省應用層協議帶來的性能高效。??別小看應用層協議的 cpu 消耗!

解決 golang udp 的鎖競爭問題

在 udp 壓力測試的時候,發現 client 和 server 都跑不滿 cpu 的情況。開始以為是 golang udp server 的問題,去掉所有相關的業務邏輯,只是單純的做 atomic 計數,還是跑不滿 cpu。通過 go tool pprof 的函數調用圖以及火焰圖,看不出問題所在。嘗試使用 iperf 進行 udp 壓測,golang udp server 的壓力直接干到了滿負載??梢哉f是壓力源不足。

那么 udp 性能上不去的問題看似明顯了,應該是 golang udp client 的問題了。我嘗試在 go udp client 里增加了多協程寫入,10 個 goroutine,100 個 goroutine,500 個 goroutine,都沒有好的明顯的提升效果,而且性能抖動很明顯。??

進一步排查問題,通過 lsof 分析 client 進程的描述符列表,client 連接 udp server 只有一個連接。也就是說,500 個協程共用一個連接。接著使用 strace 做 syscall 系統調用統計,發現 futex 和 pselect6 系統調用特別多,這一看就是存在過大的鎖競爭。翻看 golang net 源代碼,果然發現 golang 在往 socket fd 寫入時,存在寫鎖競爭。

TODO 圖片

  1. // xiaorui.cc 
  2.  
  3. // Write implements io.Writer. 
  4. func (fd *FD) Write(p []byte) (int, error) { 
  5.     if err := fd.writeLock(); err != nil { 
  6.         return 0, err 
  7.     } 
  8.     defer fd.writeUnlock() 
  9.     if err := fd.pd.prepareWrite(fd.isFile); err != nil { 
  10.         return 0, err 
  11.     } 

怎么優化鎖競爭?

實例化多個 udp 連接到一個數組池子里,在客戶端代碼里隨機使用 udp 連接。這樣就能減少鎖的競爭了。

總結

udp 性能調優的過程就是這樣子了。簡單說就兩個點:一個是消除應用層協議帶來的性能消耗,再一個是 golang socket 寫鎖帶來的競爭。

 

當我們一些性能問題時,多使用 perf、strace 功能,再配合 golang pprof 分析火焰圖來分析問題。實在不行,直接干 golang 源碼。

 

責任編輯:武曉燕 來源: 碼農桃花源
相關推薦

2022-03-21 14:13:22

Go語言編程

2024-12-25 14:03:03

2019-03-01 11:03:22

Lustre高性能計算

2023-03-10 09:11:52

高性能Go堆棧

2021-05-27 10:02:57

Go緩存數據

2019-05-21 09:40:47

Elasticsear高性能 API

2024-04-28 10:17:30

gnetGo語言

2023-08-29 15:10:04

持續性能優化開發

2009-01-05 10:00:11

JSP優化Servlet性能優化

2014-03-19 14:34:06

JQuery高性能

2018-03-30 18:17:10

MySQLLinux

2018-09-18 17:20:14

MySQL優化數據庫

2023-12-14 08:01:08

事件管理器Go

2023-12-01 07:06:14

Go命令行性能

2019-03-14 15:38:19

ReactJavascript前端

2023-11-01 11:59:13

2023-12-30 18:35:37

Go識別應用程序

2021-08-04 09:33:22

Go 性能優化

2017-04-25 16:20:10

頁面優化滾動優化

2025-01-13 13:00:00

Go網絡框架nbio
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产免费看 | 日本午夜在线视频 | 怡红院成人在线视频 | 男女午夜激情视频 | 在线不卡av| 美女一级毛片 | 中文字幕亚洲无线 | 黄视频免费观看 | 美女天天操 | 久草在线青青草 | 欧美日韩精品久久久免费观看 | 亚洲一区二区三区在线观看免费 | 国产在线观看网站 | 成人在线中文字幕 | 一色桃子av一区二区 | 欧美日一区二区 | 精品国产乱码久久久久久久久 | 日韩欧美第一页 | 精品一区二区电影 | 久久精品国产精品青草 | 国产欧美在线观看 | 黄色一级大片在线免费看产 | 羞羞网站免费 | 亚洲精品乱码久久久久久蜜桃91 | 成人av在线播放 | 国产片侵犯亲女视频播放 | 亚洲午夜精品一区二区三区他趣 | 中文字幕亚洲免费 | 亚洲乱码一区二区三区在线观看 | 最新国产精品精品视频 | 91视频正在播放 | 不卡一区二区三区四区 | 亚洲国产成人av好男人在线观看 | 一区二区免费视频 | 亚洲麻豆 | 国产成人免费在线 | 91精品国产综合久久久动漫日韩 | 日韩在线精品 | 免费毛片网站在线观看 | 日韩综合在线 | 在线伊人 |