#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 МБ, большинство из них значительно ниже.