Есть две проблемы, которые нам нужно решить
- Правильное управление состоянием между лямбда-вызовами
- Настройка пула соединений
Правильно управляющее состояние
Давайте немного разберемся, как контейнер управляется AWS. Из документов AWS :
После выполнения лямбда-функции AWS Lambda поддерживает
контекст выполнения в течение некоторого времени в ожидании другой лямбды
вызов функции. По сути, сервис останавливает выполнение
контекст после завершения лямбда-функции и оттаивания контекста для
повторное использование, если AWS Lambda выбирает повторное использование контекста, когда Lambda
функция вызывается снова.
Этот подход повторного использования контекста выполнения имеет следующие последствия:
Любые объявления в вашем коде функции Lambda (вне обработчика
код, см. Модель программирования) остается инициализированным, обеспечивая дополнительные
оптимизация, когда функция вызывается снова. Например, если ваш
Лямбда-функция устанавливает соединение с базой данных, а не
восстановление соединения, исходное соединение используется в
последующие вызовы. Мы рекомендуем добавить логику в ваш код для проверки
если соединение существует до его создания.
Каждый контекст выполнения предоставляет 500 МБ дополнительного дискового пространства в
Каталог / tmp. Содержимое каталога остается при выполнении
контекст заморожен, предоставляя временный кеш, который можно использовать для
несколько вызовов. Вы можете добавить дополнительный код, чтобы проверить, имеет ли кеш
данные, которые вы сохранили. Для получения информации об ограничениях развертывания см.
AWS Lambda Limits.
Фоновые процессы или обратные вызовы, инициированные вашей функцией Lambda
который не завершился, когда функция закончила возобновление, если AWS Lambda
выбирает повторно использовать контекст выполнения. Вы должны убедиться, что любой
фоновые процессы или обратные вызовы (в случае Node.js) в вашем коде
завершены до выхода кода.
Этот первый пункт маркировки говорит о том, что состояние сохраняется между выполнениями. Давайте посмотрим на это в действии:
let counter = 0
module.exports.handler = (event, context, callback) => {
counter++
callback(null, { count: counter })
}
Если вы развернете это и вызовете несколько раз последовательно , вы увидите, что счетчик будет увеличиваться между вызовами.
Теперь, когда вы знаете, что вы не должны вызывать defer db.Close()
, вместо этого вы должны повторно использовать экземпляр базы данных. Вы можете сделать это, просто сделав db
переменной уровня пакета.
Сначала создайте пакет базы данных, который будет экспортировать функцию Open
:
package database
import (
"fmt"
"os"
_ "github.com/go-sql-driver/mysql"
"github.com/jinzhu/gorm"
)
var (
host = os.Getenv("DB_HOST")
port = os.Getenv("DB_PORT")
user = os.Getenv("DB_USER")
name = os.Getenv("DB_NAME")
pass = os.Getenv("DB_PASS")
)
func Open() (db *gorm.DB) {
args := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?parseTime=true", user, pass, host, port, name)
// Initialize a new db connection.
db, err := gorm.Open("mysql", args)
if err != nil {
panic(err)
}
return
}
Затем используйте его в файле handler.go:
package main
import (
"context"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
"github.com/jinzhu/gorm"
"github.com/<username>/<name-of-lib>/database"
)
var db *gorm.DB
func init() {
db = database.Open()
}
func Handler() (events.APIGatewayProxyResponse, error) {
// You can use db here.
return events.APIGatewayProxyResponse{
StatusCode: 201,
}, nil
}
func main() {
lambda.Start(Handler)
}
OBS : не забудьте заменить github.com/<username>/<name-of-lib>/database
на правильный путь.
Теперь вы все равно можете увидеть ошибку too many connections
. Если это произойдет, вам понадобится пул соединений.
Настройка пула соединений
Из Википедия :
В программной инженерии пул соединений - это кеш базы данных.
Соединения поддерживаются, так что соединения могут быть использованы повторно, когда
Будущие запросы к базе данных не требуется. Пулы соединений
используется для повышения производительности выполнения команд в базе данных.
Вам потребуется пул соединений, в котором количество разрешенных соединений должно быть равно количеству запущенных параллельных лямбд, у вас есть два варианта:
MySQL Proxy - это простая программа, которая находится между вашим клиентом и
MySQL сервер (ы) и которые могут контролировать, анализировать или преобразовывать их
коммуникации. Его гибкость допускает широкий спектр применения,
включая балансировку нагрузки, отработку отказа, анализ запросов, фильтрацию запросов
и модификации, и многое другое.
Amazon Aurora Serverless - конфигурация с автоматическим масштабированием по требованию
для Amazon Aurora (MySQL-совместимое издание), где база данных будетавтоматический запуск, выключение и масштабирование емкости в зависимости от увеличения или уменьшения
на потребности вашего приложения. Это позволяет вам запустить вашу базу данных в
облако без управления экземплярами базы данных. Это просто,
экономически эффективный вариант для редких, периодических или непредсказуемых
рабочие нагрузки.
Независимо от вашего выбора, в интернете есть множество руководств по настройке обоих.