Nov 20, 2019

[Go] High performancei, design lesson from FastHttp opensource project

Working on my stealth mode library project - vact,
there are several design calls can follow through the fasthttp project.

Jot it down here.

Server:
https://github.com/valyala/fasthttp

Client:
https://godoc.org/github.com/valyala/fasthttp#Client
HostClient
https://godoc.org/github.com/valyala/fasthttp#HostClient
PipelineClient
https://godoc.org/github.com/valyala/fasthttp#PipelineClient
(Head Of Line blocking issue due to it's using pipelined requests)

Reference:
http/1.0 pipelining
https://en.wikipedia.org/wiki/HTTP_pipelining
http/2.0
https://en.wikipedia.org/wiki/HTTP/2
QUIC
https://en.wikipedia.org/wiki/QUIC


Tips:
  1. Re-use object
    func fetchURLS(ch <-chan string) {
        var r Response
        for url := range ch {
            Get(url, &r)
            processResponse(&r)
            // reset response object, so it may be re-used
            r.Reset()
        }
    }
    
  2. Do not put object into pool if some header/tag is present.
    Close/re-cycle such connection/object instead.
  3. Server may stop responding, so goroutines calling Get() may
    pile up indefinitely.
    One way to detect it:
    (Check graceful shutdown: http://vsdmars.blogspot.com/2019/02/golangdesign-graceful-shutdown.html)
  4. func GetTimeout(url string, timeout time.Duration, resp *Response) {
        select {
            case concurrencyCh <- struct{}{}
            default:
            // too many goroutines are blocked in Get(), return back to caller
        }
        ch := make(chan struct{})
    
        go func() {
            Get(url, resp)
            <-concurrencyCh
            close(ch)
        }()
    
        select {
            case <-ch:
            case <-time.After(timeout):
        }
    }
  5. For every kind of network connection, setup a timeout!
    It's been used in TCP as well.
  6. conn := dialHost(url)
    conn.SetReadDeadline(time.Now().Add(readTimeout))
    conn.SetWriteDeadline(time.Now().Add(writeTimeout))
    
  7. Should the connection be closed on timed out request?
    Only if you want to DoS the remote server, otherwise, let it timeout.
  8. Pool size should ALWAYS be limited.
  9. After connection spike, there could be connection left overs.
    Limit the connection life time.
  10. Each tcp dial will trigger a DNS request.
    We could cache host -> ip mapping for a period of time, or
    rely on host's dns cache
  11. http client can be smart, dial with round-robin to each ip behind single
    domain name.
  12. Each dial should have timeout.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.