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.

Reply via email to