Serverless PHP: deploy no AWS Lambda ou Bref
1. Introdução ao Serverless PHP
A computação serverless representa uma mudança de paradigma no desenvolvimento backend. Em vez de gerenciar servidores, você escreve código que é executado sob demanda em infraestrutura gerenciada pela nuvem. Para o ecossistema PHP, isso abre possibilidades interessantes: escalabilidade automática, pagamento por execução (redução de custos em aplicações com tráfego variável) e eliminação da sobrecarga operacional de manter servidores web.
No entanto, o modelo serverless traz desafios específicos. O PHP tradicional foi projetado para ambientes com estado persistente (como Apache ou Nginx com PHP-FPM). Em ambientes serverless como AWS Lambda, cada execução é efêmera e stateless. Além disso, cold starts (inicialização a frio) podem impactar a latência, e há limites rígidos de tempo de execução (15 minutos no Lambda) e tamanho de pacote (250 MB).
2. Arquitetura Serverless para PHP
A arquitetura serverless para PHP segue o modelo FaaS (Function as a Service). O AWS Lambda executa funções PHP em resposta a eventos. Para aplicações web, o API Gateway atua como ponto de entrada HTTP, roteando requisições para funções Lambda específicas.
O ciclo de vida de uma requisição típica:
1. Cliente faz requisição HTTP ao API Gateway
2. API Gateway converte a requisição em um evento JSON
3. Lambda executa o runtime PHP com o handler definido
4. O handler processa o evento e retorna uma resposta
5. API Gateway converte a resposta de volta para HTTP
Esse modelo elimina a necessidade de um servidor web persistente, mas exige que o código PHP seja adaptado para funcionar em ambiente stateless.
3. Bref: O Framework Serverless para PHP
Bref é o framework serverless mais maduro para PHP no ecossistema AWS. Ele resolve a incompatibilidade fundamental entre PHP e Lambda fornecendo um runtime PHP otimizado e ferramentas de deploy.
Instalação e Configuração Inicial
composer require bref/bref
Após instalar, você precisa configurar o arquivo serverless.yml na raiz do projeto:
service: minha-api-php
provider:
name: aws
region: us-east-1
runtime: provided.al2
plugins:
- ./vendor/bref/bref
functions:
api:
handler: public/index.php
runtime: php-81
events:
- httpApi: '*'
package:
patterns:
- '!node_modules/**'
- '!tests/**'
Estrutura de um Projeto Bref
Um projeto Bref típico contém:
- serverless.yml: configuração de deploy
- public/index.php: ponto de entrada da aplicação
- vendor/: dependências gerenciadas pelo Composer
- Handlers específicos para cada função Lambda
4. Deploy no AWS Lambda com Bref
Configuração do serverless.yml
O arquivo serverless.yml define funções, eventos e recursos:
functions:
api:
handler: public/index.php
runtime: php-81
environment:
DB_HOST: ${env:DB_HOST}
DB_NAME: ${env:DB_NAME}
events:
- httpApi:
method: GET
path: /users
- httpApi:
method: POST
path: /users
- schedule:
rate: rate(5 minutes)
enabled: true
Deploy Manual
# Instalar dependências
composer install --no-dev --optimize-autoloader
# Deploy
serverless deploy --stage production --region us-east-1
# Variáveis de ambiente
serverless deploy --stage production --env DB_HOST=meu-host.rds.amazonaws.com
Gerenciamento de Dependências
O Bref empacota automaticamente o diretório vendor/ junto com o código. Para otimizar o tamanho do pacote:
composer install --no-dev --optimize-autoloader --classmap-authoritative
5. Criando Handlers e Rotas
Handler Básico
<?php
// public/index.php
require __DIR__ . '/../vendor/autoload.php';
use Bref\Context\Context;
use Bref\Event\Http\HttpRequestEvent;
use Bref\Event\Http\HttpResponse;
return function (HttpRequestEvent $event, Context $context): HttpResponse {
$method = $event->getMethod();
$path = $event->getPath();
if ($method === 'GET' && $path === '/health') {
return new HttpResponse('OK', ['Content-Type' => 'text/plain'], 200);
}
return new HttpResponse('Not Found', [], 404);
};
Integração com Laravel
composer require bref/laravel-bridge
<?php
// public/index.php
use Bref\LaravelBridge\BrefServiceProvider;
$app = require __DIR__ . '/../bootstrap/app.php';
$app->register(BrefServiceProvider::class);
return $app;
Rotas Personalizadas com JSON
<?php
// src/Handlers/UserHandler.php
namespace App\Handlers;
use Bref\Context\Context;
use Bref\Event\Http\HttpRequestEvent;
use Bref\Event\Http\HttpResponse;
class UserHandler
{
public function handle(HttpRequestEvent $event, Context $context): HttpResponse
{
$users = [
['id' => 1, 'name' => 'Alice'],
['id' => 2, 'name' => 'Bob']
];
return new HttpResponse(
json_encode($users),
['Content-Type' => 'application/json'],
200
);
}
}
6. Banco de Dados e Estado
Conexão com RDS MySQL
<?php
// src/Database/Connection.php
namespace App\Database;
class Connection
{
private static ?\PDO $instance = null;
public static function get(): \PDO
{
if (self::$instance === null) {
self::$instance = new \PDO(
sprintf(
'mysql:host=%s;dbname=%s',
getenv('DB_HOST'),
getenv('DB_NAME')
),
getenv('DB_USER'),
getenv('DB_PASSWORD'),
[\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION]
);
}
return self::$instance;
}
}
DynamoDB para Escalabilidade
<?php
use Aws\DynamoDb\DynamoDbClient;
$dynamoDb = new DynamoDbClient([
'region' => getenv('AWS_REGION'),
'version' => 'latest'
]);
$result = $dynamoDb->putItem([
'TableName' => 'Users',
'Item' => [
'id' => ['S' => uniqid()],
'name' => ['S' => 'Alice'],
'created_at' => ['N' => (string) time()]
]
]);
7. Monitoramento, Logs e Otimização
Logs Estruturados com Monolog
<?php
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
$logger = new Logger('app');
$logger->pushHandler(new StreamHandler('php://stderr', Logger::INFO));
$logger->info('Requisição processada', [
'path' => $event->getPath(),
'method' => $event->getMethod(),
'duration_ms' => round((microtime(true) - $start) * 1000)
]);
Métricas no CloudWatch
O Bref envia automaticamente métricas para CloudWatch:
- Duration: tempo de execução em milissegundos
- Invocations: número de invocações
- Errors: erros não tratados
- ColdStart: indica se foi uma inicialização a frio
Otimização de Cold Starts
functions:
api:
handler: public/index.php
runtime: php-81
provisionedConcurrency: 2 # Mantém 2 instâncias sempre quentes
layers:
- ${bref:layer.php-81} # Usa layer otimizado do Bref
8. Casos de Uso e Boas Práticas
Aplicações Típicas
- APIs REST: endpoints leves com alto tráfego variável
- Webhooks: processamento de eventos de serviços externos
- Processamento de Filas: integração com SQS para jobs assíncronos
- Backends para SPAs: servindo dados para aplicações React/Vue
Segurança
provider:
iam:
role:
statements:
- Effect: Allow
Action:
- dynamodb:GetItem
- dynamodb:PutItem
Resource: arn:aws:dynamodb:us-east-1:*:table/Users
- Effect: Allow
Action:
- s3:GetObject
Resource: arn:aws:s3:::meu-bucket/*
Limitações a Considerar
- Tempo máximo de execução: 15 minutos (configurável até 900 segundos)
- Tamanho do pacote: 250 MB (incluindo layers)
- Memória máxima: 10 GB
- Cold starts: podem levar de 1 a 5 segundos em PHP
Referências
- Documentação Oficial do Bref — Guia completo de instalação, configuração e deploy de aplicações PHP serverless com Bref
- AWS Lambda PHP Runtime — Documentação oficial da AWS sobre o runtime PHP para Lambda
- Laravel Bridge para Bref — Tutorial oficial de integração do Laravel com ambientes serverless usando Bref
- Serverless PHP: Guia Prático — Artigo técnico da Serverless Inc. sobre boas práticas para PHP serverless
- Otimizando Cold Starts em PHP Lambda — Post do blog oficial da AWS sobre técnicas de otimização para reduzir cold starts em funções PHP
- Monolog para Lambda — Biblioteca de logging que funciona perfeitamente com CloudWatch em ambientes serverless
- AWS SDK para PHP — Documentação oficial do SDK PHP para integração com serviços AWS como DynamoDB, S3 e SQS