-
Notifications
You must be signed in to change notification settings - Fork 17
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
Workaround asio::ssl async_read_some busy-loop #69
Conversation
af17436
to
6856be2
Compare
Results for connection throughput testing - as before, I'm really just trying to make sure we don't regress performance here, and comparing against the not-shown fix using a fixed buffer size. The memory usage is fairly adhoc - I just watched Values in connections completed per second over the test run:
The machine used for testing had 16GB of ram - so assuming top isn't doing something crazy 1.1% is about 180MiB and 2% is about 320MiB.
Each test run was only about 10 seconds. I hit ephemeral port issues on this host running longer tests - probably can work around this if we want to, but these numbers seemed like a reasonable comparison to me. |
libamqpprox/amqpprox_session.cpp
Outdated
@@ -682,6 +682,9 @@ void Session::readData(FlowType direction) | |||
readData(direction); | |||
} | |||
else { | |||
if (readAmount > 0) { | |||
LOG_TRACE << "read_some returned data and error. Data discarded to close sockets"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can add some more info in this trace like direction?
f79263b
to
d5d3c7d
Compare
chriskohlhoff/asio#1015 `asio::ssl` has a bug where calling async_read_some with `null_buffers` isn't correctly handled, and more or less immediately invokes the provided handler with no data. This causes `amqpprox` to busy-loop whenever a TLS socket has been accepted or opened. There were two options for how to fix this: 1) Always read with a fixed size buffer, such as 32kb. This would simplify the code slightly, at the expense of needing multiple reads to handle larger than 32kb frames in non-TLS mode, even when the full frame is available to `amqpprox` in one go. 2) Ask asio::ssl to read with a very small buffer, then ask the openssl library how many bytes are available. This technique aligns with how `amqpprox`'s read loop works today. That is what is implemented here. In theory something similar could be upstreamed into `asio::ssl`. It's a little tricky though and this exact code couldn't handle the generic `MutableBufferSequence` interface - we can take some shortcuts in our code. I've done some benchmarking to check this change isn't going to regress performance noticeably. Data throughput tests indicate that this fix improves performance for TLS connections over the existing code. Still running connection throughput tests.
20c47a2
to
4081d1c
Compare
This commit changes MaybeSecureSocketAdaptor to template a few critical types which allows us to write unit tests against some of it's behaviours In theory this could probably also replace the SocketIntercept things, which were a nice solution when the implementation of this class passed straight through to the asio types. Since working around some asio bugs bloomberg#69 and adding support for data rate limits bloomberg#88 the MaybeSecureSocketAdaptor class has expanded enough that we should be writing unit tests for it - and probably should have done so before now.
This commit changes MaybeSecureSocketAdaptor to template a few critical types which allows us to write unit tests against some of it's behaviours In theory this could probably also replace the SocketIntercept things, which were a nice solution when the implementation of this class passed straight through to the asio types. Since working around some asio bugs bloomberg#69 and adding support for data rate limits bloomberg#88 the MaybeSecureSocketAdaptor class has expanded enough that we should be writing unit tests for it - and probably should have done so before now.
This commit changes MaybeSecureSocketAdaptor to template a few critical types which allows us to write unit tests against some of it's behaviours In theory this could probably also replace the SocketIntercept things, which were a nice solution when the implementation of this class passed straight through to the asio types. Since working around some asio bugs bloomberg#69 and adding support for data rate limits bloomberg#88 the MaybeSecureSocketAdaptor class has expanded enough that we should be writing unit tests for it - and probably should have done so before now.
This commit changes MaybeSecureSocketAdaptor to template a few critical types which allows us to write unit tests against some of it's behaviours In theory this could probably also replace the SocketIntercept things, which were a nice solution when the implementation of this class passed straight through to the asio types. Since working around some asio bugs #69 and adding support for data rate limits #88 the MaybeSecureSocketAdaptor class has expanded enough that we should be writing unit tests for it - and probably should have done so before now.
asio::ssl
has a bug where calling async_read_some withnull_buffers
isn't correctly handled, and more or less immediately invokes the
provided handler with no data. This causes
amqpprox
to busy-loopwhenever a TLS socket has been accepted or opened.
There were two options for how to address this in our code:
simplify the code slightly, at the expense of needing multiple reads
to handle larger than 32kb frames in non-TLS mode, even when the full
frame is available to
amqpprox
in one go.library how many bytes are available. This technique aligns with how
amqpprox
's read loop works today. That is what is implemented here.In theory something similar could be upstreamed into
asio::ssl
. It's alittle tricky though and this exact code couldn't handle the generic
MutableBufferSequence
interface - we can take some shortcuts in ourcode.
I've done some benchmarking to check this change isn't going to regress
performance noticeably. Data throughput tests indicate that this fix improves
performance for TLS connections over the existing code.
Performance Tests
Testing by setting up amqpprox as per the performance tests README.md, and running the perf tester like:
Results in MiB/s over a ~20second run
This shows there isn't really any chance to non-TLS performance, and there is a slight increase in throughput with this code change (or the fixed-buffer size change).
Still TODOasync_read_some
definition since it should be unusedRef: chriskohlhoff/asio#1015