Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nghttpd does not support larger frames requested by a client #1647

Closed
robaho opened this issue Nov 20, 2021 · 9 comments · May be fixed by #1648
Closed

nghttpd does not support larger frames requested by a client #1647

robaho opened this issue Nov 20, 2021 · 9 comments · May be fixed by #1648
Labels

Comments

@robaho
Copy link
Contributor

robaho commented Nov 20, 2021

With http2, the client can request larger frame sizes in order to improve efficiency.

After requesting the larger size, the frames returned by nghttpd are still the default 16k.

@robaho
Copy link
Contributor Author

robaho commented Nov 20, 2021

The offending code is in nghttp2_session.c:1814

 window_size = nghttp2_session_enforce_flow_control_limits(
      session, stream, NGHTTP2_DATA_PAYLOADLEN);

NGHTTP2_DATA_PAYLOADLEN is a constant of 16k - the framesize minimum.

robaho added a commit to robaho/nghttp2 that referenced this issue Nov 20, 2021
@robaho robaho mentioned this issue Nov 20, 2021
@robaho
Copy link
Contributor Author

robaho commented Nov 20, 2021

I am not sure the PR is the best solution. There is a dependency on the write buffer size. If this is too small, the call fails with NGHTTP2_ERR_WOULDBLOCK and the transfer stops. I don't think this behavior is correct.

With the changes:

using a Go client:
16k frames = 1.9 GB/s
256k frames = 2.9 GB/s

using h2load:
16k frames = 3.0 GB/s
256k frames = 3.7 GB/s

So even using h2load it 20% faster with the larger frames.

@tatsuhiro-t
Copy link
Member

In my testing, it is not the size of frame but the size of buffer that increases the number.
I think the framing overhead is negligible if it is implemented properly.
The large frame size causes number of issues, including slow (or too late) prioritization propagation, increased memory usage by large buffers.

@robaho
Copy link
Contributor Author

robaho commented Nov 21, 2021

I don't disagree in the case of nghttp - but it's interface is not exactly "standard".

And a few counter points:

  1. Both Java and Go clients benefit tremendously from the changes.
  2. Profiling of both clients and servers show contention/overhead in the frame processing. This makes sense since a single stream has multiple servers and clients multiplexed onto it - so there must be concurrency issues to make this happen and it happens in user-space.
  3. The spec specifically calls for this capability. You can ask why? It came from SPDY - it was obvious that high throughput connections benefit from larger frames based on typical implementations.
  4. A system doing complex communications would most like use a large and small framed connection - to avoid the slow propagation issues.
  5. The tests I wrote use locally generated in-memory data streams - no disk IO - so the frame overhead processing is more apparent. I would need to write a custom nghttpd server to implement this.

At the end of the day, the spec calls for this so I think the reference implementation should properly support it.

@tatsuhiro-t
Copy link
Member

https://nghttp2.org/documentation/types.html#c.nghttp2_data_source_read_length_callback should be used to select the frame size.

So far, only go and java implementations suffer from the frame size. It means they might choose the wrong architecture. If so, it would be better to let them reconsider the design rather than asking the other server or client vendors to accept and use larger frames.

If I remembered it correctly, the frame size extension was introduced in the last minute change. There were lots of discussions about it, and in order to just get consensus, the frame size field was extended to 3 bytes, without the proof of any real numbers, and only with the speculation that the future network might need this.

That said, libnghttp2 has an interface to enlarge frame size (I had no plan to add it, but someone submitted PR). I do not feel the need to add the capability to extend frame size for nghttpd because the difference is negligible or not noticeable.

@robaho
Copy link
Contributor Author

robaho commented Nov 22, 2021

As I pointed out, the current frame size handling in nghttpd is broken. I created a PR #1650 to demonstrate. You can run this in conjunction with the -f option of h2load and using any frame size greater than the write buffer (64k) will cause the transfer to hang indefinitely.

@tatsuhiro-t
Copy link
Member

Yes, it needs larger buffers for larger frames. I just have no plan to add that capability to nghttpd.

@robaho
Copy link
Contributor Author

robaho commented Nov 22, 2021

You don't need to have a larger write buffer everywhere. Why not recreate the write buffer for the connection when the server receives a max_frame_size setting update?

In any case, I don't think hanging the transfer is correct. If anything, the server should cap the requested size from the callback to the write buffer size - essentially ignoring the request to change the max size.

Copy link

github-actions bot commented May 2, 2024

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 7 days.

@github-actions github-actions bot added the Stale label May 2, 2024
@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale May 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants