PHP微服务架构终极整合方案:
graph TD
A[客户端] --> B{Kong网关}
B -->|路由| C[用户服务]
B -->|路由| D[订单服务]
B -->|路由| E[支付服务]
C -->|注册| F[Consul集群]
D -->|注册| F
E -->|注册| F
C -->|配置| G[Apollo]
D -->|配置| G
E -->|配置| G
D -->|消息| H[RabbitMQ集群]
H --> E
H --> I[通知服务]
F --> J[Prometheus]
G --> J
H --> J
J --> K[Grafana]
L[Jaeger] --> M[服务追踪]
基础设施快速部署
Docker Compose 全栈配置1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44version: '3.8'
services:
# 注册中心
consul-server:
image: consul:1.15
ports: ["8500:8500"]
command: "agent -server -bootstrap-expect=1 -ui -client 0.0.0.0"
# API网关
kong:
image: kong:3.4
depends_on: [consul-server]
environment:
KONG_DATABASE: "off"
KONG_DECLARATIVE_CONFIG: "/etc/kong/kong.yml"
KONG_PROXY_ACCESS_LOG: "/dev/stdout"
KONG_ADMIN_ACCESS_LOG: "/dev/stdout"
KONG_PROXY_ERROR_LOG: "/dev/stderr"
ports: ["8000:8000", "8001:8001"]
volumes:
- ./kong:/etc/kong
# 配置中心
apollo:
image: apolloconfig/apollo-portal:2.1.0
ports: ["8070:8070"]
environment:
SPRING_DATASOURCE_URL: "jdbc:mysql://apollo-db:3306/ApolloPortalDB"
# 消息队列
rabbitmq:
image: rabbitmq:3.11-management
ports: ["5672:5672", "15672:15672"]
environment:
RABBITMQ_DEFAULT_USER: "admin"
RABBITMQ_DEFAULT_PASS: "secret"
# 监控系统
prometheus:
image: prom/prometheus:v2.47
ports: ["9090:9090"]
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml核心服务PHP实现包
composer.json 关键依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14{
"require": {
"php": ">=8.2",
"ext-swoole": "*",
"ext-redis": "*",
"ext-amqp": "*",
"sensiolabs/consul-php-sdk": "^2.0",
"guzzlehttp/guzzle": "^7.8",
"php-amqplib/php-amqplib": "^3.2",
"resilience-php/resilience-php": "^1.3",
"apolloconfig/apollo-client": "^2.0"
}
}服务注册与发现完整实现
服务注册(bootstrap.php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28use SensioLabs\Consul\ServiceFactory;
$consul = new ServiceFactory(['base_uri' => 'http://consul-server:8500']);
// 自动获取本机IP
$ip = trim(shell_exec("hostname -i"));
// 注册服务
$consul->get(AgentInterface::class)->registerService([
'ID' => 'order-service-'.gethostname(),
'Name' => 'order-service',
'Address' => $ip,
'Port' => 8000,
'Check' => [
'HTTP' => "http://{$ip}:8000/health",
'Interval' => '5s',
'Timeout' => '2s',
'DeregisterCriticalServiceAfter' => '30s'
],
'Tags' => ['v2', 'primary']
]);
// 健康检查端点
$app->get('/health', function() {
check_database();
check_redis();
return json_response(['status' => 'UP']);
});服务发现与负载均衡
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37class ServiceDiscovery {
private static $cache = [];
private static $ttl = 5; // 缓存5秒
public static function getInstance(string $service): string {
$now = time();
// 缓存有效期内直接返回
if (isset(self::$cache[$service]) &&
$now - self::$cache[$service]['timestamp'] < self::$ttl) {
return self::selectInstance(self::$cache[$service]['instances']);
}
// 从Consul获取新实例
$instances = $consul->getCatalog()->service($service)->json();
self::$cache[$service] = [
'instances' => $instances,
'timestamp' => $now
];
return self::selectInstance($instances);
}
private static function selectInstance(array $instances): string {
// 加权随机算法
$total = array_sum(array_column($instances, 'Weight'));
$rand = mt_rand(1, $total);
$current = 0;
foreach ($instances as $instance) {
$current += $instance['Weight'];
if ($rand <= $current) {
return "http://{$instance['ServiceAddress']}:{$instance['ServicePort']}";
}
}
}
}统一配置中心接入
Apollo配置监听
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23$apollo = new \ApolloClient\Client([
'config_server' => 'http://apollo:8070',
'app_id' => 'order-service',
'cluster' => 'default'
]);
// 初始化配置
$mysqlConfig = $apollo->get('mysql');
DB::connect($mysqlConfig);
// 动态监听
$apollo->listen(['mysql', 'redis'], function($namespace, $config) {
switch ($namespace) {
case 'mysql':
DB::reconnect($config);
break;
case 'redis':
Redis::setConfig($config);
break;
}
Logger::info("Config updated: $namespace");
});服务通信完整方案
同步调用(HTTP)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22class HttpServiceClient {
use CircuitBreaker;
public function call(string $service, string $endpoint, array $data) {
return $this->protect(function() use ($service, $endpoint, $data) {
$baseUrl = ServiceDiscovery::getInstance($service);
$client = new GuzzleHttp\Client([
'base_uri' => $baseUrl,
'timeout' => 2.0
]);
return $client->post($endpoint, [
'json' => $data,
'headers' => [
'X-Trace-Id' => Trace::getId()
]
]);
}, function() { // 降级处理
return ['status' => 'degraded'];
});
}
}异步通信(RabbitMQ)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32class EventPublisher {
private $channel;
public function __construct() {
$conn = new AMQPStreamConnection('rabbitmq', 5672, 'admin', 'secret');
$this->channel = $conn->channel();
// 声明死信交换器
$this->channel->exchange_declare('dlx', 'direct', false, true);
$this->channel->queue_declare('dlq', false, true);
$this->channel->queue_bind('dlq', 'dlx');
}
public function publish(string $event, array $data) {
$this->channel->tx_select();
try {
$message = new AMQPMessage(json_encode($data), [
'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT,
'message_id' => Uuid::uuid4(),
'timestamp' => time()
]);
$this->channel->basic_publish($message, 'events', $event);
DB::table('outbox')->insert(['message_id' => $message->get('message_id')]);
$this->channel->tx_commit();
} catch (Exception $e) {
$this->channel->tx_rollback();
throw $e;
}
}
}服务降级熔断策略
多级降级配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44class DegradeManager {
private static $levels = [
'order-service' => [
'full' => ['threshold' => 0.95, 'fallback' => 'cache'],
'cache' => ['threshold' => 0.8, 'fallback' => 'readonly'],
'readonly' => ['threshold' => 0.5, 'fallback' => 'static']
]
];
public static function handle(string $service, callable $func) {
$status = self::getServiceStatus($service);
try {
switch ($status) {
case 'full':
return $func();
case 'cache':
return Cache::remember("fallback:$service", 60, $func);
case 'readonly':
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
return $func();
}
throw new DegradeException('只读模式');
case 'static':
return ['status' => 'degraded'];
}
} catch (Exception $e) {
self::recordFailure($service);
return self::handle($service, $func); // 自动降级
}
}
private static function getServiceStatus(string $service): string {
$failureRate = Prometheus::getFailureRate($service);
foreach (self::$levels[$service] as $level => $config) {
if ($failureRate <= $config['threshold']) {
return $level;
}
}
return 'static';
}
}监控与告警配置
Prometheus指标收集
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44class Metrics {
private static $counter;
public static function init() {
$registry = new CollectorRegistry(new InMemory());
self::$counter = $registry->registerCounter(
'php',
'http_requests_total',
'Total HTTP requests',
['method', 'endpoint', 'status']
);
// 暴露指标端点
$app->get('/metrics', function() use ($registry) {
$renderer = new RenderTextFormat();
return $renderer->render($registry->getMetricFamilySamples());
});
}
public static function countRequest($method, $path, $status) {
self::$counter->inc([
$method,
preg_replace('/\d+/', '{id}', $path),
$status
]);
}
}
// 在中间件中调用
$app->addMiddleware(function($req, $handler) {
$start = microtime(true);
$response = $handler->handle($req);
$duration = microtime(true) - $start;
Metrics::countRequest(
$req->getMethod(),
$req->getUri()->getPath(),
$response->getStatusCode()
);
return $response;
});生产环境部署建议
服务注册中心:
部署3节点Consul集群
启用ACL和TLS加密
设置自动备份策略
API网关:
Kong集群 + Nginx负载均衡
启用JWT插件和速率限制
配置WAF规则防止攻击
配置中心:
Apollo多环境隔离(DEV/TEST/PROD)
敏感配置加密存储
设置配置变更审批流程
消息队列:
RabbitMQ镜像队列
设置合理的TTL和死信策略
监控队列积压情况
监控系统:
Prometheus联邦集群
Grafana统一看板
关键指标告警(P99延迟>500ms,错误率>1%)
完整架构调用流程示例
- 客户端请求 → Kong网关(认证+限流)
网关查询Consul获取订单服务实例
订单服务处理时:
从Apollo获取当前配置
通过HTTP调用支付服务(带熔断)
发送消息到RabbitMQ
支付服务消费消息后:
更新数据库
记录Prometheus指标
推送结果到通知服务
全链路追踪数据上报Jaeger
本文链接: https://erik.xyz/2025/07/09/php-architecture03/
版权声明: 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。转载请注明出处!