paramiko - 与系统的rsync/sftp/scp相比,sftp传输速度慢

5
我注意到,使用paramiko的sftp进行get或put时,无法获得与rsync / sftp / scp / finder相同的传输速度。在我们的千兆网络中,通过mac mini服务器(运行Mac os 10.12.6)进行文件传输,可以持续达到95-100MB / sec。如果我使用paramiko的sftp.get,则其最大速度为25MB / sec。我曾使用paramiko 1.17,并升级到2.3.1,但速度基本相同。有什么想法可能会导致这种限制吗?谢谢!Adam

其他人也已经在多年前抱怨过这个问题。有一些可能的解决方案,例如在这里https://github.com/paramiko/paramiko/issues/175,但不确定是否有帮助。 - Hannu
Hannu,感谢你提供的链接。我也在GitHub和SO上找到了一些类似的建议,但是像更改window_size这样的建议都没有任何作用。希望有好消息。干杯! - adamteale
1
嗨@adamteale,这个问题解决了吗?我也遇到了同样的问题,增加window_size对我也没有任何影响,我仍然只能得到最大25MB/s的速度。我想要达到使用scp时相同的速度,超过50MB/s。你是否成功使用paramiko提高了速度? - Rogerio Hilbert
迄今为止有什么进展吗?我正在面对最新版本的相同问题,但我没有看到最近的相关问题。我是独自一人吗? - Krishna
1个回答

2

我遇到了同样的问题,并实现了其他人提出的一些建议。 可以做三件事:

  1. Increase the buffer size in your transport.

      transport = paramiko.Transport(ftp_host, ftp_port)
      transport.default_window_size = 4294967294 # 2147483647
      transport.packetizer.REKEY_BYTES = pow(2, 40)
      transport.packetizer.REKEY_PACKETS = pow(2, 40)
    
  2. Perform a read ahead prior to getting the file.

     ftp_file = ftp_conn.file(file_name, "r")  
     ftp_file_size = ftp_file.stat().st_size 
     ftp_file.prefetch(ftp_file_size)
     ftp_file.set_pipelined()  
     ftp_file_data = ftp_file.read(ftp_file_size)
    
  3. The other thing you can do when transferring larger files is implementing "chunks". This splits the files into smaller pieces that are transferred individually. I have only tested this with a transfer to s3.

     chunk_size = 6000000 #6 MB
     chunk_count = int(math.ceil(ftp_file_size / float(chunk_size)))
     multipart_upload = s3_conn.create_multipart_upload(Bucket=bucket_name, Key=s3_key_val)
     parts = []
     for i in range(chunk_count):
         print("Transferring chunk {}...".format(i + 1), "of ", chunk_count)
    
         start_time = time.time()
         ftp_file.prefetch(chunk_size * (i+1) # This statement is where the magic was to keep speeds high.
         chunk = ftp_file.read(int(chunk_size))
         part = s3_conn.upload_part(
             Bucket=bucket_name,
             Key=s3_file_path,
             PartNumber=part_number,
             UploadId=multipart_upload["UploadId"],
             Body=chunk
         )
         end_time = time.time()
         total_seconds = end_time - start_time
         print("speed is {} kb/s total seconds taken {}".format(math.ceil((int(chunk_size) / 1024) / total_seconds), total_seconds))
         part_output = {"PartNumber": i, "ETag": part["ETag"]}
         parts.append(part)
     print("Chunk {} Transferred Successfully!".format(i + 1))
    
     part_info = {"Parts": parts}
     s3_conn.complete_multipart_upload(
         Bucket=bucket_name,
         Key=s3_key_val,
         UploadId=multipart_upload["UploadId"],
         MultipartUpload=part_info
     )
    
处理数据块的重要部分是 ftp_file.prefetch(chunk_size * (i+1)),它会随着每次循环逐步向前读取更多数据。
实施所有这些之后,下载速度从200 kBps提高到5 MBps(最大隧道速度)。
在此代码的后续迭代中,我遇到了来自paramiko垃圾回收的问题。我通过删除该行解决了这些问题:
ftp_file.set_pipelined() 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接