[Solved] Ssh2 rust is slow to connect (10x slower than PHP)


#1

Hey everyone,

Today’s issue is a weird one that I don’t really understand.

First let’s begin with the code:

    let tcp = TcpStream::connect("127.0.0.1:22").unwrap();
    let mut sess = Session::new().unwrap();
    sess.handshake(&tcp).unwrap();

    sess.userauth_password("account", "password").unwrap();

    let sftp = sess.sftp().unwrap();

Library used: ssh2

This code works fine.
BUT the goal of using Rust for my own server as a backend was to learn Rust and gain or have the same performance as PHP.

The issue is:

  • PHP does the connection in 0.03 seconds (which seems fine as it is on the same computer)
  • Rust does the connection in 0.3 seconds (Yes, 10 times slower)

I guess this either comes from the wrapper or from libssh2 itself (which I don’t know how to test)

Does any of you could guide on what is going on here ? Maybe someone knows how to use libssh2 in C and calculate the time it takes on Rust and on C ?

I have tried to see if it was optimization so I ran it with “cargo run --release” but nothing changed.

My idea to go around this issue was to keep the user connected for as long as he is connected to the website (this means that the connection is not drop at all between request, which I don’t really like)

I manly wanted to use the ssh2 library because it has sftp functions and I wanted to use those.
I will try out thrussh to see if it works better but I have no idea yet on how I will manage file transfer with thrussh…

Thanks in advance!

EDIT: Just tested out with my laptop. same exact result (almost). I got 0.2 seconds. Still way too much compared to the 0.03 of PHP (tested with a local rust and local ssh server, just like my server/website setup)


#2

Are you timing running your binary directly or running cargo run?


#3

I am using cargo run.

EDIT: Just tried to run the binary directly, same result.


#4

Is the PHP version also doing a handshake?


#5

Actually I am not very smart… The PHP version is using ftps… (which also takes 0.05 seconds on Rust but the nlist and list function don’t work.

I would like to know if I can locally test the connection speed to the ssh server. It seems like there is an issue here.

@vitalyd Let me do some quick time mesurements to see if the handshake is the issue, I’ll edit this when I have the answer.

EDIT: Time taken:

  • tcp stream connect: negligeable.
  • New session: negligeable.
  • Handshake: 0.07 seconds (a little bit high for a local handshake no ? or is the process simply slow ?)
  • User authentification: 0.02 seconds
  • new sftp connection: 0.20 seconds
  • executing the “ls” command and getting it’s result: 0.17 seconds (this one is quite high but it opens a channel and wait for it to be closed before returning)
    Without the ls execution, program still takes ~0.27 seconds to execute.
  • Reading a dir from sftp: negligeable.

Edit 2: corrected the time it took for sftp connection

Edit 3: After more investigation I found out the openning of a Channel Session could be the issue. It takes 0.16 seconds. Doing the ls command before the sftp connection speeds the connction BUT the channel session still takes 0.2 seconds to create. I’m guessing the sftp session creates a channel to use for most of the work.


#6

Even with regular commands, my system takes around 0.3 seconds, e.g. echo ls | sftp localhost or just ssh localhost ls.


#7

Well… That answers my question. I will maybe try another ssh server ? I don’t know if this will work.
I will also fix the rust-ftp crate in which I found a bug that rendered it useless for me (it doesn’t seem to be really active).
Do you have any idea of what could be better to manage files remotely ? and what is used instead of ftp ? (In local host I could simply go with the included IO functions)


#8

Random shot: Do you have UseDNS enabled on sshd?


#9

No, I already turned it off when I was searching for this issue :confused:

I tried with another server:
With dropbear, it takes .15 seconds (yay, only 5x slower than ftps (and not PHP like I was saying)).
The time it takes is on the handshake (0.10 seconds) sftp connection (0.05 seconds).

This is better, it tells us that Rust is not the issue here. But the ssh server and the way the handshake is done.

I still want ssh for my project because I want my website to be able to execute commands and do things. But I will need to find a way to keep the connection up for longer than a request (the rust server here is listening for JSON requests, it goes into an action handler where it creates the connection, does what it needs and goes out of scope which disconnects ssh. If the connection is established once and does not disconnect, speed won’t be an issue.

By the way: speed was a concern because it will slow down the file browsing in the file tree (because it is dynamic and only updates when it needs to (someone has clicked on a folder))

I’m sorry if I write too much :laughing:


#10

But I will need to find a way to keep the connection up for longer than a request (the rust server here is listening for JSON requests, it goes into an action handler where it creates the connection, does what it needs and goes out of scope which disconnects ssh.

OpenSSH supports multiplexing and persistent connections. See ControlMaster and ControlPersist in man ssh_config. I don’t know about libssh2 though.


#11

I don’t want to set it on the server side as the web app needs to be able to do this for any time of configuration. That’s why I would like to do it myself. I’ll see what libssh2 has to offer in more detail. For now the issue is mostly resolved as I know where it comes from. And it is not something I can easilsy get around.

On the website, someone will connect to his ssh server and it will go though mine before, so I don’t think it will be as quick as a localhost anyway.

I will document myself on multiplexing and persistent connections just to know how it works. Maybe it will be a way to do it. Hmmmmm. I’ll have to think about it.


#12

Multiplexing and persistent connections is a client-side feature (ssh_config, not sshd_config).