diff options
| author | Owen Jacobson <owen.jacobson@grimoire.ca> | 2015-07-03 22:31:49 -0400 |
|---|---|---|
| committer | Owen Jacobson <owen.jacobson@grimoire.ca> | 2015-07-03 22:35:09 -0400 |
| commit | 76aed6ef732de38d82245b3d674f70bab30221e5 (patch) | |
| tree | d50e9a296d91ef8a49bcb29c3e80096f200a3c26 /.html/dev/buffers.html | |
| parent | 92f66d3e3a0996bb1fad9dc83d7e184f92673e5d (diff) | |
Fuck it, serve the files directly.
Diffstat (limited to '.html/dev/buffers.html')
| -rw-r--r-- | .html/dev/buffers.html | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/.html/dev/buffers.html b/.html/dev/buffers.html new file mode 100644 index 0000000..839eefd --- /dev/null +++ b/.html/dev/buffers.html @@ -0,0 +1,202 @@ +<!DOCTYPE html> +<html> +<head> + <title> + The Codex ยป + Observations on Buffering + </title> + + <link + rel='stylesheet' + type='text/css' + href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> + <link + rel="stylesheet" + type="text/css" + href="../media/css/reset.css"> + <link + rel="stylesheet" + type="text/css" + href="../media/css/grimoire.css"> +</head> +<body> + +<div id="shell"> + + <ol id="breadcrumbs"> + + <li class="crumb-0 not-last"> + + <a href="../">index</a> + + </li> + + <li class="crumb-1 not-last"> + + <a href="./">dev</a> + + </li> + + <li class="crumb-2 last"> + + buffers + + </li> + + </ol> + + + + <div id="article"> + <h1 id="observations-on-buffering">Observations on Buffering</h1> +<p>None of the following is particularly novel, but the reminder has been useful:</p> +<ul> +<li> +<p>All buffers exist in one of two states: full (writes outpace reads), or empty + (reads outpace writes). There are no other stable configurations.</p> +</li> +<li> +<p>Throughput on an empty buffer is dominated by the write rate. Throughput on a + full buffer is dominated by the read rate.</p> +</li> +<li> +<p>A full buffer imposes a latency penalty equal to its size in bits, divided by + the read rate in bits per second. An empty buffer imposes (approximately) no + latency penalty.</p> +</li> +</ul> +<p>The previous three points suggest that <strong>traffic buffers should be measured in +seconds, not in bytes</strong>, and managed accordingly. Less obviously, buffer +management needs to be considerably more sophisticated than the usual "grow +buffer when full, up to some predefined maximum size."</p> +<p>Point one also implies a rule that I see honoured more in ignorance than in +awareness: <strong>you can't make a full buffer less full by making it bigger</strong>. Size +is not a factor in buffer fullness, only in buffer latency, so adjusting the +size in response to capacity pressure is worse than useless.</p> +<p>There are only three ways to make a full buffer less full:</p> +<ol> +<li> +<p>Increase the rate at which data exits the buffer.</p> +</li> +<li> +<p>Slow the rate at which data enters the buffer.</p> +</li> +<li> +<p>Evict some data from the buffer.</p> +</li> +</ol> +<p>In actual practice, most full buffers are upstream of some process that's +already going as fast as it can, either because of other design limits or +because of physics. A buffer ahead of disk writing can't drain faster than the +disk can accept data, for example. That leaves options two and three.</p> +<p>Slowing the rate of arrival usually implies some variety of <em>back-pressure</em> on +the source of the data, to allow upstream processes to match rates with +downstream processes. Over-large buffers delay this process by hiding +back-pressure, and buffer growth will make this problem worse. Often, +back-pressure can happen automatically: failing to read from a socket, for +example, will cause the underlying TCP stack to apply back-pressure to the peer +writing to the socket by delaying TCP-level message acknowledgement. Too often, +I've seen code attempt to suppress these natural forms of back-pressure without +replacing them with anything, leading to systems that fail by surprise when +some other resource โ usually memory โ runs out.</p> +<p>Eviction relies on the surrounding environment, and must be part of the +protocol design. Surprisingly, most modern application protocols get very +unhappy when you throw their data away: the network age has not, sadly, brought +about protocols and formats particularly well-designed for distribution.</p> +<p>If neither back-pressure nor eviction are available, the remaining option is to +fail: either to start dropping data unpredictably, or to cease processing data +entirely as a result of some resource or another running out, or to induce so +much latency that the data is useless by the time it arrives.</p> +<hr> +<p>Some uncategorized thoughts:</p> +<ul> +<li> +<p>Some buffers exist to trade latency against the overhead of coordination. A + small buffer in this role will impose more coordination overhead; a large + buffer will impose more latency.</p> +<ul> +<li> +<p>These buffers appear where data transits between heterogenous system: for + example, buffering reads from the network for writes to disk.</p> +</li> +<li> +<p>Mismanaged buffers in this role will tend to cause the system to spend + an inordinate proportion of latency and throughput negotiating buffer + sizes and message readiness.</p> +</li> +<li> +<p>A coordination buffer is most useful when <em>empty</em>; in the ideal case, the + buffer is large enough to absorb one message's worth of data from the + source, then pass it along to the sink as quickly as possible.</p> +</li> +</ul> +</li> +<li> +<p>Some buffers exist to trade latency against jitter. A small buffer in this + role will expose more jitter to the upstream process. A large buffer in this + role will impose more latency.</p> +<ul> +<li> +<p>These tend to appear in <em>homogenous</em> systems with differing throughputs, + or as a consequence of some other design choice. Store-and-forward + switching in networks, for example, implies that switches must buffer at + least one full frame of network data.</p> +</li> +<li> +<p>Mis-managed buffers in this role will <em>amplify</em> rather than smoothing out + jitter. Apparent throughput will be high until the buffer fills, then + change abruptly when full. Upstream processes are likely to throttle + down, causing them to under-deliver if the buffer drains, pushing the + system back to a high-throughput mode. <a href="http://www.bufferbloat.net">This problem gets worse the + more buffers are present in a system</a>.</p> +</li> +<li> +<p>An anti-jitter buffer is most useful when <em>full</em>; in exchange for a + latency penalty, sudden changes in throughput will be absorbed by data + in the buffer rather than propagating through to the source or sink.</p> +</li> +</ul> +</li> +<li> +<p>Multimedia people understand this stuff at a deep level. Listen to them when + designing buffers for other applications.</p> +</li> +</ul> + </div> + + + +<div id="comments"> +<div id="disqus_thread"></div> +<script type="text/javascript"> + /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ + var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname + + /* * * DON'T EDIT BELOW THIS LINE * * */ + (function() { + var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; + dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; + (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); + })(); +</script> +<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> +<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> +</div> + + + + <div id="footer"> + <p> + + The Codex โ + + Powered by <a href="http://markdoc.org/">Markdoc</a>. + +<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/buffers.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/buffers.md">history</a>). + + </p> + </div> + +</div> +</body> +</html>
\ No newline at end of file |
