Serverless функции на PHP: AWS Lambda продвинутый уровень

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Serverless функции на PHP: AWS Lambda — от теории к продвинутой практике

Serverless-архитектура давно перестала быть экзотикой, а PHP, благодаря таким инструментам, как Bref и Laravel Vapor, уверенно занял свою нишу в мире бессерверных вычислений. В этой статье мы разберем продвинутые техники работы с AWS Lambda на PHP: как победить холодный старт, настроить работу внутри VPC и эффективно обрабатывать события от S3 и SQS. Материал рассчитан на разработчиков, уже знакомых с основами деплоя PHP-приложений на Lambda.

1. Оптимизация холодного старта: от 2 секунд к 200 миллисекундам

Главный враг serverless приложений на PHP — холодный старт. В отличие от Node.js или Python, PHP требует загрузки интерпретатора и фреймворка. Вот как минимизировать задержки.

1.1. Использование Bref и предварительно скомпилированных слоев

Bref — это де-факто стандарт для запуска PHP на Lambda. Он предоставляет готовые слои (Layers) с PHP-интерпретатором. Для ускорения используйте bref/extra-php-extensions и подключайте только необходимые расширения.

Пример базовой конфигурации serverless.yml:

service: my-php-app

provider:
  name: aws
  runtime: provided.al2
  region: eu-central-1

plugins:
  - ./vendor/bref/bref

functions:
  api:
    handler: public/index.php
    layers:
      - ${bref:layer.php-81}
    events:
      - httpApi: '*'

1.2. Ленивая загрузка и кэширование конфигураций

Не загружайте весь фреймворк (Laravel, Symfony) при каждом запросе. Используйте Laravel Octane с Swoole или RoadRunner, но для Lambda лучше подойдет Bref Laravel Bridge, который кэширует конфиги и маршруты.

Код для кэширования конфигурации в bootstrap.php:

// public/index.php (точка входа для Lambda)
require_once __DIR__ . '/../vendor/autoload.php';

$app = require_once __DIR__ . '/../bootstrap/app.php';

// Кэшируем конфигурацию при первом запуске
if (! file_exists(__DIR__ . '/../bootstrap/cache/config.php')) {
    $app->make('config')->get('app');
    // Сохраняем скомпилированный конфиг
    file_put_contents(
        __DIR__ . '/../bootstrap/cache/config.php',
        '<?php return ' . var_export($app->make('config')->all(), true) . ';'
    );
} else {
    $config = require __DIR__ . '/../bootstrap/cache/config.php';
    $app->instance('config', $config);
}

$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
$response = $kernel->handle(
    $request = Illuminate\Http\Request::capture()
);
$response->send();
$kernel->terminate($request, $response);

Совет: Установите memorySize в 1024 MB и timeout в 30 секунд для баланса скорости и стоимости. Больше памяти — быстрее процессор.

2. Работа с VPC: подключение к RDS и ElastiCache

Lambda-функции по умолчанию работают вне вашей VPC. Для доступа к базам данных (RDS, Aurora) или кэшу (ElastiCache) необходимо разместить функцию внутри VPC. Это добавляет сложность и увеличивает холодный старт на 5-10 секунд.

2.1. Настройка VPC в serverless.yml

functions:
  processUser:
    handler: src/handlers/userHandler.php
    layers:
      - ${bref:layer.php-81}
    vpc:
      securityGroupIds:
        - sg-0123456789abcdef0
      subnetIds:
        - subnet-abc123
        - subnet-def456
    events:
      - sqs:
          arn: arn:aws:sqs:eu-central-1:123456789012:user-queue

2.2. Управление подключениями через PDO

Используйте пул соединений RDS Proxy или ElastiCache для многократного использования соединений внутри одного контейнера Lambda.

Пример класса для работы с БД с повторным использованием соединения:

class DatabaseConnection
{
    private static ?\PDO $instance = null;

    public static function getConnection(): \PDO
    {
        if (self::$instance === null) {
            $host = getenv('DB_HOST');
            $dbname = getenv('DB_NAME');
            $username = getenv('DB_USER');
            $password = getenv('DB_PASS');

            self::$instance = new \PDO(
                "mysql:host={$host};dbname={$dbname};charset=utf8mb4",
                $username,
                $password,
                [
                    \PDO::ATTR_ERRMODE            => \PDO::ERRMODE_EXCEPTION,
                    \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
                    \PDO::ATTR_EMULATE_PREPARES   => false,
                ]
            );
        }
        return self::$instance;
    }
}

Важно: В VPC Lambda не имеет доступа к интернету по умолчанию. Если нужен внешний API — настройте NAT Gateway или используйте VPC Endpoints для S3 и DynamoDB.

3. Обработка событий S3 и SQS: асинхронные пайплайны

Serverless-функции идеальны для событийно-ориентированных архитектур. Рассмотрим два частых сценария.

3.1. Триггер на загрузку файла в S3

Допустим, нужно создавать превью изображений при загрузке в бакет.

Код обработчика:

// src/handlers/imageResizer.php
require_once __DIR__ . '/../../vendor/autoload.php';

use Aws\S3\S3Client;
use Aws\Lambda\LambdaClient;

function handler(array $event): void
{
    $s3 = new S3Client([
        'region' => getenv('AWS_REGION'),
        'version' => 'latest',
    ]);

    foreach ($event['Records'] as $record) {
        $bucket = $record['s3']['bucket']['name'];
        $key = rawurldecode($record['s3']['object']['key']);

        // Получаем оригинал                

Блоги

Рекомендаций по книгам