-
-
Notifications
You must be signed in to change notification settings - Fork 931
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve SFTP performance on medium/high latency connections #866
Improve SFTP performance on medium/high latency connections #866
Conversation
Avery nice performance boost! This has been a complaint for a long time
… On Aug 30, 2021, at 3:41 PM, zybexXL ***@***.***> wrote:
@zybexXL commented on this pull request.
In src/Renci.SshNet/ServiceFactory.cs <#866 (comment)>:
> @@ -132,7 +132,7 @@ public ISftpFileReader CreateSftpFileReader(string fileName, ISftpSession sftpSe
{
var fileAttributes = sftpSession.EndLStat(statAsyncResult);
fileSize = fileAttributes.Size;
- maxPendingReads = Math.Min(10, (int) Math.Ceiling((double) fileAttributes.Size / chunkSize) + 1);
+ maxPendingReads = Math.Min(100, (int)Math.Ceiling((double)fileAttributes.Size / chunkSize) + 1);
this line is also changed on PR #864 <#864> - here <https://github.com/sshnet/SSH.NET/pull/864/files#diff-abfc42015c3bccaae3e2012df18a1b2a24d66c6effb9ef5e30cbe6516023f967R135>
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub <#866 (review)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AAD7IHSQNLHAOK4ITGGLEWDT7PNHPANCNFSM5DCO2DGA>.
Triage notifications on the go with GitHub Mobile for iOS <https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675> or Android <https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub>.
|
@@ -59,7 +59,7 @@ private void SetupMocks() | |||
.Setup(p => p.EndLStat(_statAsyncResult)) | |||
.Throws(new SshException()); | |||
_sftpSessionMock.InSequence(seq) | |||
.Setup(p => p.CreateFileReader(_handle, _sftpSessionMock.Object, _chunkSize, 3, null)) | |||
.Setup(p => p.CreateFileReader(_handle, _sftpSessionMock.Object, _chunkSize, 10, null)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note: This value needs to be the same as ServiceFactory.cs:115
|
||
private void SetupData() | ||
{ | ||
var random = new Random(); | ||
|
||
_maxPendingReads = 100; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note: This value needs to be the same as ServiceFactory.cs:145
I've renamed this testcase to match what it does
@zybexXL Could you check how many read-aheads putty performs? I recall that it does not perform that many, but I could be wrong. How does it compare with SSH.NET on speed/throughput ? |
@drieseng, according to Wireshark, EDIT: I'm running tests with psftp now - it seems it only sends a couple of read-aheads, and it's much slower than Filezilla. I'll post results soon. |
Confirmed, psftp sends only a single read request and waits for the data to arrive before sending another one. There's always a gap of a few ms between each 32KB block; this is not that bad when the server is close, but for distant servers and fast connections it just kills the speed. It ends up at about half-speed compared to this PR. For SSH.NET with/without this patch, see benchmarks on top post. Filezilla, with the 128 read-aheads, has identical speed to SSH.NET with #865 and #866 applied. Ideally the number of read-aheads should be dynamic to adjust to distance+speed automatically. That could be explored in a future PR, perhaps needed when 10Gbit speeds become common. |
Just for future reference, here is how the dotnet team tackled a similar issue in HTTP/2: https://devblogs.microsoft.com/dotnet/dotnet-6-networking-improvements/ |
Any updates on merging this one to the main branch? We are using SSH.NET for one of our tools in our build pipeline and we can clearly see a speed difference between FileZilla and SSH.NET. We could switch to this branch off course, but it's more pleasent to just include the NuGet package. |
Code doesn't compile for me, complaining about target frameworks being empty |
I just pulled the branch and compiled in VS2019 with no problem. This code does not touch any Framework/Project config file. |
I have tested this and it works! |
@drieseng Are we able to get this reviewed and added for a future release? Are there pending issues/concerns that can be addressed? |
- Increases maxPendingReads from 10 to 100 - Increases socket send/receive buffer to 10 SSH packets (320K)
0258824
to
58c0b4f
Compare
I've rebased this PR, please review and consider merging. |
The 2023.0.1 version has been released to Nuget: https://www.nuget.org/packages/SSH.NET/2023.0.1 |
This PR changes just 2 constants:
This results in huge improvements in transfer speeds when using sftpClient.DownloadFile/UploadFile, in particular with fast local internet connections and remote servers with high latency. The results are even better when used together with PR #865 - speeds are now comparable with Filezilla.
I tested on two servers: a relatively close one (Frankfurt) and a distant one (AWS-hosted SFTP Server). Here are the results:
The 500Mbps link is satisfyingly saturated when combining these 2 PRs! 😎
Reasoning
1. Increasing the socket send/receive buffer size
This change has low impact. This buffer holds packets that have been received and are waiting to be processed by the application. In cases where the machine is temporarily bogged down, it may happen that the incoming packets are not processed quickly enough and the previous 2-packet buffer gets full, and a 3rd incoming packet then causes the connection to stall. Increasing the buffer to 10 packets reduces the probability of this scenario, and makes the transfer more smooth and resilient to hiccups in CPU usage.
2. Increasing the maxPendingReads
This setting controls the maximum number of SFTP Read Requests that are sent to the server and are yet unanswered. When a packet arrives at the client, it sends another request for the next packet. In other words, it's the maximum number of in-flight data packets.
Each SFTP data packet is 32KB in size, so maxPendingReads=10 means that there's a maximum of 320 KB in flight before the transfer stalls. With 100, this is raised to 3.2MB in flight.
Modern internet connections are FAST. Transferring 320KB at 100Mbps takes about 30ms, and at 500Mbps it takes just 6.4ms (plus latency, ignoring details). This means that when talking to a server that is 100ms away this happens:
The numbers are not accurate and I'm ignoring lots of detail but you get the idea. 320KB of in-flight data is just not suitable for today's fast connections anymore. Raising it to ~3.2MB fixes this problem (for now), and restores performance on distant servers.