Paramiko Не удается загрузить большие файлы> 1GB

def download(): if os.path.exists( dst_dir_path ) == False: logger.error( "Cannot access destination folder %s. Please check path and permissions. " % ( dst_dir_path )) return 1 elif os.path.isdir( dst_dir_path ) == False: logger.error( "%s is not a folder. Please check path. " % ( dst_dir_path )) return 1 file_list = None #transport = paramiko.Transport(( hostname, port)) paramiko.util.log_to_file('paramiko.log') ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) #transport try: ssh.connect( hostname, username=username, password=password, timeout=5.0) #transport.connect(username=username, password=password ) except Exception, err: logger.error( "Failed to connect to the remote server. Reason: %s" % ( str(err) ) ) return 1 try: #sftp = paramiko.SFTPClient.from_transport(transport) sftp = ssh.open_sftp() except Exception, err: logger.error( "Failed to start SFTP session from connection to %s. Check that SFTP service is running and available. Reason: %s" % ( hostname, str(err) )) return 1 try: sftp.chdir(src_dir_path) #file_list = sftp.listdir(path="%s" % ( src_dir_path ) ) file_list = sftp.listdir() except Exception, err: logger.error( "Failed to list files in folder %s. Please check path and permissions. Reason: %s" % ( src_dir_path, str(err) )) return 1 match_text = re.compile( file_mask ) download_count = 0 for file in file_list: # Here is an item name... but is it a file or directory? #logger.info( "Downloading file %s." % ( file ) ) if not re.match( file_mask, file ): continue else: logger.info( "File \"%s\" name matched file mask \"%s\". matches %s.Processing file..." % ( file, file_mask, (match_text.match( file_mask ) ) ) ) src_file_path = "./%s" % ( file ) dst_file_path = "/".join( [ dst_dir_path, file] ) retry_count = 0 while True: try: logger.info( "Downloading file %s to %s." % ( file, dst_file_path ) ) #sftp.get( file, dst_file_path, callback=printTotals ) #sftp.get( remote file, local file ) sftp.get( file, dst_file_path) #sftp.get( remote file, local file ) logger.info( "Successfully downloaded file %s to %s." % ( file, dst_file_path ) ) download_count += 1 break except Exception, err: if retry_count == retry_threshold: logger.error( "Failed to download %s to %s. Reason: %s." % ( file, dst_file_path, str(err) ) ) sftp.close() #transport.close() return 1 else: logger.error( "Failed to download %s to %s. Reason: %s." % ( file, dst_file_path, str(err) ) ) retry_count +=1 sftp.close() transport.close() logger.info( "%d files downloaded." % ( download_count ) ) return 0 

Когда я запускаю функцию ниже, она загружает исходный файл около 3 минут, а затем закрывает сеанс, хотя загружается только 38-41 МБ (изменяется) от 1-1,6 ГБ файла.

Из файла журнала Paramiko похоже, что соединение SSh остается открытым, а сеанс SFTP закрывается:

DEB [20120913-10: 05: 00.894] thr = 1 paramiko.transport: Переключиться на новые ключи … DEB [20120913-10: 05: 06.953] thr = 1 paramiko.transport: Rekeying (получено 401 пакетов, получено 1053444 байт ) DEB [20120913-10: 05: 07.391] thr = 1 paramiko.transport: kex algos: ['diffie-hellman-group1-sha1', 'diffie-hellman-group-exchange-sha1'] ключ сервера: ['ssh -dss '] client encrypt: [' aes256-ctr ',' aes192-ctr ',' aes128-ctr ',' aes256-cbc ',' aes192-cbc ',' aes128-cbc ',' twofish-cbc ',' 'blowfish-cbc', '3des-cbc', 'arcfour'] server encrypt: ['aes256-ctr', 'aes192-ctr', 'aes128-ctr', 'aes256-cbc', 'aes192-cbc', ' maca: ['hmac-sha1', 'hmac-sha1-96', 'hmac-md5 ',' hmac-md5-96 ',' umac-64@openssh.com '] сервер mac: [' hmac-sha1 ',' hmac-sha1-96 ',' hmac-md5 ',' hmac-md5-96 ',' umac-64@openssh.com '] client compress: [' zlib@openssh.com ',' zlib ',' none '] сжимать сервер: [' zlib@openssh.com ',' zlib ',' none '] client lang: [' '] server lang: [' '] kex следует? False DEB [20120913- 10: 05: 07.421] thr = 1 paramiko.transport: Ciphers согласились: local = aes128-ctr, remote = aes128-ctr DEB [20120913-10: 05: 07.421] thr = 1 paramiko.transport: используя kex diffie-hellman- группа1-SHA1; тип ключа сервера ssh-dss; шифр: локальный aes128-ctr, удаленный aes128-ctr; mac: локальный hmac-sha1, удаленный hmac-sha1; сжатие: локальный нет, удаленный нет DEB [20120913-10: 05: 07.625] thr = 1 paramiko.transport: перейти на новые ключи … INF [20120913-10: 05: 10.374] thr = 2 paramiko.transport.sftp: [chan 1] sftp session закрыт. DEB [20120913-10: 05: 10.388] thr = 2 paramiko.transport: [chan 1] EOF отправлено (1)

После этого момента сценарий завершает работу с этим исключением (из блока try / except sftp.get ())

Недостаточно ресурсов для завершения запроса

Сама система имеет гигабайты свободного места на диске, так что это не проблема.

Та же передача, что и паракмико не работает, отлично работает с FileZilla и с Java-приложением, которые я написал много лет назад для передачи SFTP. Поэтому я думаю, что это проблема с парамико.

Это выполняется в Windows XP и Windows Server 2003.

Я пробовал исправление Paramko 1.17, так что он чаще обновляет ключи, но передача все равно бросает исключение. Python 2.7.3 Paramiko 1.7 с исправлением Windows 2003 Sevfer

Идеи?

Дополнительная информация: он не работает на серверах Windows XP SP3 и Windows 2003, точно такие же поведение и сообщения об ошибках. sys.version информация Windows XP Workstation: «2.7.3 (по умолчанию, 10 апреля 2012, 23:31:26) [MSC v.1500 32 бит (Intel)]« Windows 2003 Server: «2.7.3 (по умолчанию, 10 апреля 2012, 23:31:26) [MSC v.1500 32 бит (Intel)] 'Я закрепил файл packet.py, чтобы сократить время между продлениями ключей. Это не повлияло на поведение sftp.get ().

4 Solutions collect form web for “Paramiko Не удается загрузить большие файлы> 1GB”

Протокол SFTP не имеет возможности передавать данные файла; вместо этого у него есть способ запросить блок данных с определенного смещения в открытом файле. Наивный способ загрузки файла состоял в том, чтобы запросить первый блок, записать его на диск, затем запросить второй блок и так далее. Это надежный, но очень медленный.

Вместо этого у Paramiko есть трюк производительности, который он использует: когда вы вызываете .get() он немедленно отправляет запрос для каждого блока в файле и запоминает, какое смещение должно быть записано. Затем, когда каждый ответ приходит, он гарантирует, что он будет записан в правильное смещение на диске. Для получения дополнительной информации см. SFTPFile.prefetch() и SFTPFile.readv() в документации Paramiko. Я подозреваю, что хранящаяся в нем информация о хранении, когда загрузка вашего 1GB-файла может вызвать … что-то закончится из-за нехватки ресурсов, генерируя сообщение «недостаточно ресурсов».

Вместо того, чтобы использовать .get() , если вы просто вызываете .open() чтобы получить экземпляр SFTPFile , тогда вызовите .read() на этом объекте или просто .read() его стандартной функции библиотеки Python shutil.copyfileobj() чтобы загрузить содержание. Это должно избегать кэша предварительной выборки Paramiko и позволяет загружать файл, даже если он не так быстр.

У меня была очень похожая проблема, в моем случае файл составляет всего ~ 400 МБ, но после загрузки примерно 35 МБ будет последовательно отказываться. Он не всегда терпел неудачу при том же количестве загруженных байт, но где-то около 35 – 40 МБ файл прекратил передачу, а через минуту я получил бы «Недостаточно ресурсов для завершения запроса».

Загрузка файла через WinSCP или PSFTP работала нормально.

Я пробовал метод Screwtape, и он работал, но был очень медленным. Мой 400-мегабайтный файл был в темпе, чтобы взять что-то вроде 4 часа для загрузки, что было неприемлемым временным периодом для этого конкретного приложения.

Кроме того, когда-то, когда мы впервые установили это, все сработало нормально. Но администратор сервера внесла некоторые изменения в SFTP-сервер, и это произошло. Я не уверен, какие изменения были внесены, но поскольку он все еще работал нормально с использованием WinSCP / других методов SFTP, я не думал, что это будет полезно, если вы попытаетесь атаковать это со стороны сервера.

Я не собираюсь притворяться, что понимаю, почему, но вот что в итоге работает для меня:

  1. Я загрузил и установил текущую версию Paramiko (1.11.1 в это время). Первоначально это не имело никакого значения, но я решил, что упомянул об этом на всякий случай, если это будет частью решения.

  2. Трассировка стека для исключения:

     File "C:\Python26\lib\site-packages\paramiko\sftp_client.py", line 676, in get size = self.getfo(remotepath, fl, callback) File "C:\Python26\lib\site-packages\paramiko\sftp_client.py", line 645, in getfo data = fr.read(32768) File "C:\Python26\lib\site-packages\paramiko\file.py", line 153, in read new_data = self._read(read_size) File "C:\Python26\lib\site-packages\paramiko\sftp_file.py", line 157, in _read data = self._read_prefetch(size) File "C:\Python26\lib\site-packages\paramiko\sftp_file.py", line 138, in _read_prefetch self._check_exception() File "C:\Python26\lib\site-packages\paramiko\sftp_file.py", line 483, in _check_exception raise x 
  3. Я немного заметил это в файле sftp_file.py (строки 43-45 в текущей версии):

     # Some sftp servers will choke if you send read/write requests larger than # this size. MAX_REQUEST_SIZE = 32768 
  4. По прихоти, я попытался изменить MAX_REQUEST_SIZE на 1024 и, вот и я, я смог загрузить весь файл!

  5. После того, как я получил его для работы, изменив MAX_REQUEST_SIZE на 1024, я попробовал кучу других значений между 1024 и 32768, чтобы увидеть, повлияло ли это на производительность или что-то еще. Но я всегда получал ошибку раньше или позже, когда значение было значительно больше, чем 1024 (1025 было в порядке, но в итоге 1048 не удалось).

В дополнение к ответу Screwtape также стоит упомянуть, что вы, вероятно, должны ограничить размер блока с помощью .read([block size in bytes])

См. Ленивый метод чтения большого файла

У меня были реальные проблемы с просто file.read() без размера размера блока в 2.4, возможно, 2.7 определяет правильный размер блока.

Я пытаюсь проследить код в paramiko, теперь я уверен, что это проблема сервера.

1. Что сделала предварительная выборка

Чтобы увеличить скорость загрузки, paramiko попытается выполнить предварительную выборку файла методом fetch. Когда SFTP_FILE.prefetch() метод SFTP_FILE.prefetch() , создается новый поток, и тон запроса на выборку отправляется на сервер, используя весь файл.
мы можем найти это в файле paramiko / sftp_file.py вокруг строки 464.

2. Как убедиться в проблеме сервера

Указанный выше запрос запускается в асинхронном режиме. SFTP_FILE._async_response() используется для получения ответа от сервера async.And отслеживает код, мы можем найти, что это исключение создано в методе SFTP_FILE._async_response() который конвертирует из сообщения, отправленного с сервера. Теперь мы уверены, что это исключение из сервера.

3. Как решить проблему

Поскольку у меня нет доступа к серверу, поэтому использовать sftp в командной строке – это мой лучший выбор. Но, с другой стороны, теперь мы знаем, что слишком много запросов заставляет сервер сбой, поэтому мы можем заснуть при отправке запроса на сервер ,

  • Ошибка Paramiko: ошибка при чтении протокола SSH
  • Выключение туннеля SSH в Парамико
  • Выполнение команды с использованием переключателя Paramiko on Brocade
  • Парамико: перенаправление портов вокруг NAT-маршрутизатора
  • Дождитесь завершения задачи на удаленном компьютере через Python
  • Подключение к удаленной базе данных Postgresql через туннель ssh с использованием python
  • Paramiko и exec_command - убивающий удаленный процесс?
  • Код Python для установки ssh на удаленный сервер, а затем подключитесь к MYSQL
  •  
    Interesting Posts for Van-Lav

    Почему нет ускорения при использовании многопроцессорной обработки питонов для неудобной параллельной проблемы внутри цикла for, с общими данными numpy?

    Уменьшить Dimensons при преобразовании списка в массив

    Django Rest Framework (DRF) Как установить класс разбиения на страницы в зависимости от query_params?

    Python IDE на консоли Linux

    Применение LIMIT и OFFSET ко всем запросам в SQLAlchemy

    Python реверсирует строку UTF-8

    Как отправить электронное письмо нескольким получателям, используя python smtplib?

    Список кортежей для преобразования DataFrame

    Перечисление зависимостей пакета с помощью pip

    pyyaml ​​и использование кавычек только для строк

    python Как удалить первую и последнюю двойные кавычки

    Установите аппаратные часы в Python?

    Python: необязательные аргументы argparse без тире

    Моделирование астероида с использованием Matplotlib с использованием поверхности и каркаса

    Передача аргументов при вызове функции через dict

    Python - лучший язык программирования в мире.