k6 icon indicating copy to clipboard operation
k6 copied to clipboard

Negative http_req_receiving values

Open na-- opened this issue 3 years ago • 13 comments

Reported in https://stackoverflow.com/questions/66368090/k6-https-k6-io-tool-reports-negative-http-req-duration-time with k6 v0.30.0:

   checks.....................: 0.00%  ✓ 0     ✗ 133631
   data_received..............: 18 MB  1.8 MB/s
   data_sent..................: 10 MB  1.0 MB/s
   http_req_blocked...........: avg=47.03µs  min=13.6µs     med=20.8µs  max=46.11ms  p(90)=27.1µs  p(95)=33.5µs 
   http_req_connecting........: avg=3.96µs   min=0s         med=0s      max=34.35ms  p(90)=0s      p(95)=0s     
 ✓ http_req_duration..........: avg=14.05ms  min=-15.7758ms med=11.71ms max=163.09ms p(90)=27.25ms p(95)=33.93ms
   http_req_receiving.........: avg=108.11µs min=-34.2818ms med=48.4µs  max=87.86ms  p(90)=83.3µs  p(95)=112.6µs
   http_req_sending...........: avg=47.79µs  min=11.6µs     med=20.5µs  max=56.39ms  p(90)=32.8µs  p(95)=45.6µs 
   http_req_tls_handshaking...: avg=0s       min=0s         med=0s      max=0s       p(90)=0s      p(95)=0s     
   http_req_waiting...........: avg=13.89ms  min=0s         med=11.56ms max=163.01ms p(90)=27.02ms p(95)=33.66ms
   http_reqs..................: 133631 13350.537278/s
   iteration_duration.........: avg=14.9ms   min=287.4µs    med=12.32ms max=227.44ms p(90)=28.72ms p(95)=35.79ms
   iterations.................: 133631 13350.537278/s
   vus........................: 200    min=200 max=200 
   vus_max....................: 200    min=200 max=200 

Previously, we've had issues like this with HTTP/2 measurements (e.g. the server starts returning a response before it has completely processes the whole request we're sending it) or with strange connection reuse happened (e.g. an already established network connection gets freed and immediately reused by the HTTP client while it was in the middle of establishing a new connection). I thought we had fixed all of these issues, but this looks like it could be the former.

na-- avatar Feb 25 '21 12:02 na--

hello, thanks for a prompt response I have added a few details and attached docker-compose file to reproduce the issue here https://github.com/ludenus/k6-issue-1872

ludenus avatar Feb 25 '21 13:02 ludenus

I ran the example repo on my machine and couldn't reproduce the issue :confused: First I somewhat modified the script to be able to run it with 2000 VUs on my laptop, so I ran this with K6_COMPATIBILITY_MODE: "base" (docs):

var http = require('k6/http');
var check = require('k6').check;

exports.options = {
  thresholds: {
    http_req_duration: ['avg < 200', 'p(99)<1000', 'p(99.999)<1000'],
  },
};

exports.default = function () {
  var res = http.get('http://pong/ping/k6');
  check(res, {
    'is status 200': function(r) { return r.status === 200; },
    'is duration <= 1000ms': function(r) { return r.http_req_duration < 1000; },
  });
}

And it resulted in this:

k6_1    |      checks.....................: 50.00%  ✓ 1395838 ✗ 1395838
k6_1    |      data_received..............: 190 MB  1.9 MB/s
k6_1    |      data_sent..................: 108 MB  1.1 MB/s
k6_1    |      http_req_blocked...........: avg=217.2µs  min=1.87µs   med=3.55µs   max=354.11ms p(90)=4.57µs   p(95)=5.23µs  
k6_1    |      http_req_connecting........: avg=90.13µs  min=0s       med=0s       max=163.36ms p(90)=0s       p(95)=0s      
k6_1    |    ✓ http_req_duration..........: avg=113.41ms min=121.46µs med=101.23ms max=827.13ms p(90)=159.74ms p(95)=246.7ms 
k6_1    |      http_req_receiving.........: avg=796.46µs min=12.69µs  med=20.2µs   max=398.31ms p(90)=39.55µs  p(95)=203.49µs
k6_1    |      http_req_sending...........: avg=160.83µs min=5.74µs   med=8.29µs   max=412.5ms  p(90)=15.94µs  p(95)=67.64µs 
k6_1    |      http_req_tls_handshaking...: avg=0s       min=0s       med=0s       max=0s       p(90)=0s       p(95)=0s      
k6_1    |      http_req_waiting...........: avg=112.46ms min=85.2µs   med=101.02ms max=578.31ms p(90)=158.68ms p(95)=243.82ms
k6_1    |      http_reqs..................: 1395838 13942.148485/s
k6_1    |      iteration_duration.........: avg=142.51ms min=1.43ms   med=115.59ms max=864.27ms p(90)=249.44ms p(95)=318.89ms
k6_1    |      iterations.................: 1395838 13942.148485/s
k6_1    |      vus........................: 1       min=1     max=2000 
k6_1    |      vus_max....................: 2000    min=2000  max=2000 

Them I ran the original, exactly as it is in the repo, just with 200 VUs, and got this:

k6_1    |      checks.....................: 50.00%  ✓ 1304842 ✗ 1304842
k6_1    |      data_received..............: 178 MB  1.8 MB/s
k6_1    |      data_sent..................: 100 MB  1.0 MB/s
k6_1    |      http_req_blocked...........: avg=9.56µs  min=1.8µs   med=3.26µs  max=33.71ms  p(90)=4.58µs  p(95)=5.35µs 
k6_1    |      http_req_connecting........: avg=518ns   min=0s      med=0s      max=11.31ms  p(90)=0s      p(95)=0s     
k6_1    |    ✓ http_req_duration..........: avg=13.17ms min=89.44µs med=10.91ms max=142.08ms p(90)=26.46ms p(95)=31.67ms
k6_1    |      http_req_receiving.........: avg=76.3µs  min=9.88µs  med=20.5µs  max=106.79ms p(90)=34.76µs p(95)=47.87µs
k6_1    |      http_req_sending...........: avg=23µs    min=4.97µs  med=7.99µs  max=76.18ms  p(90)=14.66µs p(95)=18.83µs
k6_1    |      http_req_tls_handshaking...: avg=0s      min=0s      med=0s      max=0s       p(90)=0s      p(95)=0s     
k6_1    |      http_req_waiting...........: avg=13.07ms min=67.78µs med=10.83ms max=141.78ms p(90)=26.3ms  p(95)=31.46ms
k6_1    |      http_reqs..................: 1304842 13022.728609/s
k6_1    |      iteration_duration.........: avg=15.33ms min=139.7µs med=12.16ms max=270.02ms p(90)=29.35ms p(95)=36.2ms 
k6_1    |      iterations.................: 1304842 13022.728609/s
k6_1    |      vus........................: 200     min=200   max=200  
k6_1    |      vus_max....................: 200     min=200   max=200  

I ran the second test a few more times, just to be sure, similar results - no negative http_req_receiving... :confused: @ludenus, how reproducible is the problem on your machine? I am running on Linux, so maybe this has something to do with Docker networking on Macs maybe? :man_shrugging:

na-- avatar Feb 25 '21 22:02 na--

hello @na-- I have just reproduced the issue with the script you propose and --compatibility-mode=base k6 option From 10 measurements I get 6 that contain a negative number for one of the http_req_receiving or http_req_sending metric (sometimes they both are negative).

k6_1    | running (1m40.1s), 0000/2000 VUs, 1106397 complete and 0 interrupted iterations
k6_1    | default ✓ [ 100% ] 2000 VUs  1m40s
k6_1    | 
k6_1    |      ✓ is status 200
k6_1    |      ✗ is duration <= 1000ms
k6_1    |       ↳  0% — ✓ 0 / ✗ 1106397
k6_1    | 
k6_1    |      checks.....................: 50.00%  ✓ 1106397 ✗ 1106397
k6_1    |      data_received..............: 150 MB  1.5 MB/s
k6_1    |      data_sent..................: 85 MB   852 kB/s
k6_1    |      http_req_blocked...........: avg=347.54µs min=0s         med=22.7µs   max=1.2s     p(90)=30.2µs   p(95)=37.7µs  
k6_1    |      http_req_connecting........: avg=274.73µs min=0s         med=0s       max=1.19s    p(90)=0s       p(95)=0s      
k6_1    |    ✓ http_req_duration..........: avg=106.12ms min=79.4µs     med=100.45ms max=714.36ms p(90)=158.85ms p(95)=188.56ms
k6_1    |      http_req_receiving.........: avg=1.12ms   min=-34.5252ms med=59µs     max=493.26ms p(90)=139µs    p(95)=309µs   
k6_1    |      http_req_sending...........: avg=480.45µs min=-34.525ms  med=23.8µs   max=448.33ms p(90)=42.7µs   p(95)=100.8µs 
k6_1    |      http_req_tls_handshaking...: avg=0s       min=0s         med=0s       max=0s       p(90)=0s       p(95)=0s      
k6_1    |      http_req_waiting...........: avg=104.51ms min=0s         med=99.68ms  max=604.5ms  p(90)=156.26ms p(95)=183.64ms
k6_1    |      http_reqs..................: 1106397 11057.867627/s
k6_1    |      iteration_duration.........: avg=173.81ms min=560.8µs    med=154ms    max=1.53s    p(90)=287.87ms p(95)=355.22ms
k6_1    |      iterations.................: 1106397 11057.867627/s
k6_1    |      vus........................: 1658    min=1658  max=2000 
k6_1    |      vus_max....................: 2000    min=2000  max=2000 
k6_1    | 
perf_k6_1 exited with code 0

I will recheck on Linux host later and let you know.

ludenus avatar Feb 26 '21 09:02 ludenus

@ludenus can you please run your test again, but with this script:

var http = require('k6/http');
var check = require('k6').check;

exports.options = {
    thresholds: {
        http_req_duration: ['avg < 200', 'p(99)<1000', 'p(99.999)<1000'],
    },
};

exports.default = function () {
    var resp = http.get('http://pong/ping/k6');
    var ok = check(resp, {
        'is status 200': function (r) { return r.status === 200; },
        'is http_req_receiving >= 0': function (r) { return r.timings.receiving >= 0; },
    });
    if (!ok) {
        console.log(JSON.stringify(resp, null, 4));
    }
}

it should print the details of every request-response where http_req_receiving was less than zero.

na-- avatar Feb 26 '21 09:02 na--

sure, here it is

√  ~/wrk/perf  
% docker-compose -f ./docker-compose.k6.yaml up  
Creating network "perf_default" with the default driver
Creating perf_pong_1 ... done
Creating perf_k6_1   ... done
Attaching to perf_pong_1, perf_k6_1
pong_1  | Now listening on: http://localhost:80
pong_1  | Application started. Press CTRL+C to shut down.
k6_1    | 
k6_1    |           /\      |‾‾| /‾‾/   /‾‾/   
k6_1    |      /\  /  \     |  |/  /   /  /    
k6_1    |     /  \/    \    |     (   /   ‾‾\  
k6_1    |    /          \   |  |\  \ |  (‾)  | 
k6_1    |   / __________ \  |__| \__\ \_____/ .io
k6_1    | 
k6_1    |   execution: local
k6_1    |      script: /script.js
k6_1    |      output: -
k6_1    | 
k6_1    |   scenarios: (100.00%) 1 scenario, 2000 max VUs, 2m10s max duration (incl. graceful stop):
k6_1    |            * default: 2000 looping VUs for 1m40s (gracefulStop: 30s)
k6_1    | 
k6_1    | 
k6_1    | running (0m00.3s), 2000/2000 VUs, 142 complete and 0 interrupted iterations
k6_1    | default   [   0% ] 2000 VUs  0m00.3s/1m40s

...

k6_1    | 
k6_1    | running (0m36.3s), 2000/2000 VUs, 398661 complete and 0 interrupted iterations
k6_1    | default   [  36% ] 2000 VUs  0m36.3s/1m40s
k6_1    | time="2021-02-26T09:15:11Z" level=info msg="{\n    \"remote_ip\": \"172.19.0.2\",\n    \"remote_port\": 80,\n    \"url\": \"http://pong/ping/k6\",\n    \"status\": 200,\n    \"status_text\": \"200 OK\",\n    \"proto\": \"HTTP/1.1\",\n    \"headers\": {\n        \"Content-Type\": \"application/json; charset=UTF-8\",\n        \"Date\": \"Fri, 26 Feb 2021 09:15:11 GMT\",\n        \"Content-Length\": \"13\"\n    },\n    \"cookies\": {},\n    \"body\": \"{\\\"pong\\\":\\\"k6\\\"}\",\n    \"timings\": {\n            \"duration\": 81.4798,\n            \"blocked\": 0.0213,\n            \"looking_up\": 0,\n            \"connecting\": 0,\n            \"tls_handshaking\": 0,\n            \"sending\": 0.0238,\n            \"waiting\": 92.5957,\n            \"receiving\": -11.1397\n        },\n    \"tls_version\": \"\",\n    \"tls_cipher_suite\": \"\",\n    \"ocsp\": {\n            \"produced_at\": 0,\n            \"this_update\": 0,\n            \"next_update\": 0,\n            \"revoked_at\": 0,\n            \"revocation_reason\": \"\",\n            \"status\": \"\"\n        },\n    \"error\": \"\",\n    \"error_code\": 0,\n    \"request\": {\n            \"method\": \"GET\",\n            \"url\": \"http://pong/ping/k6\",\n            \"headers\": {\n                \"User-Agent\": [\n                    \"k6/0.30.0 (https://k6.io/)\"\n                ]\n            },\n            \"body\": \"\",\n            \"cookies\": {}\n        }\n}" source=console
k6_1    | time="2021-02-26T09:15:12Z" level=info msg="{\n    \"remote_ip\": \"172.19.0.2\",\n    \"remote_port\": 80,\n    \"url\": \"http://pong/ping/k6\",\n    \"status\": 200,\n    \"status_text\": \"200 OK\",\n    \"proto\": \"HTTP/1.1\",\n    \"headers\": {\n        \"Content-Type\": \"application/json; charset=UTF-8\",\n        \"Date\": \"Fri, 26 Feb 2021 09:15:11 GMT\",\n        \"Content-Length\": \"13\"\n    },\n    \"cookies\": {},\n    \"body\": \"{\\\"pong\\\":\\\"k6\\\"}\",\n    \"timings\": {\n            \"duration\": 42.0096,\n            \"blocked\": 0.0238,\n            \"looking_up\": 0,\n            \"connecting\": 0,\n            \"tls_handshaking\": 0,\n            \"sending\": 0.0381,\n            \"waiting\": 69.6788,\n            \"receiving\": -27.7073\n        },\n    \"tls_version\": \"\",\n    \"tls_cipher_suite\": \"\",\n    \"ocsp\": {\n            \"produced_at\": 0,\n            \"this_update\": 0,\n            \"next_update\": 0,\n            \"revoked_at\": 0,\n            \"revocation_reason\": \"\",\n            \"status\": \"\"\n        },\n    \"error\": \"\",\n    \"error_code\": 0,\n    \"request\": {\n            \"method\": \"GET\",\n            \"url\": \"http://pong/ping/k6\",\n            \"headers\": {\n                \"User-Agent\": [\n                    \"k6/0.30.0 (https://k6.io/)\"\n                ]\n            },\n            \"body\": \"\",\n            \"cookies\": {}\n        }\n}" source=console
k6_1    | 
k6_1    | running (0m37.2s), 2000/2000 VUs, 410673 complete and 0 interrupted iterations
k6_1    | default   [  37% ] 2000 VUs  0m37.3s/1m40s
k6_1    | time="2021-02-26T09:15:12Z" level=info msg="{\n    \"remote_ip\": \"172.19.0.2\",\n    \"remote_port\": 80,\n    \"url\": \"http://pong/ping/k6\",\n    \"status\": 200,\n    \"status_text\": \"200 OK\",\n    \"proto\": \"HTTP/1.1\",\n    \"headers\": {\n        \"Date\": \"Fri, 26 Feb 2021 09:15:11 GMT\",\n        \"Content-Length\": \"13\",\n        \"Content-Type\": \"application/json; charset=UTF-8\"\n    },\n    \"cookies\": {},\n    \"body\": \"{\\\"pong\\\":\\\"k6\\\"}\",\n    \"timings\": {\n            \"duration\": 88.9084,\n            \"blocked\": 0.0242,\n            \"looking_up\": 0,\n            \"connecting\": 0,\n            \"tls_handshaking\": 0,\n            \"sending\": 0.0232,\n            \"waiting\": 105.644,\n            \"receiving\": -16.7588\n        },\n    \"tls_version\": \"\",\n    \"tls_cipher_suite\": \"\",\n    \"ocsp\": {\n            \"produced_at\": 0,\n            \"this_update\": 0,\n            \"next_update\": 0,\n            \"revoked_at\": 0,\n            \"revocation_reason\": \"\",\n            \"status\": \"\"\n        },\n    \"error\": \"\",\n    \"error_code\": 0,\n    \"request\": {\n            \"method\": \"GET\",\n            \"url\": \"http://pong/ping/k6\",\n            \"headers\": {\n                \"User-Agent\": [\n                    \"k6/0.30.0 (https://k6.io/)\"\n                ]\n            },\n            \"body\": \"\",\n            \"cookies\": {}\n        }\n}" source=console
k6_1    | 
k6_1    | running (0m38.2s), 2000/2000 VUs, 421529 complete and 0 interrupted iterations
k6_1    | default   [  38% ] 2000 VUs  0m38.3s/1m40s

...

k6_1    | 
k6_1    | running (1m06.2s), 2000/2000 VUs, 699576 complete and 0 interrupted iterations
k6_1    | default   [  66% ] 2000 VUs  1m06.3s/1m40s
k6_1    | time="2021-02-26T09:15:41Z" level=info msg="{\n    \"remote_ip\": \"172.19.0.2\",\n    \"remote_port\": 80,\n    \"url\": \"http://pong/ping/k6\",\n    \"status\": 200,\n    \"status_text\": \"200 OK\",\n    \"proto\": \"HTTP/1.1\",\n    \"headers\": {\n        \"Content-Type\": \"application/json; charset=UTF-8\",\n        \"Date\": \"Fri, 26 Feb 2021 09:15:41 GMT\",\n        \"Content-Length\": \"13\"\n    },\n    \"cookies\": {},\n    \"body\": \"{\\\"pong\\\":\\\"k6\\\"}\",\n    \"timings\": {\n            \"duration\": 163.3468,\n            \"blocked\": 0.0295,\n            \"looking_up\": 0,\n            \"connecting\": 0,\n            \"tls_handshaking\": 0,\n            \"sending\": 0.0296,\n            \"waiting\": 196.8227,\n            \"receiving\": -33.5055\n        },\n    \"tls_version\": \"\",\n    \"tls_cipher_suite\": \"\",\n    \"ocsp\": {\n            \"produced_at\": 0,\n            \"this_update\": 0,\n            \"next_update\": 0,\n            \"revoked_at\": 0,\n            \"revocation_reason\": \"\",\n            \"status\": \"\"\n        },\n    \"error\": \"\",\n    \"error_code\": 0,\n    \"request\": {\n            \"method\": \"GET\",\n            \"url\": \"http://pong/ping/k6\",\n            \"headers\": {\n                \"User-Agent\": [\n                    \"k6/0.30.0 (https://k6.io/)\"\n                ]\n            },\n            \"body\": \"\",\n            \"cookies\": {}\n        }\n}" source=console
k6_1    | 
k6_1    | running (1m07.2s), 2000/2000 VUs, 707133 complete and 0 interrupted iterations
k6_1    | default   [  67% ] 2000 VUs  1m07.3s/1m40s
k6_1    | time="2021-02-26T09:15:42Z" level=info msg="{\n    \"remote_ip\": \"172.19.0.2\",\n    \"remote_port\": 80,\n    \"url\": \"http://pong/ping/k6\",\n    \"status\": 200,\n    \"status_text\": \"200 OK\",\n    \"proto\": \"HTTP/1.1\",\n    \"headers\": {\n        \"Date\": \"Fri, 26 Feb 2021 09:15:41 GMT\",\n        \"Content-Length\": \"13\",\n        \"Content-Type\": \"application/json; charset=UTF-8\"\n    },\n    \"cookies\": {},\n    \"body\": \"{\\\"pong\\\":\\\"k6\\\"}\",\n    \"timings\": {\n            \"duration\": 162.9286,\n            \"blocked\": 0.0286,\n            \"looking_up\": 0,\n            \"connecting\": 0,\n            \"tls_handshaking\": 0,\n            \"sending\": 0.0265,\n            \"waiting\": 167.0958,\n            \"receiving\": -4.1937\n        },\n    \"tls_version\": \"\",\n    \"tls_cipher_suite\": \"\",\n    \"ocsp\": {\n            \"produced_at\": 0,\n            \"this_update\": 0,\n            \"next_update\": 0,\n            \"revoked_at\": 0,\n            \"revocation_reason\": \"\",\n            \"status\": \"\"\n        },\n    \"error\": \"\",\n    \"error_code\": 0,\n    \"request\": {\n            \"method\": \"GET\",\n            \"url\": \"http://pong/ping/k6\",\n            \"headers\": {\n                \"User-Agent\": [\n                    \"k6/0.30.0 (https://k6.io/)\"\n                ]\n            },\n            \"body\": \"\",\n            \"cookies\": {}\n        }\n}" source=console
k6_1    | time="2021-02-26T09:15:42Z" level=info msg="{\n    \"remote_ip\": \"172.19.0.2\",\n    \"remote_port\": 80,\n    \"url\": \"http://pong/ping/k6\",\n    \"status\": 200,\n    \"status_text\": \"200 OK\",\n    \"proto\": \"HTTP/1.1\",\n    \"headers\": {\n        \"Content-Type\": \"application/json; charset=UTF-8\",\n        \"Date\": \"Fri, 26 Feb 2021 09:15:41 GMT\",\n        \"Content-Length\": \"13\"\n    },\n    \"cookies\": {},\n    \"body\": \"{\\\"pong\\\":\\\"k6\\\"}\",\n    \"timings\": {\n            \"duration\": 191.153,\n            \"blocked\": 0.0336,\n            \"looking_up\": 0,\n            \"connecting\": 0,\n            \"tls_handshaking\": 0,\n            \"sending\": 0.0626,\n            \"waiting\": 199.7006,\n            \"receiving\": -8.6102\n        },\n    \"tls_version\": \"\",\n    \"tls_cipher_suite\": \"\",\n    \"ocsp\": {\n            \"produced_at\": 0,\n            \"this_update\": 0,\n            \"next_update\": 0,\n            \"revoked_at\": 0,\n            \"revocation_reason\": \"\",\n            \"status\": \"\"\n        },\n    \"error\": \"\",\n    \"error_code\": 0,\n    \"request\": {\n            \"method\": \"GET\",\n            \"url\": \"http://pong/ping/k6\",\n            \"headers\": {\n                \"User-Agent\": [\n                    \"k6/0.30.0 (https://k6.io/)\"\n                ]\n            },\n            \"body\": \"\",\n            \"cookies\": {}\n        }\n}" source=console
k6_1    | 
k6_1    | running (1m08.2s), 2000/2000 VUs, 712356 complete and 0 interrupted iterations

...

k6_1    | 
k6_1    | running (1m36.2s), 2000/2000 VUs, 1015207 complete and 0 interrupted iterations
k6_1    | default   [  96% ] 2000 VUs  1m36.3s/1m40s
k6_1    | time="2021-02-26T09:16:11Z" level=info msg="{\n    \"remote_ip\": \"172.19.0.2\",\n    \"remote_port\": 80,\n    \"url\": \"http://pong/ping/k6\",\n    \"status\": 200,\n    \"status_text\": \"200 OK\",\n    \"proto\": \"HTTP/1.1\",\n    \"headers\": {\n        \"Content-Type\": \"application/json; charset=UTF-8\",\n        \"Date\": \"Fri, 26 Feb 2021 09:16:11 GMT\",\n        \"Content-Length\": \"13\"\n    },\n    \"cookies\": {},\n    \"body\": \"{\\\"pong\\\":\\\"k6\\\"}\",\n    \"timings\": {\n            \"duration\": 25.157,\n            \"blocked\": 0.0935,\n            \"looking_up\": 0,\n            \"connecting\": 0,\n            \"tls_handshaking\": 0,\n            \"sending\": 0.0287,\n            \"waiting\": 28.694,\n            \"receiving\": -3.5657\n        },\n    \"tls_version\": \"\",\n    \"tls_cipher_suite\": \"\",\n    \"ocsp\": {\n            \"produced_at\": 0,\n            \"this_update\": 0,\n            \"next_update\": 0,\n            \"revoked_at\": 0,\n            \"revocation_reason\": \"\",\n            \"status\": \"\"\n        },\n    \"error\": \"\",\n    \"error_code\": 0,\n    \"request\": {\n            \"method\": \"GET\",\n            \"url\": \"http://pong/ping/k6\",\n            \"headers\": {\n                \"User-Agent\": [\n                    \"k6/0.30.0 (https://k6.io/)\"\n                ]\n            },\n            \"body\": \"\",\n            \"cookies\": {}\n        }\n}" source=console
k6_1    | time="2021-02-26T09:16:11Z" level=info msg="{\n    \"remote_ip\": \"172.19.0.2\",\n    \"remote_port\": 80,\n    \"url\": \"http://pong/ping/k6\",\n    \"status\": 200,\n    \"status_text\": \"200 OK\",\n    \"proto\": \"HTTP/1.1\",\n    \"headers\": {\n        \"Date\": \"Fri, 26 Feb 2021 09:16:11 GMT\",\n        \"Content-Length\": \"13\",\n        \"Content-Type\": \"application/json; charset=UTF-8\"\n    },\n    \"cookies\": {},\n    \"body\": \"{\\\"pong\\\":\\\"k6\\\"}\",\n    \"timings\": {\n            \"duration\": 53.5901,\n            \"blocked\": 0.0294,\n            \"looking_up\": 0,\n            \"connecting\": 0,\n            \"tls_handshaking\": 0,\n            \"sending\": 0.0312,\n            \"waiting\": 58.0011,\n            \"receiving\": -4.4422\n        },\n    \"tls_version\": \"\",\n    \"tls_cipher_suite\": \"\",\n    \"ocsp\": {\n            \"produced_at\": 0,\n            \"this_update\": 0,\n            \"next_update\": 0,\n            \"revoked_at\": 0,\n            \"revocation_reason\": \"\",\n            \"status\": \"\"\n        },\n    \"error\": \"\",\n    \"error_code\": 0,\n    \"request\": {\n            \"method\": \"GET\",\n            \"url\": \"http://pong/ping/k6\",\n            \"headers\": {\n                \"User-Agent\": [\n                    \"k6/0.30.0 (https://k6.io/)\"\n                ]\n            },\n            \"body\": \"\",\n            \"cookies\": {}\n        }\n}" source=console
k6_1    | 

...

k6_1    | 
k6_1    | running (1m40.0s), 0000/2000 VUs, 1055790 complete and 0 interrupted iterations
k6_1    | default ✓ [ 100% ] 2000 VUs  1m40s
k6_1    | 
k6_1    |      ✓ is status 200
k6_1    |      ✗ is http_req_receiving >= 0
k6_1    |       ↳  99% — ✓ 1055782 / ✗ 8
k6_1    | 
k6_1    |      checks.....................: 99.99%  ✓ 2111572 ✗ 8     
k6_1    |      data_received..............: 144 MB  1.4 MB/s
k6_1    |      data_sent..................: 81 MB   813 kB/s
k6_1    |      http_req_blocked...........: avg=1.12ms   min=0s           med=23.7µs   max=3.18s    p(90)=31.3µs   p(95)=39.3µs  
k6_1    |      http_req_connecting........: avg=1.03ms   min=0s           med=0s       max=3.18s    p(90)=0s       p(95)=0s      
k6_1    |    ✓ http_req_duration..........: avg=111.83ms min=197.7µs      med=103.46ms max=1.01s    p(90)=170.35ms p(95)=208.6ms 
k6_1    |      http_req_receiving.........: avg=1.19ms   min=-33.505499ms med=59.7µs   max=390.04ms p(90)=154.5µs  p(95)=335µs   
k6_1    |      http_req_sending...........: avg=555.45µs min=-34.3892ms   med=24.3µs   max=417.19ms p(90)=48.3µs   p(95)=112.2µs 
k6_1    |      http_req_tls_handshaking...: avg=0s       min=0s           med=0s       max=0s       p(90)=0s       p(95)=0s      
k6_1    |      http_req_waiting...........: avg=110.08ms min=129.89µs     med=102.66ms max=1.01s    p(90)=167.5ms  p(95)=203.35ms
k6_1    |      http_reqs..................: 1055790 10555.615079/s
k6_1    |      iteration_duration.........: avg=182.12ms min=482.1µs      med=157.89ms max=3.27s    p(90)=307.92ms p(95)=377.09ms
k6_1    |      iterations.................: 1055790 10555.615079/s
k6_1    |      vus........................: 2000    min=2000  max=2000
k6_1    |      vus_max....................: 2000    min=2000  max=2000
k6_1    | 
perf_k6_1 exited with code 0

ludenus avatar Feb 26 '21 09:02 ludenus

Here they are after some formatting:

{
    "remote_ip": "172.19.0.2",
    "remote_port": 80,
    "url": "http://pong/ping/k6",
    "status": 200,
    "status_text": "200 OK",
    "proto": "HTTP/1.1",
    "headers": {
        "Content-Type": "application/json; charset=UTF-8",
        "Date": "Fri, 26 Feb 2021 09:15:11 GMT",
        "Content-Length": "13"
    },
    "cookies": {},
    "body": "{\"pong\":\"k6\"}",
    "timings": {
            "duration": 81.4798,
            "blocked": 0.0213,
            "looking_up": 0,
            "connecting": 0,
            "tls_handshaking": 0,
            "sending": 0.0238,
            "waiting": 92.5957,
            "receiving": -11.1397
        },
    "tls_version": "",
    "tls_cipher_suite": "",
    "ocsp": {
            "produced_at": 0,
            "this_update": 0,
            "next_update": 0,
            "revoked_at": 0,
            "revocation_reason": "",
            "status": ""
        },
    "error": "",
    "error_code": 0,
    "request": {
            "method": "GET",
            "url": "http://pong/ping/k6",
            "headers": {
                "User-Agent": [
                    "k6/0.30.0 (https://k6.io/)"
                ]
            },
            "body": "",
            "cookies": {}
        }
}
{
    "remote_ip": "172.19.0.2",
    "remote_port": 80,
    "url": "http://pong/ping/k6",
    "status": 200,
    "status_text": "200 OK",
    "proto": "HTTP/1.1",
    "headers": {
        "Content-Type": "application/json; charset=UTF-8",
        "Date": "Fri, 26 Feb 2021 09:15:11 GMT",
        "Content-Length": "13"
    },
    "cookies": {},
    "body": "{\"pong\":\"k6\"}",
    "timings": {
            "duration": 42.0096,
            "blocked": 0.0238,
            "looking_up": 0,
            "connecting": 0,
            "tls_handshaking": 0,
            "sending": 0.0381,
            "waiting": 69.6788,
            "receiving": -27.7073
        },
    "tls_version": "",
    "tls_cipher_suite": "",
    "ocsp": {
            "produced_at": 0,
            "this_update": 0,
            "next_update": 0,
            "revoked_at": 0,
            "revocation_reason": "",
            "status": ""
        },
    "error": "",
    "error_code": 0,
    "request": {
            "method": "GET",
            "url": "http://pong/ping/k6",
            "headers": {
                "User-Agent": [
                    "k6/0.30.0 (https://k6.io/)"
                ]
            },
            "body": "",
            "cookies": {}
        }
}
{
    "remote_ip": "172.19.0.2",
    "remote_port": 80,
    "url": "http://pong/ping/k6",
    "status": 200,
    "status_text": "200 OK",
    "proto": "HTTP/1.1",
    "headers": {
        "Date": "Fri, 26 Feb 2021 09:15:11 GMT",
        "Content-Length": "13",
        "Content-Type": "application/json; charset=UTF-8"
    },
    "cookies": {},
    "body": "{\"pong\":\"k6\"}",
    "timings": {
            "duration": 88.9084,
            "blocked": 0.0242,
            "looking_up": 0,
            "connecting": 0,
            "tls_handshaking": 0,
            "sending": 0.0232,
            "waiting": 105.644,
            "receiving": -16.7588
        },
    "tls_version": "",
    "tls_cipher_suite": "",
    "ocsp": {
            "produced_at": 0,
            "this_update": 0,
            "next_update": 0,
            "revoked_at": 0,
            "revocation_reason": "",
            "status": ""
        },
    "error": "",
    "error_code": 0,
    "request": {
            "method": "GET",
            "url": "http://pong/ping/k6",
            "headers": {
                "User-Agent": [
                    "k6/0.30.0 (https://k6.io/)"
                ]
            },
            "body": "",
            "cookies": {}
        }
}
{
    "remote_ip": "172.19.0.2",
    "remote_port": 80,
    "url": "http://pong/ping/k6",
    "status": 200,
    "status_text": "200 OK",
    "proto": "HTTP/1.1",
    "headers": {
        "Content-Type": "application/json; charset=UTF-8",
        "Date": "Fri, 26 Feb 2021 09:15:41 GMT",
        "Content-Length": "13"
    },
    "cookies": {},
    "body": "{\"pong\":\"k6\"}",
    "timings": {
            "duration": 163.3468,
            "blocked": 0.0295,
            "looking_up": 0,
            "connecting": 0,
            "tls_handshaking": 0,
            "sending": 0.0296,
            "waiting": 196.8227,
            "receiving": -33.5055
        },
    "tls_version": "",
    "tls_cipher_suite": "",
    "ocsp": {
            "produced_at": 0,
            "this_update": 0,
            "next_update": 0,
            "revoked_at": 0,
            "revocation_reason": "",
            "status": ""
        },
    "error": "",
    "error_code": 0,
    "request": {
            "method": "GET",
            "url": "http://pong/ping/k6",
            "headers": {
                "User-Agent": [
                    "k6/0.30.0 (https://k6.io/)"
                ]
            },
            "body": "",
            "cookies": {}
        }
}
{
    "remote_ip": "172.19.0.2",
    "remote_port": 80,
    "url": "http://pong/ping/k6",
    "status": 200,
    "status_text": "200 OK",
    "proto": "HTTP/1.1",
    "headers": {
        "Date": "Fri, 26 Feb 2021 09:15:41 GMT",
        "Content-Length": "13",
        "Content-Type": "application/json; charset=UTF-8"
    },
    "cookies": {},
    "body": "{\"pong\":\"k6\"}",
    "timings": {
            "duration": 162.9286,
            "blocked": 0.0286,
            "looking_up": 0,
            "connecting": 0,
            "tls_handshaking": 0,
            "sending": 0.0265,
            "waiting": 167.0958,
            "receiving": -4.1937
        },
    "tls_version": "",
    "tls_cipher_suite": "",
    "ocsp": {
            "produced_at": 0,
            "this_update": 0,
            "next_update": 0,
            "revoked_at": 0,
            "revocation_reason": "",
            "status": ""
        },
    "error": "",
    "error_code": 0,
    "request": {
            "method": "GET",
            "url": "http://pong/ping/k6",
            "headers": {
                "User-Agent": [
                    "k6/0.30.0 (https://k6.io/)"
                ]
            },
            "body": "",
            "cookies": {}
        }
}
{
    "remote_ip": "172.19.0.2",
    "remote_port": 80,
    "url": "http://pong/ping/k6",
    "status": 200,
    "status_text": "200 OK",
    "proto": "HTTP/1.1",
    "headers": {
        "Content-Type": "application/json; charset=UTF-8",
        "Date": "Fri, 26 Feb 2021 09:15:41 GMT",
        "Content-Length": "13"
    },
    "cookies": {},
    "body": "{\"pong\":\"k6\"}",
    "timings": {
            "duration": 191.153,
            "blocked": 0.0336,
            "looking_up": 0,
            "connecting": 0,
            "tls_handshaking": 0,
            "sending": 0.0626,
            "waiting": 199.7006,
            "receiving": -8.6102
        },
    "tls_version": "",
    "tls_cipher_suite": "",
    "ocsp": {
            "produced_at": 0,
            "this_update": 0,
            "next_update": 0,
            "revoked_at": 0,
            "revocation_reason": "",
            "status": ""
        },
    "error": "",
    "error_code": 0,
    "request": {
            "method": "GET",
            "url": "http://pong/ping/k6",
            "headers": {
                "User-Agent": [
                    "k6/0.30.0 (https://k6.io/)"
                ]
            },
            "body": "",
            "cookies": {}
        }
}
{
    "remote_ip": "172.19.0.2",
    "remote_port": 80,
    "url": "http://pong/ping/k6",
    "status": 200,
    "status_text": "200 OK",
    "proto": "HTTP/1.1",
    "headers": {
        "Content-Type": "application/json; charset=UTF-8",
        "Date": "Fri, 26 Feb 2021 09:16:11 GMT",
        "Content-Length": "13"
    },
    "cookies": {},
    "body": "{\"pong\":\"k6\"}",
    "timings": {
            "duration": 25.157,
            "blocked": 0.0935,
            "looking_up": 0,
            "connecting": 0,
            "tls_handshaking": 0,
            "sending": 0.0287,
            "waiting": 28.694,
            "receiving": -3.5657
        },
    "tls_version": "",
    "tls_cipher_suite": "",
    "ocsp": {
            "produced_at": 0,
            "this_update": 0,
            "next_update": 0,
            "revoked_at": 0,
            "revocation_reason": "",
            "status": ""
        },
    "error": "",
    "error_code": 0,
    "request": {
            "method": "GET",
            "url": "http://pong/ping/k6",
            "headers": {
                "User-Agent": [
                    "k6/0.30.0 (https://k6.io/)"
                ]
            },
            "body": "",
            "cookies": {}
        }
}
{
    "remote_ip": "172.19.0.2",
    "remote_port": 80,
    "url": "http://pong/ping/k6",
    "status": 200,
    "status_text": "200 OK",
    "proto": "HTTP/1.1",
    "headers": {
        "Date": "Fri, 26 Feb 2021 09:16:11 GMT",
        "Content-Length": "13",
        "Content-Type": "application/json; charset=UTF-8"
    },
    "cookies": {},
    "body": "{\"pong\":\"k6\"}",
    "timings": {
            "duration": 53.5901,
            "blocked": 0.0294,
            "looking_up": 0,
            "connecting": 0,
            "tls_handshaking": 0,
            "sending": 0.0312,
            "waiting": 58.0011,
            "receiving": -4.4422
        },
    "tls_version": "",
    "tls_cipher_suite": "",
    "ocsp": {
            "produced_at": 0,
            "this_update": 0,
            "next_update": 0,
            "revoked_at": 0,
            "revocation_reason": "",
            "status": ""
        },
    "error": "",
    "error_code": 0,
    "request": {
            "method": "GET",
            "url": "http://pong/ping/k6",
            "headers": {
                "User-Agent": [
                    "k6/0.30.0 (https://k6.io/)"
                ]
            },
            "body": "",
            "cookies": {}
        }
}

na-- avatar Feb 26 '21 09:02 na--

For context, here are some similar issues we've had in the past: https://github.com/loadimpact/k6/issues/588, https://github.com/loadimpact/k6/pull/862. This time it seems like:

  • it's not an HTTP/2 issue, see "proto": "HTTP/1.1" everywhere
  • we're reusing connections ("connecting": 0 in all cases)
  • requests were successful, they weren't cancelled or timed out or anything bad - we got a good response

I may be wrong, but this time it's looking like it might be a bug or a race in the Go stdlib's net/http/httptrace module... On the k6 side, receiving is calculated here: https://github.com/loadimpact/k6/blob/51790fc8df37113ac20b586b28051e21672dab16/lib/netext/httpext/tracer.go#L326-L328

It is the difference between done and gotFirstResponseByte. We get gotFirstResponseByte directly from the net/http/httptrace.ClientTrace hook, which is supposedly "called when the first byte of the response headers is available" (from the official docs: https://github.com/loadimpact/k6/blob/51790fc8df37113ac20b586b28051e21672dab16/lib/netext/httpext/tracer.go#L259-L265

done is calculated by the time we've already gotten a response, i.e. the whole RoundTrip() method is complete! https://github.com/loadimpact/k6/blob/51790fc8df37113ac20b586b28051e21672dab16/lib/netext/httpext/request.go#L323 https://github.com/loadimpact/k6/blob/51790fc8df37113ac20b586b28051e21672dab16/lib/netext/httpext/transport.go#L201 https://github.com/loadimpact/k6/blob/51790fc8df37113ac20b586b28051e21672dab16/lib/netext/httpext/transport.go#L90-L91 https://github.com/loadimpact/k6/blob/51790fc8df37113ac20b586b28051e21672dab16/lib/netext/httpext/tracer.go#L267-L269

So, either I'm missing something major, or, somehow, httptrace.GotFirstResponseByte() gets called by Go's HTTP code after the whole HTTP request has already completed :confused:

na-- avatar Feb 26 '21 09:02 na--

On the other hand, it doesn't look like the relevant code from the Go stdlib does anything strange, or indeed, has been changed recently :confused: https://github.com/golang/go/blame/520f3b72db7befab2028d9a47376267cf2d274a9/src/net/http/transport.go#L2265-L2270

na-- avatar Feb 26 '21 09:02 na--

@na-- so far I did NOT manage to reproduce the issue on Linux host host info

CPU: Intel(R) Pentium(R) CPU J4205 @ 1.50GHz
CPU(s):                    4
Thread(s) per core: 1
CPU max MHz:        2600.0000
CPU min MHz:         800.0000

RAM 4Gb Ubuntu 20.04.2 LTS kernel 5.4.0-66-generic Docker version 19.03.11, build 42e35e61f3

ludenus avatar Feb 26 '21 10:02 ludenus

I'm officially stumped :sweat_smile: Debugging this would be super difficult when I can't reproduce it locally, and when it happens so rarely. See the check count in https://github.com/loadimpact/k6/issues/1872#issuecomment-786519330

      ✗ is http_req_receiving >= 0
       ↳  99% — ✓ 1055782 / ✗ 8

It has happened 8 times out of 1055790 requests, i.e. in ~0.000758% of requests. It's probably some strange and very infrequent data race, and I imagine it happens even more rarely when you're not testing localhost, as is essentially the case with the docker-compose example, but real-world systems with higher latencies... If anyone has any ideas how we can track this down, please share. The quick "fix" would be to just replace this code: https://github.com/loadimpact/k6/blob/51790fc8df37113ac20b586b28051e21672dab16/lib/netext/httpext/tracer.go#L326-L328

With something like this:

if gotFirstResponseByte != 0 && done.After(gotFirstResponseByte) {
	trail.Receiving = done.Sub(time.Unix(0, gotFirstResponseByte))
}

And we won't get any more negative http_req_receiving values, but without knowing the root cause, that may just mask the issue instead of actually fixing it. Who knows, it may be a valid fix/workaround, if the bug is that the stdlib is firing GotFirstResponseByte() too late, for some reason, but I won't be willing to bet that's the case :man_shrugging:

na-- avatar Feb 26 '21 10:02 na--

Hi @na-- One possibility is that the thread doing the latency measurement is migrated to another cpu between measurements.

monotonic clocks are guaranteed to increase on each cpu locally. However, there are cases where the clock between cpus is not synchronised. Most cpus will support invariant_tsc , but it is possible that multisocket machines don't synchronise across sockets. VMs/hypervisors also may not use tsc and/or may not expose tsc to a guest.

Ideas to reproduce:

runs tests on a machine/vm without tsc invariant clocksource taskset k6 to 2 cpus on difference sockets to encourage threads to migrate between sockets. simplify to a golang reproducer without any k6 or network code

Ideas to detect:

trace thread cpu migration events (typically via perf or ebpf on linux if it can be reproduced there)

alexb-img avatar Aug 24 '22 06:08 alexb-img

Thanks, @alexb-img, this sounds like a very plausible explanation for what we observed! I can't test it right now, but assuming you are right, do you have any suggestions for a better fix purely in user-space Go, without any messing with eBPF and such?

The simplest "fix" might indeed be to just consider any negative values close to 0 to be just 0... :thinking:

na-- avatar Aug 26 '22 08:08 na--

Hey @ludenus, https://github.com/ludenus/k6-issue-1872/blob/f02a3f383a0fbc077ded73bb8d67af0273f40017/docker-compose.yaml#L12C4-L12C34 can you try to run an updated version of your docker-compose, please? k6 is now v0.51 and loadimpact image is not supported anymore.

You should use the following docker image:

grafana/k6:0.51.0

@ludenus what is your running OS? Is it Windows?

I tried to run it on Linux and I'm not yet able to reproduce it. As the comment in the code mentions, the reason could related to cancel requests. I don't think we have this case covered in our unit tests. It would be good to check and cover it.

codebien avatar May 22 '24 11:05 codebien