<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Go:你真的了解 timeout 嘛?

          共 5291字,需瀏覽 11分鐘

           ·

          2021-06-24 01:01

          服務(wù)為什么需要 timeout 呢?提前釋放資源

          記得在上家公司時(shí),一個(gè) python 服務(wù)與公網(wǎng)交互,request 庫(kù)發(fā)出去的請(qǐng)求沒有設(shè)置 timeout ... 而且還是個(gè)定時(shí)任務(wù),占用了超多 fd

          同時(shí)微服務(wù)場(chǎng)景下某下游的服務(wù)阻塞卡頓,這樣會(huì)造成他的級(jí)聯(lián)上下游都雪崩了。

          語(yǔ)言層面:對(duì)于使用線程池的語(yǔ)言,會(huì)消耗所有線程,work 不夠用。其實(shí)對(duì)于 go 來說,創(chuàng)建大量 goroutine 也會(huì)有 runtime 開銷的, 只是慢性死亡罷了

          內(nèi)核層面:還有一點(diǎn)超時(shí)配置的必要性,如果某服務(wù)掛了,那么內(nèi)核會(huì)幫忙收尾,根據(jù)情況或走 RST 或走 FIN,訪問者就知道鏈接關(guān)了。但如果主機(jī)掛了,或者中間網(wǎng)絡(luò)設(shè)備掛了,客戶端沒有超時(shí)配置,就只能 tcp keepalive 來判斷死鏈接,按照默認(rèn)內(nèi)核配置語(yǔ)言兩個(gè)多小時(shí)。文末提到 redis 就是例子

          Latency

          業(yè)界都用 P99 分位來衡量服務(wù)的 latency, 即使這樣如果 QPS 非常高,另外 1% 的請(qǐng)求也會(huì)出現(xiàn) long tail. 再來看幾個(gè)不同側(cè)重點(diǎn)的概念:

          Server Side P99 統(tǒng)計(jì)的只是 server handler 處理時(shí)間

          Client P99 =  client framework 時(shí)間 + client 內(nèi)核處理時(shí)間 + 網(wǎng)絡(luò)傳輸時(shí)間 + server 處理時(shí)間

          當(dāng)你發(fā)現(xiàn) latency 比較高,想去 challenge 下游時(shí),請(qǐng)對(duì)好口徑。通常 client p99 > server p99

          這還是普通的 server/client 模式,如果中間涉及了 lb, 或是 mesh 排查問題很要命

          可觀測(cè)性

          現(xiàn)在都是微服務(wù)場(chǎng)景,一個(gè)訂單全鏈路涉及幾十個(gè)服務(wù),查起問題非常困難,所以分布式的 tracing 系統(tǒng)非常重要

          另外現(xiàn)在也都擁抱云原生環(huán)境,如果引入 service mesh 的話更難以排查問題

          一般 tracing 系統(tǒng)都是根據(jù) google 論文 Dapper, a Large-Scale Distributed Systems Tracing Infrastructure[1] 發(fā)展而來的

          除了自己造輪子,主流的有 zipkin[2], opentelemetry[3]

          底層實(shí)現(xiàn)

          定時(shí)器這塊業(yè)務(wù)早有標(biāo)準(zhǔn)實(shí)現(xiàn):小頂堆, 紅黑樹時(shí)間輪. 感興趣的同學(xué)可以搜索相關(guān)文章

          原理不難,但是有公司面試都要求手寫紅黑樹!!!這就過份了吧

          Linux 內(nèi)核和 Nginx 的定時(shí)器采用了 紅黑樹 實(shí)現(xiàn),好多長(zhǎng)連接系統(tǒng)多采用 時(shí)間輪

          Go 使用 小頂堆, 四叉堆,比較矮胖,不是最樸素的二叉堆。

          最早版本只有一個(gè) timer 堆,所以性能非常差,精度也有問題。一般都用戶實(shí)現(xiàn)多堆,或是用時(shí)間輪實(shí)現(xiàn)。這方面的輪子比寫公眾號(hào)的碼農(nóng)都多 ^_^

          后來經(jīng)過優(yōu)化 Go 內(nèi)置多堆實(shí)現(xiàn),每個(gè) P 一個(gè) timer 堆,性能好了很多。注意,Go 的 conn timeout 是通過用戶層 timer 實(shí)現(xiàn)的,而不是內(nèi)核的 setsockopt

          HTTP

          這里要區(qū)分 http1 和 http2, 以前寫過一篇 HOL blocking 的文章,感興趣可以翻下歷史

          Http1 如果超時(shí)到了,那么底層庫(kù)是要關(guān)閉 tcp connection 的,強(qiáng)制丟棄未讀到的數(shù)據(jù),這時(shí)會(huì)產(chǎn)生大量的 timewait, 要注意

          但是對(duì)于 Http2 來說,虛擬出來了 stream, 做到了多路復(fù)用,只要關(guān)閉 stream 即可,底層 socket 還可以正常使用

          對(duì)于 go http 還有一個(gè)坑,可以參考 i/o timeout , 希望你不要踩到這個(gè)net/http包的坑[4]

          func init() {
              tr = &http.Transport{
                  MaxIdleConns: 100,
                  Dial: func(netw, addr string) (net.Conn, error) {
                      conn, err := net.DialTimeout(netw, addr, time.Second*2//設(shè)置建立連接超時(shí)
                      if err != nil {
                          return nil, err
                      }
                      err = conn.SetDeadline(time.Now().Add(time.Second * 3)) //設(shè)置發(fā)送接受數(shù)據(jù)超時(shí)
                      if err != nil {
                          return nil, err
                      }
                      return conn, nil
                  },
              }
          }

          上面代碼是錯(cuò)誤使用,這個(gè)導(dǎo)致每次 conn 連接后只設(shè)置一次超時(shí)時(shí)間

              client := &http.Client{
                  Transport: tr,
                  Timeout: 3*time.Second,  // 超時(shí)加在這里,是每次調(diào)用的超時(shí)
              }

          正確的應(yīng)該在 http.Client 結(jié)構(gòu)體里設(shè)置,感興趣的去參考全文吧

          另外服務(wù)端也要設(shè)置 timeout, 以防把服務(wù)端壓跨,請(qǐng)參考 So you want to expose Go on the Internet[5]

            srv := &http.Server{
              ReadTimeout:  5 * time.Second,
              WriteTimeout: 10 * time.Second,
              IdleTimeout:  120 * time.Second,
              TLSConfig:    tlsConfig,
              Handler:      serveMux,
          }
          log.Println(srv.ListenAndServeTLS(""""))

          數(shù)據(jù)庫(kù)相關(guān)

          做為 CRUD Boy, 經(jīng)常和 DB 打交道,讓我們來看下常見的超時(shí)設(shè)置與坑

          Redis 服務(wù)端要注意兩個(gè)參數(shù):timeouttcp-keepalive

          其中 timeout 用于關(guān)閉 idle client conn, 默認(rèn)是 0 不關(guān)閉,為了減少服務(wù)端 fd 占用,建議設(shè)置一個(gè)合理的值

          tcp-keepalive 在很早的 redis 版本是不開啟的,這樣經(jīng)常會(huì)遇到因?yàn)榫W(wǎng)格抖動(dòng)等原因,socket conn 一直存在,但實(shí)際上 client 早己經(jīng)不存在的情況

          Redis Client 實(shí)現(xiàn)有一個(gè)重大問題,對(duì)于集群環(huán)境下,有些請(qǐng)求會(huì)做 Redirect 跳轉(zhuǎn),默認(rèn)是 16 次,如果 tcp read timeout 設(shè)置了 100ms, 那總時(shí)間很可能超過了 1s

          這就是一直強(qiáng)調(diào)的問題,tcp timeout 設(shè)置不代表實(shí)際的調(diào)用時(shí)間,因?yàn)闃I(yè)務(wù)層會(huì)多次調(diào)用 socket 讀寫。最好外面包一層 context 或是 circuit breaker

          MySQL 也同樣服務(wù)端可以設(shè)置 MAX_EXECUTION_TIME 來控制 sql 執(zhí)行時(shí)間。不同發(fā)行版本還不一樣,有的只支持 select, 有的同時(shí)支持 dml ddl ...

          其它

          Q: 有同事問 timeout 與 sla 什么關(guān)系?

          A: 要大于 sla. 沒有經(jīng)過 toB 業(yè)務(wù)的重錘,感觸不深,有朋友了解的可以留言講講 toB 業(yè)務(wù)的玩法

          Q: 如何傳遞 timeout ?

          A: 一般都是框架層傳遞的,比如 grpc 會(huì)在 header 里傳遞服務(wù)的 timeout, 每經(jīng)過一個(gè) backend, 減去相應(yīng)的耗時(shí)

          Q: 依賴的下游出現(xiàn)大量超時(shí),應(yīng)該如何處理?

          A: 要做到 fast fail, 一定得有降級(jí) (circuit breaker 熔斷)措施,否則會(huì)拖垮整條鏈路。

          小結(jié)

          這次分享就這些,以后面還會(huì)分享更多的內(nèi)容,如果感興趣,可以關(guān)注并點(diǎn)擊左下角的分享轉(zhuǎn)發(fā)哦(:

          參考資料

          [1]

          Dapper, a Large-Scale Distributed Systems Tracing Infrastructure: https://research.google/pubs/pub36356/,

          [2]

          zipkin: https://zipkin.io/,

          [3]

          opentelemetry: https://opentelemetry.io/docs/concepts/distributions/,

          [4]

          i/o timeout , 希望你不要踩到這個(gè)net/http包的坑: https://mp.weixin.qq.com/s/UBiZp2Bfs7z1_mJ-JnOT1Q,

          [5]

          So you want to expose Go on the Internet: https://blog.cloudflare.com/exposing-go-on-the-internet/,



          推薦閱讀


          福利

          我為大家整理了一份從入門到進(jìn)階的Go學(xué)習(xí)資料禮包,包含學(xué)習(xí)建議:入門看什么,進(jìn)階看什么。關(guān)注公眾號(hào) 「polarisxu」,回復(fù) ebook 獲取;還可以回復(fù)「進(jìn)群」,和數(shù)萬 Gopher 交流學(xué)習(xí)。

          瀏覽 65
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产黄色视频在线免费观看 | 人妻黄色视频 | 18禁www网站 | 哪里有免费的av 男女wwwwww | 欧美性爱免费在线视频海量版 |