<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">(waking up from post-holiday coma :-)) ... Happy 2014!<br><br>On Fri, Dec 20, 2013 at 12:49 PM, Alex <span dir="ltr"><<a href="mailto:alex@zeitgeist.se" target="_blank">alex@zeitgeist.se</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div><span style="color:rgb(80,0,80)">> This would require a bit more work than the current patch, but I'd love to see a similar strategy in nginx. Hardcoding a fixed record size will inevitably lead to suboptimal delivery of either interactive or bulk traffic. Thoughts?</span><br>
<font color="#500050"><br></font><span style="color:rgb(80,0,80)">It'd be interesting to know how difficult it'd be to implement such a</span><br><span style="color:rgb(80,0,80)">dynamic behavior of the SSL buffer size. An easier, albeit less optimal</span><br>
<span style="color:rgb(80,0,80)">solution would be to adjust the ssl_buffer_size directive depending on</span><br><span style="color:rgb(80,0,80)">the request URI (via location blocks). Not sure if Maxim's patch would</span><br>
<span style="color:rgb(80,0,80)">allow for that already? If large files are served from a known request</span><br><span style="color:rgb(80,0,80)">URI pattern, you could then increase the SSL buffer size accordingly for</span><br>
<div class="im">
that location.</div></div></blockquote><br>No, ssl_buffer_size is a server-wide directive [1]. Further, I don't think you want to go down this path: just because you're serving a large stream does not mean you don't want a fast TTFB at the beginning of the stream. For example, for video streaming you still want to optimize for the "time to first frame" such that you can decode the stream headers and get the video preview / first few frames on the screen as soon as possible. That said, once you've got the first few frames on screen, then by all means, max out the record size to decrease framing overhead. In short, for best performance, you want dynamic behavior.<br>
<br>[1] <a href="http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_buffer_size" target="_blank">http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_buffer_size</a><br><br><span style="color:rgb(80,0,80)">On Sun, Dec 22, 2013 at 2:27 PM, Maxim Dounin </span><span dir="ltr" style="color:rgb(80,0,80)"><<a href="mailto:mdounin@mdounin.ru" target="_blank">mdounin@mdounin.ru</a>></span><span style="color:rgb(80,0,80)"> wrote:</span><br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div>
<div class="gmail_extra"><div class="gmail_quote"><div><div class="h5">> Awesome, really glad to see this! A couple of followup questions...<br>><br>> (a) Is there any way to force a packet flush on record end? At the moment<br>
> nginx will fragment multiple records across packet boundaries, which is<br>> suboptimal as it means that I need a minimum of two packets to decode any<br>> record - e.g. if I set my record size to 1370 bytes, the first packet will<br>
> contain the first full record plus another 20-50 bytes of next record.<br><br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
</blockquote>There is OpenSSL socket layer on the way down. It may be possible<br><blockquote class="gmail_quote " style="margin:0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;border-right-width:1px;border-right-color:rgb(204,204,204);border-right-style:solid;padding-left:1ex;padding-right:1ex">
</blockquote>to achieve something with SSL_[CTX_]set_max_send_fragment() in<br><blockquote class="gmail_quote " style="margin:0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;border-right-width:1px;border-right-color:rgb(204,204,204);border-right-style:solid;padding-left:1ex;padding-right:1ex">
</blockquote>OpenSSL 1.0.0+, but I haven't looked into details. (As I already<br><blockquote class="gmail_quote " style="margin:0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;border-right-width:1px;border-right-color:rgb(204,204,204);border-right-style:solid;padding-left:1ex;padding-right:1ex">
</blockquote>said, I don't think that using packet-sized records is a good<br><blockquote class="gmail_quote " style="margin:0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;border-right-width:1px;border-right-color:rgb(204,204,204);border-right-style:solid;padding-left:1ex;padding-right:1ex">
</blockquote>idea, it looks like an overkill and waste of resources, both<br>
network and CPU.)> (b) Current NGX_SSL_BUFSIZE is set to 16KB which is effectively guaranteed<br>> to overflow the CWND of a new connection and introduce another RTT for<br>> interactive traffic - e.g. HTTP pages. I would love to see a lower starting<br>
> record size to mitigate this problem -- defaults matter!<br><br><blockquote class="gmail_quote " style="margin:0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;border-right-width:1px;border-right-color:rgb(204,204,204);border-right-style:solid;padding-left:1ex;padding-right:1ex">
</blockquote>We are considering using 4k or 8k as the default in the<br><blockquote class="gmail_quote " style="margin:0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;border-right-width:1px;border-right-color:rgb(204,204,204);border-right-style:solid;padding-left:1ex;padding-right:1ex">
</blockquote>future. For now, the directive is mostly to simplify<br><blockquote class="gmail_quote " style="margin:0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;border-right-width:1px;border-right-color:rgb(204,204,204);border-right-style:solid;padding-left:1ex;padding-right:1ex">
</blockquote>experimenting with various buffer sizes.<br><br>> On the subject of optimizing record size, the GFE team at Google recently<br>> landed ~following logic:<br>><br>> - new connections default to small record size<br>
> -- each record fits into a TCP packet<br>> -- packets are flushed at record boundaries<br>> - server tracks number of bytes written since reset and timestamp of last<br>> write<br>> -- if bytes written > {configurable byte threshold) then boost record size<br>
> to 16KB<br>> -- if last write timestamp > now - {configurable time threshold} then reset<br>> sent byte count<br>><br>> In other words, start with small record size to optimize for delivery of<br>> small/interactive objects (bulk of HTTP traffic). Then, if large file is<br>
> being transferred bump record size to 16KB and continue using that until<br>> the connection goes idle.. when communication resumes, start with small<br>> record size and repeat. Overall, this is aimed to optimize delivery of<br>
> small files where incremental delivery is a priority, and also for large<br>> downloads where overall throughput is a priority.<br>><br>> Both byte and time thresholds are exposed as configurable flags, and<br>
> current defaults in GFE are 1MB and 1s.<br>><br>> This would require a bit more work than the current patch, but I'd love to<br>> see a similar strategy in nginx. Hardcoding a fixed record size will<br>
> inevitably lead to suboptimal delivery of either interactive or bulk<br>
> traffic. Thoughts?<br><br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
</blockquote>While some logic like this is certainly needed to use packet-sized<br><blockquote class="gmail_quote " style="margin:0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;border-right-width:1px;border-right-color:rgb(204,204,204);border-right-style:solid;padding-left:1ex;padding-right:1ex">
</blockquote>records, it looks overcomplicated and probably not at all needed<br>
with 4k/8k buffers.<br></div></div></div></div></div></blockquote><font color="#500050"><br></font>This logic is not at all specific to packet-sized records -- that said, yes, it delivers most benefit when you are starting the session with a packet-sized record. For sake of an example, let's say we set the new default to 4k: <br>
<br>+ all records will fit into a minimum CWND (IW4 and IW10)<br>- packet loss is still a factor and may affect TTFB, but impact is much less than current 16KB record.<br>- we incur fixed 4x overhead (bytes and CPU cycles) on large streams<br>
<br>The "dynamic" implementation simply addresses the last two shortcomings: (a) using a packet-size record guarantees that we deliver the best TTFB, and (b) we minimize the CPU/byte overhead costs of smaller records by raising record size once connection is "warmed up". Further, I think it's misleading to say that "for large streams, just use a larger default record"... as I noted above, even large streams (e.g. video) need a fast time to first byte/frame.<br>
<br>I think its important that we optimize for the out-of-the box performance/experience: your average web developer / system admin won't know what record size to set for their use case, and they'll have a mix of payloads which don't lend themselves to any one record size. Besides, any static value will inevitably lead to a tradeoff in TTFB or throughput, which is an unnecessary trade-off to begin with.<br>
<br>If we want configuration knobs, then as advanced options, offer ability to customize the "boost threshold" (in KB), and inactivity timeout (to revert back to smaller size). Finally, if you want, the definition of "small record" could be a flag as well - setting it to 16KB would effectively disable the logic and give you current behavior... Yes, this is more complex than just setting a static record size, but the performance gains are significant both in throughput and latency -- and after all, isn't that what nginx is all about? :)
</div><div class="gmail_quote"><br></div><div class="gmail_quote">ig</div><br></div></div>