Login | Register For Free | Help
Search for: (Advanced)

Mailing List Archive: Apache: Dev

r1470679, async write completion, non blocking writes, and mod_ssl

 

 

Apache dev RSS feed   Index | Next | Previous | View Threaded


sf at sfritsch

Aug 4, 2013, 12:20 PM

Post #1 of 6 (48 views)
Permalink
r1470679, async write completion, non blocking writes, and mod_ssl

Hi,

I did some testing/reviewing of the ssl/event backport proposal

* core, mod_ssl: Lift the restriction that prevents mod_ssl taking
full advantage of the event MPM. Enable the ability for a module
to reverse the sense of a poll event from a read to a write or
vice versa.

The general idea of the patch is good. Unfortunately, the current
version doesn't have much effect. The problem is that the core output
filter, which does all the decisions about buffering, flushing,
blocking, and async write completion, comes after the ssl output
filter. Therefore core_output_filter only sees encrypted data and
never sees file buckets. Therefore it will only do async write
completion if the encrypted data left to send for a request is less
than THRESHOLD_MAX_BUFFER (64k).

To be more efficient the order of the filter doing the
buffering/flushing decitions and the ssl output filter would have to
be reversed. I haven't looked how this could be achieved. Maybe
mod_ssl would have to do its encryption in a AP_FTYPE_NETWORK filter
that comes after the core_output_filter().

Does it make sense to backport the current state nonetheless? While it
seems likely to me that the current API would be sufficient even if
this issue is fixed, it may be prudent to wait with a backport until
we know how the issue should be fixed exactly.


As a related issue, I have noticed that even without ssl, async write
completion does not work too well at the moment. The reason seems that
EnableSendfile/EnableMMAP default to off/on respectively, and that the
core_output_buffer does not treat MMAP buckets like it would treat
file buckets. AFAICS, there is no facility in apr to create anonymous
mmaps and we can assume that an apr_mmap_t is always backed by a file.
Is this correct? I think on some OSs, mmaping /dev/null gives an
anonymous mapping. Can we ignore that case for the purpose of deciding
how much memory a bucket needs?

Cheers,
Stefan


minfrin at sharp

Aug 4, 2013, 3:37 PM

Post #2 of 6 (43 views)
Permalink
Re: r1470679, async write completion, non blocking writes, and mod_ssl [In reply to]

On 04 Aug 2013, at 8:52 PM, Stefan Fritsch <sf [at] sfritsch> wrote:

> Hi,
>
> I did some testing/reviewing of the ssl/event backport proposal
>
> * core, mod_ssl: Lift the restriction that prevents mod_ssl taking
> full advantage of the event MPM. Enable the ability for a module
> to reverse the sense of a poll event from a read to a write or
> vice versa.
>
> The general idea of the patch is good. Unfortunately, the current
> version doesn't have much effect. The problem is that the core output
> filter, which does all the decisions about buffering, flushing,
> blocking, and async write completion, comes after the ssl output
> filter. Therefore core_output_filter only sees encrypted data and
> never sees file buckets. Therefore it will only do async write
> completion if the encrypted data left to send for a request is less
> than THRESHOLD_MAX_BUFFER (64k).
>
> To be more efficient the order of the filter doing the
> buffering/flushing decitions and the ssl output filter would have to
> be reversed. I haven't looked how this could be achieved. Maybe
> mod_ssl would have to do its encryption in a AP_FTYPE_NETWORK filter
> that comes after the core_output_filter().
>
> Does it make sense to backport the current state nonetheless? While it
> seems likely to me that the current API would be sufficient even if
> this issue is fixed, it may be prudent to wait with a backport until
> we know how the issue should be fixed exactly.

Are you seeing a specific problem?

The way openssl's async behaviour works, is that is the middle of a read, openssl might need to write, and in the middle of a write, openssl might need to read. Openssl tells you this through the codes SSL_ERROR_WANT_READ and SSL_ERROR_WANT_WRITE. You receive these codes, re-run the select or poll or whatever with the sense that openssl has asked for, and you're done. It is that simple.

Sure, httpd might do all sorts of buffering of reads and writes, but at the end of the day it won't matter, because openssl will never attempt to write-during read or read-during-write without asking you whether it is ok first.

I can see a potential problem if the core decided to buffer a write, but in theory that could be solved by mod_ssl simply sending a flush bucket down the stack whenever the sense changes. I don't see why the core needs to care that the data is a file, or encrypted, or whatever, the core should just do what the core does.

Regards,
Graham
--


sf at sfritsch

Aug 5, 2013, 1:00 AM

Post #3 of 6 (40 views)
Permalink
Re: r1470679, async write completion, non blocking writes, and mod_ssl [In reply to]

On Mon, 5 Aug 2013, Graham Leggett wrote:
> Are you seeing a specific problem?

Well, when I download a large file over a slow link, the request does not
enter write completion state but rather the worker thread is still hogged
for (nearly) the entire download.

> The way openssl's async behaviour works, is that is the middle of a
> read, openssl might need to write, and in the middle of a write, openssl
> might need to read. Openssl tells you this through the codes
> SSL_ERROR_WANT_READ and SSL_ERROR_WANT_WRITE. You receive these codes,
> re-run the select or poll or whatever with the sense that openssl has
> asked for, and you're done. It is that simple.

AFAICT, that part is ok. But it doesn't solve the problem that one thread
is hogged for every ssl connection.

> Sure, httpd might do all sorts of buffering of reads and writes, but at
> the end of the day it won't matter, because openssl will never attempt
> to write-during read or read-during-write without asking you whether it
> is ok first.
>
> I can see a potential problem if the core decided to buffer a write, but
> in theory that could be solved by mod_ssl simply sending a flush bucket
> down the stack whenever the sense changes. I don't see why the core
> needs to care that the data is a file, or encrypted, or whatever, the
> core should just do what the core does.

Let me recap the way async works in mpm event: There is no way to
interrupt and resume the handler, so the handler always must run to
completion. The only way async write completion can work is if the data
produced by the handler is buffered and is later sent bit by bit in an
async way. However, this cannot be done unconditionally or the memory
usage would grow to infinity. Therefore the core output filter has some
heuristics on when to buffer data for async write completion and when to
do blocking writes instead. In general, if there is more than 64k of data
in memory, this is written to the network in a blocking way. Only if the
buckets are backed by files (and therefore do not use significant memory
before being sent to the network), more than 64k of request data is put
into async write completion.

This is where mod_ssl comes in. It will read the file buckets, encrypt
them, and then we have encrypted data in memory that will cause the core
output filters to do blocking writes. The blocking writes happen while the
handler does ap_pass_brigade() and therefore before the worker thread
which executes the handler is freed.

An ideal solution would put the buffering/decision for
blocking/non-blocking into ap_pass_brigade(). This way other filters like
deflate could also be called asynchronously. But I am not too optimistic
that this can be achieved without API changes.


jim at jaguNET

Aug 5, 2013, 6:57 AM

Post #4 of 6 (40 views)
Permalink
Re: r1470679, async write completion, non blocking writes, and mod_ssl [In reply to]

On Aug 5, 2013, at 4:00 AM, Stefan Fritsch <sf [at] sfritsch> wrote:
>
> An ideal solution would put the buffering/decision for
> blocking/non-blocking into ap_pass_brigade(). This way other filters like
> deflate could also be called asynchronously. But I am not too optimistic
> that this can be achieved without API changes.
>

Agreed, but from what I can see the proposed patch does
add some benefit, allows for future improvement, adds no
overhead and no bugs. As such, even though it doesn't completely
solve the whole issue, it is valuable enough to be folded into
2.4. (imo 'natch)


sf at sfritsch

Aug 5, 2013, 1:50 PM

Post #5 of 6 (40 views)
Permalink
Re: r1470679, async write completion, non blocking writes, and mod_ssl [In reply to]

Am Montag, 5. August 2013, 09:57:16 schrieb Jim Jagielski:
> On Aug 5, 2013, at 4:00 AM, Stefan Fritsch <sf [at] sfritsch> wrote:
> > An ideal solution would put the buffering/decision for
> > blocking/non-blocking into ap_pass_brigade(). This way other
> > filters like deflate could also be called asynchronously. But I
> > am not too optimistic that this can be achieved without API
> > changes.
>
> Agreed, but from what I can see the proposed patch does
> add some benefit, allows for future improvement, adds no
> overhead and no bugs. As such, even though it doesn't completely
> solve the whole issue, it is valuable enough to be folded into
> 2.4. (imo 'natch)

It gives us a new API that we need to keep. But if you and Graham both
think that this is a good tradeoff, then that's fine with me. But I
want to test one more thing before I vote +1. Hopefully I will have
some time for that next week-end.

The wording of CHANGES and the docs need to be adjusted, though.


jim at jaguNET

Aug 7, 2013, 6:35 AM

Post #6 of 6 (32 views)
Permalink
Re: r1470679, async write completion, non blocking writes, and mod_ssl [In reply to]

On Aug 5, 2013, at 4:50 PM, Stefan Fritsch <sf [at] sfritsch> wrote:
>
> It gives us a new API that we need to keep.

I think it's a useful API, but ymmv

Apache dev RSS feed   Index | Next | Previous | View Threaded
 
 


Interested in having your list archived? Contact Gossamer Threads
 
  Web Applications & Managed Hosting Powered by Gossamer Threads Inc.