Open andyleiserson opened 1 month ago
Immediate workaround: #1073 Alternate workaround: #1087
Open items:
I am able to reproduce this issue (or a similar one because I am seeing protocol getting stuck at slightly different steps), but it takes more than one run to get a stall. Logs grow big and I am only interested in the last failed run, so I am using the following command to trim them
for IDENTITY in {1..3}; do tail -r /tmp/h$IDENTITY.log | awk '{print} /ipa_core::query::runner::oprf_ipa: new/{exit}' | tail -r > /tmp/hl$IDENTITY.log; done
Basically this just reverses the log file, looks for an indication of new query (oprf_ipa: new) and terminates the pipe and reverses the pipe again.
Note that on MacOS the default awk
is too old, I am using the one vended by brew.
I am suspecting a flow control issue, and not a protocol bug. Some evidence that backs this claim from the recent stall I was observing.
H3 is stuck waiting for data from H2
2024-05-27T17:52:07.525291Z WARN :stall_detector{role=H3}: ipa_core::helpers::gateway::stall_detection::gateway: Helper is stalled sn=1152528 state=
{
"gate=/ipa_prf/eval_prf/mult_mask_with_p_r_f_input", from=H2. Waiting to receive records ["[0..781]"].
}
The application layer on H2 registered a send event
2024-05-27T17:47:59.392227Z TRACE send_stream{to=H3 gate=gate=/ipa_prf/eval_prf/mult_mask_with_p_r_f_input}: ipa_core::helpers::gateway::send: new
2024-05-27T17:47:59.392642Z TRACE send_stream{to=H3 gate=gate=/ipa_prf/eval_prf/mult_mask_with_p_r_f_input}: ipa_core::helpers::buffers::ordering_sender: Sending next 1601536 bytes. next = 783. stream closed = true, alloc = 0x3a853a400
2024-05-27T17:47:59.392645Z TRACE send_stream{to=H3 gate=gate=/ipa_prf/eval_prf/mult_mask_with_p_r_f_input}: ipa_core::helpers::gateway::send: close time.busy=409µs time.idle=8.62µ
the size of this send is big and matches @andyleiserson's estimate in #1073: 1601536 bytes (~1.6MB). H2 did everything right.
Right after this send, there was another one, as large as this one
2024-05-27T17:47:59.582779Z TRACE send_stream{to=H3 gate=gate=/ipa_prf/eval_prf/revealz}: ipa_core::helpers::buffers::ordering_sender: Sending next 1601536 bytes. next = 783. stream closed = true, alloc = 0x3a9b95500
2024-05-27T17:47:59.582781Z TRACE send_stream{to=H3 gate=gate=/ipa_prf/eval_prf/revealz}: ipa_core::helpers::gateway::send: close time.busy=514µs time.idle=1.46µs
On H3 UnorderedReceiver
is actually polling the underlying stream, but it gets very small chunks back
2024-05-27T17:47:59.393886Z TRACE oprf_ipa_query{sz=50000}:compute_prf_for_inputs:receive{i=0 from=H2 gate="/ipa_prf/eval_prf/mult_mask_with_p_r_f_input"}: ipa_core::helpers::buffers::unordered_receiver: received next chunk: 1
2024-05-27T17:47:59.393886Z TRACE oprf_ipa_query{sz=50000}:compute_prf_for_inputs:receive{i=0 from=H2 gate="/ipa_prf/eval_prf/mult_mask_with_p_r_f_input"}: ipa_core::helpers::buffers::unordered_receiver: received next chunk: 1
2024-05-27T17:47:59.394255Z TRACE oprf_ipa_query{sz=50000}:compute_prf_for_inputs:receive{i=0 from=H2 gate="/ipa_prf/eval_prf/mult_mask_with_p_r_f_input"}: ipa_core::helpers::buffers::unordered_receiver: received next chunk: 1
2024-05-27T17:47:59.394255Z TRACE oprf_ipa_query{sz=50000}:compute_prf_for_inputs:receive{i=0 from=H2 gate="/ipa_prf/eval_prf/mult_mask_with_p_r_f_input"}: ipa_core::helpers::buffers::unordered_receiver: received next chunk: 1
Some other things that I noticed
Next, I want to look at HTTP2 frames to confirm it. I suspect that we are observing another variation of seq_join parallelism problem:
More evidence supporting the theory above. I added some logs to h2
crate and it does indicate that it ran out of connection capacity
2024-05-27T21:35:25.869005Z TRACE send_stream{to=H1 gate=gate=/ipa_prf/eval_prf/mult_mask_with_p_r_f_input}: ipa_core::helpers::buffers::ordering_sender: Sending next 1601536 bytes. next = 783. stream closed = true, alloc = 0x3b9f3a140
2024-05-27T21:35:25.869012Z TRACE send_stream{to=H1 gate=gate=/ipa_prf/eval_prf/mult_mask_with_p_r_f_input}: ipa_core::helpers::gateway::send: close time.busy=584µs time.idle=4.75µs
2024-05-27T21:35:25.869017Z WARN h2::proto::streams::prioritize: ipafix: stream requires extra capacity 1601536, but connection window does not have enough 823360
2024-05-27T21:35:25.869021Z WARN h2::proto::streams::prioritize: ipafix: stream requires extra capacity 1601537, but connection window does not have enough 823360
I am also not seeing any activity from Hyper on the sender (client) after that, I suspect backpressure to be the culprit
I am trying to figure out the window size at the moment when protocol stalls to confirm this theory
I can confirm the root cause of this issue being connection level flow control for HTTP2. I ran a test with it disabled and left it overnight - no failures reported
Steps to reproduce:
INPUT_SIZE
definition intests/common.mod.rs
to 50000.cargo test --release --no-default-features --features="cli test-fixture real-world-infra web-app disable-metrics multi-threading stall-detection compact-gate" -- https_semi_honest --nocapture
.Sample stall-detector output (this is from a run in @eriktaubeneck's infrastructure):
Test command for running oneshot bench with in-memory infra, which does not hang:
cargo bench --bench oneshot_ipa --features="enable-benches disable-metrics multi-threading compact-gate" -- -n 50000 -c 8 -u 10 -a 1024 -j 8
.