[tahoe-dev] [tahoe-lafs] #392: pipeline upload segments to make upload faster

tahoe-lafs trac at allmydata.org
Wed Apr 15 20:10:20 UTC 2009

#392: pipeline upload segments to make upload faster
 Reporter:  warner            |           Owner:  warner    
     Type:  enhancement       |          Status:  new       
 Priority:  major             |       Milestone:  eventually
Component:  code-performance  |         Version:  1.0.0     
 Keywords:  speed             |   Launchpad_bug:            

Comment(by warner):

 So, using the attached patch, I added pipelined writes to the immutable
 upload operation. The {{{Pipeline}}} class allows up to 50KB in the pipe
 before it starts blocking the sender (specifically, the calls to
 {{{WriteBucketProxy._write}}} return {{{defer.succeed}}} until there is
 than 50KB of unacknowledged data in the pipe, after which it returns
 Deferreds until some of those writes get retired. A terminal {{{flush()}}}
 call causes the Upload to wait for the pipeline to drain before it is
 considered complete).

 A quick performance test (in the same environments that we do the buildbot
 performance tests on: my home DSL line and tahoecs2 in colo) showed a
 significant improvement in the DSL per-file overhead, but only about a 10%
 improvement in the overall upload rate (for both DSL and colo).

 Basically, the 7 writes used to write a small file (header, segment 0,
 crypttext_hashtree, block_hashtree, share_hashtree, uri_extension, close)
 all put on the wire together, so they take bandwidth plus 1 RTT instead of
 bandwidth plus 7 RTT. The savings of 6 RTT appears to save us about 1.8
 seconds over my DSL line. (my ping time to the servers is about 11ms, but
 then there's kernel/python/twisted/foolscap/tahoe overhead on top of

 For a larger file, pipelining might increase the utilization of the wire,
 particularly if you have a "long fat" pipe (high bandwidth but high
 However, with 10 shares going out at the same time, the wire is probably
 pretty full already: the ratio of interest is segsize*N/k/BW / RTT . You
 N blocks for a single segment at once, then you wait for all the replies
 come back, then generate the next blocks. If the time it takes to send a
 single block is greater than the server's turnaround time, then N-1
 will be received before the last block is finished sending, so you've only
 got one RTT of idle time (while you wait for the last server to respond).
 Pipelining will fill this last RTT, but my guess is that isn't that much
 of a
 help, and that something else is needed to explain the performance hit we
 in colo when we moved to larger segments.

 DSL no pipelining:

 TIME (startup): 2.36461615562 up, 0.719145059586 down
 TIME (1x 200B): 2.38471603394 up, 0.734190940857 down
 TIME (10x 200B): 21.7909920216 up, 8.98366594315 down
 TIME (1MB): 45.8974239826 up, 5.21775698662 down
 TIME (10MB): 449.196600914 up, 34.1318571568 down
 upload per-file time: 2.179s
 upload speed (1MB): 22.87kBps
 upload speed (10MB): 22.37kBps

 DSL with pipelining:

 TIME (startup): 0.437352895737 up, 0.185742139816 down
 TIME (1x 200B): 0.493880987167 up, 0.202013969421 down
 TIME (10x 200B): 5.15211510658 up, 2.04516386986 down
 TIME (1MB): 43.141931057 up, 2.09753513336 down
 TIME (10MB): 416.777194977 up, 19.6058299541 down
 upload per-file time: 0.515s
 upload speed (1MB): 23.46kBps
 upload speed (10MB): 24.02kBps

 The in-colo tests showed roughly the same improvement to upload speed, but
 very little change to the per-file time. The RTT time there is shorter
 time is about 120us), which might explain the difference. But I think the
 slowdown lies elsewhere. Pipelining shaves about 30ms off each file, and
 increases the overall upload speed by about 10%.

 colo no pipelining:

 TIME (startup): 0.29696393013 up, 0.0784759521484 down
 TIME (1x 200B): 0.285771131516 up, 0.0790619850159 down
 TIME (10x 200B): 3.23165798187 up, 0.849181175232 down
 TIME (100x 200B): 31.7827451229 up, 8.95765590668 down
 TIME (1MB): 1.00738477707 up, 0.347244977951 down
 TIME (10MB): 7.12743496895 up, 2.9827849865 down
 TIME (100MB): 70.9683670998 up, 25.6454920769 down
 upload per-file time: 0.318s
 upload per-file times-avg-RTT: 83.833386
 upload per-file times-total-RTT: 20.958347
 upload speed (1MB): 1.45MBps
 upload speed (10MB): 1.47MBps
 upload speed (100MB): 1.42MBps

 colo with pipelining:

 TIME (startup): 0.262734889984 up, 0.0758249759674 down
 TIME (1x 200B): 0.271718025208 up, 0.0812950134277 down
 TIME (10x 200B): 2.80361104012 up, 0.838641881943 down
 TIME (100x 200B): 28.4790999889 up, 9.36092710495 down
 TIME (1MB): 0.853738069534 up, 0.337486028671 down
 TIME (10MB): 6.6658270359 up, 2.67381596565 down
 TIME (100MB): 64.6233050823 up, 26.5593090057 down
 upload per-file time: 0.285s
 upload per-file times-avg-RTT: 77.205647
 upload per-file times-total-RTT: 19.301412
 upload speed (1MB): 1.76MBps
 upload speed (10MB): 1.57MBps
 upload speed (100MB): 1.55MBps

 I want to run some more tests before landing this patch, to make sure it's
 really doing what I though it should be doing. I'd also like to improve
 automated speed-test to do a simple TCP transfer to measure the available
 upstream bandwidth, so we can compare tahoe's upload speed against the

Ticket URL: <http://allmydata.org/trac/tahoe/ticket/392#comment:3>
tahoe-lafs <http://allmydata.org>
secure decentralized file storage grid

More information about the tahoe-dev mailing list