проблема SFTP SSH2_DISCONNECT_PROTOCOL_ERROR в интеграции spring при использовании spring batch

Вопрос или проблема

Мое весеннее приложение для пакетной обработки пытается загрузить файл с мейнфрейма через SFTP (JDK 17). После завершения загрузки процесс продолжается с чтением, обработкой и записью. Это происходит дважды, так как есть две категории (А и Б). Категория А завершена. Когда категория ‘Б’ близка к завершению в процессе записи, в журналах отображаются следующие строки, после чего выполнение задания занимает около 10 минут.

Как правило, выполнение задания занимает около 10-15 минут, но как только эти строки появляются в журнале, выполнение задания занимает дополнительные 20 минут, занимая до 2 Гб (сначала занимает 1 Гб).

2024-10-22T746.949Z  INFO [,,] 1 --- [-timer-thread-1] o.a.s.client.session.ClientSessionImpl   : Отключение(ClientSessionImpl[[email protected]/19.59.28.35:222]): SSH2_DISCONNECT_PROTOCOL_ERROR - Обнаружен IdleTimeout после 600000/600000 мс.
2024-10-22T13:52:59.343Z  INFO [,,] 1 --- [-timer-thread-1] o.a.s.client.session.ClientSessionImpl   : Отключение(ClientSessionImpl[[email protected]/19.59.28.35:222]): SSH2_DISCONNECT_PROTOCOL_ERROR - Обнаружен IdleTimeout после 600001/600000 мс.
2024-10-22T13:52:59.944Z  INFO [,,] 1 --- [-timer-thread-1] o.a.s.client.session.ClientSessionImpl   : Отключение(ClientSessionImpl[[email protected]/19.59.28.35:222]): SSH2_DISCONNECT_PROTOCOL_ERROR - Обнаружен IdleTimeout после 600493/600000 мс.
2024-10-22T13:53:00.344Z  INFO [,,] 1 --- [-timer-thread-1] o.a.s.client.session.ClientSessionImpl   : Отключение(ClientSessionImpl[[email protected]/19.59.28.35:222]): SSH2_DISCONNECT_PROTOCOL_ERROR - Обнаружен IdleTimeout после 600575/600000 мс.
2024-10-22T13:53:04.143Z  INFO [,,] 1 --- [-timer-thread-1] o.a.s.client.session.ClientSessionImpl   : Отключение(ClientSessionImpl[[email protected]/19.59.28.35:222]): SSH2_DISCONNECT_PROTOCOL_ERROR - Обнаружен IdleTimeout после 600262/600000 мс.
2024-10-22T13:53:06.940Z  INFO [,,] 1 --- [-timer-thread-1] o.a.s.client.session.ClientSessionImpl   : Отключение(ClientSessionImpl[[email protected]/19.59.28.35:222]): SSH2_DISCONNECT_PROTOCOL_ERROR - Обнаружен IdleTimeout после 600190/600000 мс.
2024-10-22T13:53:55.243Z  INFO [,,] 1 --- [-timer-thread-1] o.a.s.client.session.ClientSessionImpl   : Отключение(ClientSessionImpl[[email protected]/19.59.28.35:222]): SSH2_DISCONNECT_PROTOCOL_ERROR - Обнаружен IdleTimeout после 600219/600000 мс.
2024-10-22T14:16:17.809Z  WARN [,,] 1 --- [lTaskExecutor-2] c.f.p.m.f.l.StepExecutionListenerFactory : Я вызываю после шага в createOrderPartStepExecutionListener
2024-10-22T14:16:17.809Z  WARN [,,] 1 --- [lTaskExecutor-2] c.f.p.m.f.l.StepExecutionListenerFactory : Я вызываю метод закрытия для обработчика заказов
2024

Поскольку это указывает на тайм-аут бездействия, я попытался установить тайм-аут в DefaultSftpSessionFactory и попытался закрыть, реализовав Closeable и используя factory.getSession().close(). Ранее мы не получали эти строки. Это может быть связано с обновлением spring integration sftp вместе с jdk 17.

FtpClient.java

@Component
@Scope("prototype")
public class FtpClient{

    @Autowired
    public RestClientBuilder restClientBuilder;

    @Value("${application.sftp.cmms.privatekey:}")
    @Setter
    public String sftpCmmsPrivateKey;

    public SftpRemoteTemplate sftpRemoteTemplate;

    private DefaultSftpSessionFactory factory;

    public RemoteFileTemplate createFtpRemoteFileTemplate(String plantCode) {
        FtpDataDTO ftpData = restClientBuilder.createClient().getFtpData(plantCode);
        if (isSecureFTP()) {
            factory = = new DefaultSftpSessionFactory();
            factory.setPrivateKey(new ByteArrayResource(sftpCmmsPrivateKey.getBytes(StandardCharsets.US_ASCII)));
            factory.setUser(ftpData.getUserId().trim());
            factory.setHost(ftpData.getHostname().trim());
            factory.setPort(222);
            factory.setAllowUnknownKeys(true);
            factory.setTimeout(300000);
            sftpRemoteTemplate = new SftpRemoteTemplate(factory);
            return sftpRemoteTemplate;
        } else {
            DefaultFtpSessionFactory factory = defaultFtpSessionFactory();
            factory.setPassword(MovisEncryption.decrypt(ftpData.getPassword().trim()));
            factory.setUsername(ftpData.getUserId().trim());
            factory.setHost(ftpData.getHostname().trim());
            factory.setPort(21);
            return new FtpRemoteTemplate(factory);
        }
    }

    private boolean isSecureFTP() {
        return !sftpCmmsPrivateKey.isBlank();
    }

Ответ или решение

Решение проблемы SSH2_DISCONNECT_PROTOCOL_ERROR в Spring Batch при использовании SFTP

Проблема

Ваша система на основе Spring Batch сталкивается с ненормальным поведением при загрузке файлов с основного компьютера через SFTP в JDK 17. После успешного завершения задач для категории A, при близком завершении обработки категории B, в логах фиксируется несколько строк, указывающих на SSH2_DISCONNECT_PROTOCOL_ERROR, связанное с IdleTimeout. Это приводит к увеличению времени выполнения задач до 20 минут и значительному увеличению потребления памяти (с 1 Гб до 2 Гб).

Причины возникновения проблемы

Ошибка SSH2_DISCONNECT_PROTOCOL_ERROR возникает, когда SSH-соединение автоматически разрывается из-за бездействия, превышающего установленный таймаут (в вашем случае – 600 секунд). Это может быть вызвано несколькими факторами:

  1. Недостаточная активность между запросами. Если не происходит обмена данными или поддерживающих сигналов (keep-alive) в течение указанного времени, соединение может быть закрыто сервером.

  2. Изменения в конфигурации Spring Integration или версии JDK. Обновления могут изменить поведение по умолчанию, что может привести к несоответствиям в работе вашего приложения.

  3. Неправильная конфигурация таймаутов. Увеличение таймаута может не помочь, если в приложении не реализована логика для поддержания активности соединения.

Возможные решения

Чтобы устранить эту проблему, рассмотрите следующие подходы:

  1. Настройка таймаутов. Убедитесь, что вы правильно установили таймауты для вашей сессии SFTP в DefaultSftpSessionFactory. Вы можете установить таймауты и значения keep-alive:
factory.setTimeout(300000); // Ожидание ответа от сервера (50000 мс)
factory.setSessionTimeout(600000); // Тайм-аут соединения
factory.setIdletimeout(300000); // Тайм-аут при неактивности
  1. Реализация механизма keep-alive. Реализуйте механизм регулярной отправки пустых запросов (или специальных команд) для поддержания соединения активным:
@Override
public void afterPropertiesSet() throws Exception {
    keepAliveExecutor = Executors.newScheduledThreadPool(1);
    keepAliveExecutor.scheduleAtFixedRate(() -> {
        try {
            if (sftpRemoteTemplate != null) {
                sftpRemoteTemplate.execute(session -> {
                    session.getSession().sendKeepAlive(); // специальная команда для поддержания активности
                    return null;
                });
            }
        } catch (Exception e) {
            // Логирование ошибок
        }
    }, 0, 300, TimeUnit.SECONDS); // Отправка каждые 5 минут
}
  1. Закрытие сессии. Убедитесь, что вы правильно закрываете сессию после завершения работы, например, через интерфейс Closeable:
try (SftpRemoteTemplate template = new SftpRemoteTemplate(factory)) {
    // Ваш код загрузки/обработки
} catch (Exception e) {
    // Обработка исключений
}

Заключение

Исправление ошибки SSH2_DISCONNECT_PROTOCOL_ERROR требует комплексного подхода к управлению подключениями SFTP, настройкам таймаутов и поддержанию активности соединений. Проверьте настройки вашего Spring Batch приложения, настройте таймауты, добавьте механизмы keep-alive и убедитесь в корректном закрытии сессий. Практическое применение этих рекомендаций должно помочь эффективно решить проблему, а также оптимизировать производительность вашей системы.

Современные IT-решения требуют пристального внимания к деталям, чтобы избежать сбоев и улучшить общий опыт использования.

Оцените материал
Добавить комментарий

Капча загружается...