<?php
class RoundRobinLoadBalancer {
private $servers;
private $currentIndex;
private $healthyServers;
public function __construct($servers = []) {
$this->servers = $servers;
$this->currentIndex = 0;
$this->healthyServers = [];
$this->updateHealthyServers();
}
/**
* Adiciona um servidor à lista
*/
public function addServer($server) {
$this->servers[] = $server;
$this->updateHealthyServers();
}
/**
* Remove um servidor da lista
*/
public function removeServer($server) {
$key = array_search($server, $this->servers);
if ($key !== false) {
unset($this->servers[$key]);
$this->servers = array_values($this->servers); // Reindexar
$this->updateHealthyServers();
// Ajustar índice se necessário
if ($this->currentIndex >= count($this->healthyServers)) {
$this->currentIndex = 0;
}
}
}
/**
* Implementação do algoritmo Round Robin
* Retorna o próximo servidor disponível
*/
public function getNextServer() {
if (empty($this->healthyServers)) {
throw new Exception("Nenhum servidor disponível");
}
$server = $this->healthyServers[$this->currentIndex];
$this->currentIndex = ($this->currentIndex + 1) % count($this->healthyServers);
return $server;
}
/**
* Verifica a saúde dos servidores
*/
private function updateHealthyServers() {
$this->healthyServers = [];
foreach ($this->servers as $server) {
if ($this->isServerHealthy($server)) {
$this->healthyServers[] = $server;
}
}
// Reset do índice se não há servidores saudáveis
if (empty($this->healthyServers)) {
$this->currentIndex = 0;
} else if ($this->currentIndex >= count($this->healthyServers)) {
$this->currentIndex = 0;
}
}
/**
* Verifica se um servidor está saudável
* Implementação básica - pode ser expandida
*/
private function isServerHealthy($server) {
$parsed = parse_url($server);
$host = $parsed['host'] ?? $server;
$port = $parsed['port'] ?? 80;
// Timeout de 2 segundos
$connection = @fsockopen($host, $port, $errno, $errstr, 2);
if ($connection) {
fclose($connection);
return true;
}
return false;
}
/**
* Força atualização do health check
*/
public function refreshHealthCheck() {
$this->updateHealthyServers();
}
/**
* Retorna estatísticas dos servidores
*/
public function getStats() {
return [
'total_servers' => count($this->servers),
'healthy_servers' => count($this->healthyServers),
'current_index' => $this->currentIndex,
'servers' => $this->servers,
'healthy_servers_list' => $this->healthyServers
];
}
/**
* Distribui uma requisição para o próximo servidor
*/
public function handleRequest($path = '/', $method = 'GET', $data = null, $headers = []) {
$server = $this->getNextServer();
return $this->forwardRequest($server, $path, $method, $data, $headers);
}
/**
* Encaminha a requisição para o servidor especificado
*/
private function forwardRequest($server, $path, $method, $data, $headers) {
$url = rtrim($server, '/') . '/' . ltrim($path, '/');
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_HTTPHEADER => $headers,
]);
if ($data && in_array($method, ['POST', 'PUT', 'PATCH'])) {
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
}
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
if ($error) {
throw new Exception("Erro na requisição: $error");
}
return [
'server' => $server,
'http_code' => $httpCode,
'response' => $response
];
}
}
// Exemplo de uso
try {
// Configurar servidores
$loadBalancer = new RoundRobinLoadBalancer([
'http://servidor1.exemplo.com',
'http://servidor2.exemplo.com',
'http://servidor3.exemplo.com'
]);
// Simular várias requisições
echo "=== Teste do Load Balancer Round Robin ===\n\n";
for ($i = 1; $i <= 6; $i++) {
try {
$server = $loadBalancer->getNextServer();
echo "Requisição $i: $server\n";
} catch (Exception $e) {
echo "Erro na requisição $i: " . $e->getMessage() . "\n";
}
}
echo "\n=== Estatísticas ===\n";
print_r($loadBalancer->getStats());
// Exemplo de requisição HTTP real (descomente para testar com servidores reais)
/*
$response = $loadBalancer->handleRequest('/api/status', 'GET');
echo "\nResposta do servidor {$response['server']}:\n";
echo "HTTP Code: {$response['http_code']}\n";
echo "Response: {$response['response']}\n";
*/
} catch (Exception $e) {
echo "Erro: " . $e->getMessage() . "\n";
}
// Exemplo de uso com health check ativo
class AdvancedRoundRobinLoadBalancer extends RoundRobinLoadBalancer {
private $healthCheckInterval;
private $lastHealthCheck;
public function __construct($servers = [], $healthCheckInterval = 30) {
$this->healthCheckInterval = $healthCheckInterval;
$this->lastHealthCheck = 0;
parent::__construct($servers);
}
public function getNextServer() {
// Verificar se precisa fazer health check
if (time() - $this->lastHealthCheck > $this->healthCheckInterval) {
$this->refreshHealthCheck();
$this->lastHealthCheck = time();
}
return parent::getNextServer();
}
}
// Exemplo com health check automático
echo "\n\n=== Load Balancer com Health Check Automático ===\n";
$advancedLB = new AdvancedRoundRobinLoadBalancer([
'http://localhost:8001',
'http://localhost:8002',
'http://localhost:8003'
], 10); // Health check a cada 10 segundos
for ($i = 1; $i <= 3; $i++) {
try {
$server = $advancedLB->getNextServer();
echo "Requisição $i: $server\n";
} catch (Exception $e) {
echo "Erro na requisição $i: " . $e->getMessage() . "\n";
}
}
?>