Catch up on highlights from Firebase at Google I/O 2023. Learn more

Советы и хитрости

В этом документе описаны передовые методы проектирования, реализации, тестирования и развертывания облачных функций.

Правильность

В этом разделе описаны общие рекомендации по проектированию и внедрению облачных функций.

Напишите идемпотентные функции

Ваши функции должны давать один и тот же результат, даже если они вызываются несколько раз. Это позволяет вам повторить вызов, если предыдущий вызов завершился сбоем в коде. Дополнительные сведения см. в разделе Повторные попытки функций, управляемых событиями .

Не запускать фоновые действия

Фоновая активность — это все, что происходит после завершения вашей функции. Вызов функции завершается, когда функция возвращается или иным образом сигнализирует о завершении, например, путем вызова аргумента callback в функциях Node.js, управляемых событиями. Любой код, запущенный после корректного завершения, не может получить доступ к ЦП и не будет выполняться.

Кроме того, когда последующий вызов выполняется в той же среде, ваша фоновая деятельность возобновляется, мешая новому вызову. Это может привести к неожиданному поведению и ошибкам, которые трудно диагностировать. Доступ к сети после завершения функции обычно приводит к сбросу соединений (код ошибки ECONNRESET ).

Фоновую активность часто можно обнаружить в журналах отдельных вызовов, найдя все, что регистрируется после строки, сообщающей о завершении вызова. Иногда фоновая активность может быть скрыта глубже в коде, особенно при наличии асинхронных операций, таких как обратные вызовы или таймеры. Просмотрите свой код, чтобы убедиться, что все асинхронные операции завершены до завершения функции.

Всегда удалять временные файлы

Локальное дисковое хранилище во временном каталоге представляет собой файловую систему в памяти. Файлы, которые вы пишете, потребляют память, доступную для вашей функции, и иногда сохраняются между вызовами. Отсутствие явного удаления этих файлов может в конечном итоге привести к ошибке нехватки памяти и последующему холодному запуску.

Вы можете увидеть объем памяти, используемый отдельной функцией, выбрав ее в списке функций в консоли GCP и выбрав график использования памяти .

Не пытайтесь писать за пределами временного каталога и обязательно используйте независимые от платформы/ОС методы для создания путей к файлам.

Вы можете уменьшить требования к памяти при обработке больших файлов с помощью конвейерной обработки. Например, вы можете обработать файл в облачном хранилище, создав поток чтения, пропустив его через процесс на основе потока и записав выходной поток непосредственно в облачное хранилище.

Инструменты

В этом разделе приведены рекомендации по использованию инструментов для реализации, тестирования и взаимодействия с облачными функциями.

Местное развитие

Развертывание функции занимает немного времени, поэтому часто бывает быстрее протестировать код вашей функции локально.

Разработчики Firebase могут использовать эмулятор облачных функций Firebase CLI .

Используйте Sendgrid для отправки электронных писем

Cloud Functions не разрешает исходящие подключения через порт 25, поэтому вы не можете выполнять незащищенные подключения к SMTP-серверу. Рекомендуемый способ отправки электронной почты — использовать SendGrid . Вы можете найти другие варианты отправки электронной почты в руководстве по отправке электронной почты из экземпляра для Google Compute Engine.

Производительность

В этом разделе описываются передовые методы оптимизации производительности.

Используйте зависимости с умом

Поскольку функции не имеют состояния, среда выполнения часто инициализируется с нуля (во время так называемого холодного запуска ). Когда происходит холодный запуск, оценивается глобальный контекст функции.

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

Используйте глобальные переменные для повторного использования объектов в будущих вызовах.

Нет гарантии, что состояние облачной функции будет сохранено для будущих вызовов. Однако облачные функции часто повторно используют среду выполнения предыдущего вызова. Если вы объявляете переменную в глобальной области видимости, ее значение можно повторно использовать в последующих вызовах без необходимости повторного вычисления.

Таким образом, вы можете кэшировать объекты, воссоздание которых может быть дорогостоящим при каждом вызове функции. Перемещение таких объектов из тела функции в глобальную область может привести к значительному повышению производительности. В следующем примере тяжелый объект создается только один раз для каждого экземпляра функции и используется для всех вызовов функций, достигающих данного экземпляра:

console.log('Global scope');
const perInstance = heavyComputation();
const functions = require('firebase-functions');

exports.function = functions.https.onRequest((req, res) => {
    console.log('Function invocation');
    const perFunction = lightweightComputation();

    res.send(`Per instance: ${perInstance}, per function: ${perFunction}`);
});

Особенно важно кэшировать сетевые подключения, ссылки на библиотеки и клиентские объекты API в глобальном масштабе. Примеры см. в разделе Оптимизация сети .

Делать ленивую инициализацию глобальных переменных

Если вы инициализируете переменные в глобальной области видимости, код инициализации всегда будет выполняться через вызов холодного запуска, увеличивая задержку вашей функции. В некоторых случаях это приводит к прерывистым тайм-аутам вызываемых служб, если они не обрабатываются должным образом в блоке try / catch . Если некоторые объекты не используются во всех путях кода, рассмотрите возможность их ленивой инициализации по требованию:

const functions = require('firebase-functions');
let myCostlyVariable;

exports.function = functions.https.onRequest((req, res) => {
    doUsualWork();
    if(unlikelyCondition()){
        myCostlyVariable = myCostlyVariable || buildCostlyVariable();
    }
    res.status(200).send('OK');
});

Это особенно важно, если вы определяете несколько функций в одном файле, и разные функции используют разные переменные. Если вы не используете ленивую инициализацию, вы можете тратить ресурсы на переменные, которые инициализируются, но никогда не используются.

Уменьшите количество холодных запусков, установив минимальное количество экземпляров

По умолчанию Cloud Functions масштабирует количество экземпляров в зависимости от количества входящих запросов. Вы можете изменить это поведение по умолчанию, задав минимальное количество экземпляров, которые облачные функции должны держать в готовности для обслуживания запросов. Установка минимального количества экземпляров уменьшает количество холодных запусков вашего приложения. Мы рекомендуем установить минимальное количество экземпляров, если ваше приложение чувствительно к задержкам.

Дополнительные сведения об этих параметрах среды выполнения см. в разделе Управление поведением масштабирования .

Дополнительные ресурсы

Узнайте больше об оптимизации производительности в видеоролике «Атлас производительности Google Cloud» Время холодной загрузки облачных функций .