Improve HTTP request tracing #866
Labels
enhancement
evaluation needed
proposal needs to be validated or tested before fully implementing it in k6
new-http
issues that would require (or benefit from) a new HTTP API
refactor
Currently we use Go's
net/http/httptrace
library to save nanosecond timestamps of the different events that happen during an HTTP request. This mostly works, but due to quirks of the Go standard library (mostly related to HTTP/2 requests), some corner cases aren't especially well handled by the current nanosec-timestamps-with-atomicsTracer
implementation, even after the fixes (1, 2) we recently did.Go's standard library sometimes tries to retry HTTP/2 requests: stdlib code,
golang.org/x/net/http2
(which we need for itsConfigureTransport()
method because we have to be able to support a custom TLS configuration in theTransport
)... To me this seems like a strange behavior to force (it doesn't look configurable at all, so we can't disable it), seemingly at odds with some of the principles ofnet/http/httptrace
( ClientTrace currently traces a single HTTP request & response during a single round trip and has no hooks that span a series of redirected requests ), so we'll have to figure out a way to deal with it... When there are retries, we likely will even have to emit more than one set ofhttp_req_*
k6 metrics.One potential way to do that would be to implement a more efficient way to save all of the events a the new
Tracer
(i.e newhttptrace.ClientTrace
implementation) receives. We did that in the debug branch we used to trace different corner cases, but it was very inefficient. It has to be benchmarked, but probably a simple slice with a lock will likely be fast enough. Alternatively, other more complicated options like lock-free buffers also exist if we need more performance. In any case, once we have all of the events saved in a list, we can sort them by their time and build a state machine that goes backwards from the end of the requests to the first event and emits 1 or more (or 0, if we ignore incomplete requests?) sets ofhttp_req_{blocked,connecting,tls_handhaking,sending,waiting,receiving,...}
metrics.Here are some dumps from the aforementioned tracing in the debug branch that illustrate why the current simple calculations with atomics aren't the sufficient:
We got a connection without making it, but it wasn't reused 😕... Upcoming Golang issue about this behavior...
Again:
Quite a few events there...
Started making a connection, but an already established one got freed and we'll reuse it instead!
Once you intentionally break and/or stress your network, you start to see all sorts of strange combinations of events like these...
The text was updated successfully, but these errors were encountered: