Всплески памяти Ruby (выделения) при обработке строк base64

#ruby-on-rails #ruby #heroku

#ruby-on-rails #ruby #heroku

Вопрос:

У меня есть экземпляр rails, который в среднем использует около 250 МБ памяти. В последнее время у меня возникают проблемы с некоторыми действительно сильными всплесками использования памяти, что приводит к времени отклика около ~ 25 секунд. У меня есть конечная точка, которая принимает некоторые относительно простые параметры и строки base64, которые отправляются в AWS.

Смотрите Изображение ниже для корреляции между памятью / временем отклика.введите описание изображения здесь

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

Прежде всего, я нахожу, что распределение памяти net_http чрезвычайно велико. Во-вторых, операция обновления заняла в общей сложности около 25 секунд. Когда я внимательно смотрю на временную шкалу, я заметил некоторые «пустые пробелы», между ~ 5 и ~ 15 секундами. Конкретные операции, которые выполняются во время этих HTTP-вызовов, с моей точки зрения, не являются чем-то особенным. Но я немного смущен, почему возникают эти пробелы, может быть, кто-нибудь мог бы рассказать мне немного об этом?

введите описание изображения здесь

Код, обрабатывающий запросы:

 def store_documents
        identity_documents.each do |side, content|
          is_file = content.is_a?(ActionDispatch::Http::UploadedFile)

          file_extension = is_file ? content : content[:name]
          file_name = "#{SecureRandom.uuid}_#{side}#{File.extname(file_extension)}"

          if is_file
            write_to_storage_service(file_name, content.tempfile.path)
          else
            write_file(file_name, content[:uri])
            write_to_storage_service(file_name, file_name)
            delete_file(file_name)
          end

          store_object_key_on_profile(side, file_name)
        end
      end
      # rubocop:enable Metrics/MethodLength

      def write_file(file_name, base_64_string)
        File.open(file_name, 'wb') do |f|
          f.write(
            Base64.decode64(
              get_content(base_64_string)
            )
          )
        end
      end

      def delete_file(file_name)
        File.delete(file_name)
      end

      def write_to_storage_service(file_name, path)
        S3_IDENTITY_BUCKET
          .object(file_name)
          .upload_file(path)
      rescue Aws::Xml::Parser::ParsingError => e
        log_error(e)
        add_errors(base: e)
      end

      def get_content(base_64_string)
        base_64_string.sub %r{data:((image|application)/.{3,}),}, ''
      end

      def store_object_key_on_profile(side, file_name)
        profile.update("#{side}_identity_document_object_key": file_name)
      end

      def identity_documents
        {
          front: front_identity_document,
          back:  back_identity_document
        }
      end

      def front_identity_document
        @front_identity_document ||= identity_check_params[:front_identity_document]
      end

      def back_identity_document
        @back_identity_document ||= identity_check_params[:back_identity_document]
      end
  

Я склоняюсь к некоторым проблемам с Ruby GC, или, возможно, в Ruby недостаточно страниц для непосредственного хранения строки base64 в памяти? Я знаю, что в Ruby 2.6 и Ruby 2.7 были некоторые значительные улучшения в отношении фрагментации памяти, но это тоже не сильно изменилось (в настоящее время работает Ruby 2.7.1)

У меня есть ресурсы Heroku, настроенные на использование стандартных 2x динамиков (1 ГБ оперативной памяти) x3. WEB_CONCURRENCY (рабочие) установлено значение 2, а количество потоков — 5.

Я понимаю, что мои вопросы довольно широкие, меня больше интересуют некоторые инструменты или идеи, которые могли бы помочь сузить мою область. Спасибо!

Комментарии:

1. Есть ли что-нибудь, что ограничивает размер загружаемых изображений? Это просто иногда застревает при обработке синхронной записи файлов, когда слишком много людей одновременно загружают слишком много изображений в высоком разрешении? Поскольку данные в кодировке Base64 на ~ 30% больше исходного файла…

2. @nullTerminator Я знаю об увеличении на 30%. Изображения в среднем составляют несколько МБ, самый высокий — 8 МБ, большинство из них значительно ниже.