微服务架构
1. 微服务概述
1.1 什么是微服务?
定义:将一个大型应用拆分成多个小型、独立的服务,每个服务负责单一的业务功能。
单体架构 vs 微服务架构:
单体架构:
┌─────────────────────────┐
│ 一个大应用 │
│ ┌──────────────────┐ │
│ │ 用户模块 │ │
│ │ 订单模块 │ │
│ │ 商品模块 │ │
│ │ 支付模块 │ │
│ └──────────────────┘ │
│ 一个数据库 │
└─────────────────────────┘
微服务架构:
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ 用户服务 │ │ 订单服务 │ │ 商品服务 │ │ 支付服务 │
│ DB1 │ │ DB2 │ │ DB3 │ │ DB4 │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
1.2 微服务的优势
- ✅ 独立部署:每个服务可以独立部署和扩展
- ✅ 技术多样性:不同服务可以用不同技术栈
- ✅ 团队自治:每个团队负责一个服务
- ✅ 故障隔离:一个服务出问题不影响其他服务
1.3 微服务的挑战
- ❌ 复杂性增加:需要服务注册、发现、治理
- ❌ 数据一致性:分布式事务难以处理
- ❌ 网络延迟:服务间调用增加网络开销
- ❌ 运维成本:需要更多的监控和部署工具
2. 服务注册与发现
2.1 为什么需要服务注册与发现?
在微服务架构中,服务的 IP 和端口是动态的(容器化部署、自动扩缩容),需要一个中心化的注册中心。
没有注册中心:
订单服务 → 如何找到用户服务的地址?需要硬编码 IP
有注册中心:
用户服务启动 → 注册到 Consul(IP: 192.168.1.100, Port: 9501)
订单服务 → 从 Consul 查询用户服务的地址 → 调用
2.2 Consul 服务注册
安装 Consul
# Docker 方式
docker run -d --name=consul -p 8500:8500 consul
# 访问 Web UI
http://localhost:8500
配置 Hyperf
config/autoload/consul.php:
<?php
return [
'uri' => 'http://127.0.0.1:8500',
'token' => '',
'check' => [
'deregister_critical_service_after' => '90m',
'interval' => '1s',
],
];
注册服务
config/autoload/services.php:
<?php
return [
'enable' => [
'discovery' => true,
'register' => true,
],
'consumers' => [],
'providers' => [],
'drivers' => [
'consul' => [
'uri' => 'http://127.0.0.1:8500',
'token' => '',
],
],
];
启动服务后,会自动注册到 Consul。
2.3 服务发现
<?php
use Hyperf\Di\Annotation\Inject;
use Hyperf\LoadBalancer\LoadBalancerInterface;
use Hyperf\ServiceGovernance\DriverManager;
class OrderService
{
#[Inject]
private DriverManager $driverManager;
public function callUserService()
{
// 从注册中心获取用户服务的节点
$nodes = $this->driverManager->getNodes('user-service');
// 负载均衡选择一个节点
$node = $nodes[array_rand($nodes)];
// 调用服务
$url = "http://{$node['host']}:{$node['port']}/api/user/1";
$response = file_get_contents($url);
return json_decode($response, true);
}
}
3. RPC 服务调用
3.1 什么是 RPC?
RPC(Remote Procedure Call):远程过程调用,像调用本地方法一样调用远程服务。
// 传统 HTTP 调用
$url = 'http://user-service/api/user/1';
$response = file_get_contents($url);
$user = json_decode($response, true);
// RPC 调用(像本地方法一样)
$user = $userService->getUserById(1);
3.2 JSON-RPC 实现
服务端
定义服务接口:
<?php
namespace App\JsonRpc;
interface UserServiceInterface
{
public function getUserById(int $id): array;
public function createUser(array $data): array;
}
实现服务:
<?php
namespace App\JsonRpc;
use Hyperf\RpcServer\Annotation\RpcService;
#[RpcService(
name: 'UserService',
protocol: 'jsonrpc-http',
server: 'jsonrpc-http',
publishTo: 'consul'
)]
class UserService implements UserServiceInterface
{
public function getUserById(int $id): array
{
return [
'id' => $id,
'name' => 'John Doe',
'email' => 'john@example.com',
];
}
public function createUser(array $data): array
{
// 创建用户逻辑
return ['id' => 1, ...$data];
}
}
配置服务端口:
config/autoload/server.php:
<?php
return [
'servers' => [
[
'name' => 'jsonrpc-http',
'type' => Server::SERVER_HTTP,
'host' => '0.0.0.0',
'port' => 9504,
],
],
];
客户端
配置服务消费者:
config/autoload/services.php:
<?php
return [
'consumers' => [
[
'name' => 'UserService',
'service' => App\JsonRpc\UserServiceInterface::class,
'protocol' => 'jsonrpc-http',
'load_balancer' => 'random',
'nodes' => [
['host' => '127.0.0.1', 'port' => 9504],
],
],
],
];
调用服务:
<?php
namespace App\Controller;
use App\JsonRpc\UserServiceInterface;
use Hyperf\Di\Annotation\Inject;
class OrderController
{
#[Inject]
private UserServiceInterface $userService;
public function createOrder()
{
// 像调用本地方法一样调用远程服务
$user = $this->userService->getUserById(1);
// 创建订单
$order = Order::create([
'user_id' => $user['id'],
'total_amount' => 100,
]);
return $order;
}
}
3.3 gRPC 实现
gRPC 是 Google 开发的高性能 RPC 框架,基于 HTTP/2 和 Protocol Buffers。
定义 .proto 文件
grpc/user.proto:
syntax = "proto3";
package user;
service UserService {
rpc GetUser (GetUserRequest) returns (UserReply) {}
}
message GetUserRequest {
int32 id = 1;
}
message UserReply {
int32 id = 1;
string name = 2;
string email = 3;
}
生成 PHP 代码
php bin/hyperf.php gen:grpc-code
实现服务
<?php
namespace App\Grpc;
use Hyperf\GrpcServer\Annotation\GrpcService;
use User\UserServiceInterface;
use User\GetUserRequest;
use User\UserReply;
#[GrpcService(name: 'user.UserService', server: 'grpc')]
class UserService implements UserServiceInterface
{
public function GetUser(GetUserRequest $request): UserReply
{
$user = User::find($request->getId());
$reply = new UserReply();
$reply->setId($user->id);
$reply->setName($user->name);
$reply->setEmail($user->email);
return $reply;
}
}
4. 配置中心
4.1 为什么需要配置中心?
在微服务架构中,配置分散在多个服务中,修改配置需要重新部署。配置中心可以:
- 集中管理配置
- 动态更新配置(无需重启)
- 配置版本管理
4.2 Apollo 配置中心
配置
config/autoload/apollo.php:
<?php
return [
'enable' => true,
'server' => 'http://127.0.0.1:8080',
'appid' => 'my-app',
'cluster' => 'default',
'namespaces' => ['application'],
'interval' => 5, // 轮询间隔(秒)
];
读取配置
<?php
use Hyperf\Config\Annotation\Value;
class UserService
{
#[Value('user.max_age')]
private int $maxAge;
public function checkAge(int $age)
{
if ($age > $this->maxAge) {
throw new \Exception('年龄超过限制');
}
}
}
监听配置变更
<?php
namespace App\Listener;
use Hyperf\Apollo\ConfigProvider;
use Hyperf\Event\Annotation\Listener;
use Hyperf\Event\Contract\ListenerInterface;
use Psr\Container\ContainerInterface;
#[Listener]
class ConfigChangedListener implements ListenerInterface
{
public function __construct(private ContainerInterface $container)
{
}
public function listen(): array
{
return [
ConfigProvider::class,
];
}
public function process(object $event): void
{
echo "配置已更新\n";
// 重新加载配置
$this->container->get(ConfigInterface::class)->reload();
}
}
5. 服务治理
5.1 负载均衡
Hyperf 支持多种负载均衡算法:
<?php
// config/autoload/services.php
return [
'consumers' => [
[
'name' => 'UserService',
'load_balancer' => 'random', // 随机
// 或者:
// 'load_balancer' => 'round-robin', // 轮询
// 'load_balancer' => 'weighted-random', // 加权随机
],
],
];
5.2 熔断器
当服务频繁出错时,自动熔断,避免雪崩。
<?php
namespace App\Service;
use Hyperf\CircuitBreaker\Annotation\CircuitBreaker;
class OrderService
{
#[CircuitBreaker(
timeout: 3.0, // 超时时间
failCounter: 10, // 失败次数阈值
successCounter: 5, // 成功次数阈值(半开状态)
fallback: 'fallbackMethod' // 降级方法
)]
public function callUserService()
{
// 调用用户服务
return $this->userService->getUserById(1);
}
public function fallbackMethod()
{
// 降级逻辑:返回默认数据
return ['id' => 0, 'name' => '游客'];
}
}
熔断器状态:
正常状态 → 失败次数达到阈值 → 熔断状态(直接返回降级数据)
↓
等待一段时间后进入半开状态
↓
尝试调用,成功次数达到阈值 → 恢复正常
5.3 限流
防止服务被过多请求压垮。
<?php
namespace App\Middleware;
use Hyperf\Di\Annotation\Inject;
use Hyperf\RateLimit\Annotation\RateLimit;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
#[RateLimit(
create: 10, // 每秒创建 10 个令牌
capacity: 100, // 令牌桶容量
consume: 1 // 每次请求消耗 1 个令牌
)]
class RateLimitMiddleware implements MiddlewareInterface
{
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
// 如果令牌不足,会抛出异常
return $handler->handle($request);
}
}
5.4 链路追踪
在微服务架构中,一个请求可能经过多个服务,链路追踪可以追踪请求的完整路径。
集成 Zipkin
composer require hyperf/tracer
config/autoload/opentracing.php:
<?php
return [
'default' => 'zipkin',
'enable' => [
'guzzle' => true,
'redis' => true,
'db' => true,
],
'tracer' => [
'zipkin' => [
'driver' => Hyperf\Tracer\Adapter\ZipkinTracerFactory::class,
'app' => [
'name' => 'order-service',
],
'options' => [
'endpoint_url' => 'http://localhost:9411/api/v2/spans',
],
],
],
];
启动后,所有请求都会自动追踪到 Zipkin。
6. 分布式事务
6.1 问题
在微服务架构中,一个业务可能涉及多个服务,如何保证数据一致性?
创建订单:
1. 订单服务:创建订单
2. 库存服务:扣减库存
3. 支付服务:扣款
如果支付失败,如何回滚订单和库存?
6.2 解决方案
方案一:Saga 模式
每个服务定义正向操作和补偿操作(回滚)。
<?php
namespace App\Saga;
class OrderSaga
{
public function execute()
{
try {
// 1. 创建订单
$orderId = $this->orderService->create();
// 2. 扣减库存
$this->inventoryService->deduct($productId, $quantity);
// 3. 扣款
$this->paymentService->pay($amount);
return $orderId;
} catch (\Exception $e) {
// 补偿操作(回滚)
$this->paymentService->refund($amount);
$this->inventoryService->restore($productId, $quantity);
$this->orderService->cancel($orderId);
throw $e;
}
}
}
方案二:消息队列(最终一致性)
通过消息队列实现异步补偿。
<?php
// 订单服务
public function createOrder()
{
// 1. 创建订单
$order = Order::create([...]);
// 2. 发送消息到队列
$this->producer->produce(new OrderCreatedMessage([
'order_id' => $order->id,
'product_id' => $productId,
'quantity' => $quantity,
]));
return $order;
}
// 库存服务(消费者)
public function handleOrderCreated(OrderCreatedMessage $message)
{
try {
// 扣减库存
$this->deduct($message->product_id, $message->quantity);
// 发送成功消息
$this->producer->produce(new InventoryDeductedMessage([...]));
} catch (\Exception $e) {
// 发送失败消息
$this->producer->produce(new InventoryDeductFailedMessage([...]));
}
}
7. 要点
必须掌握
- 微服务的概念和优势
- 服务注册与发现的原理
- RPC 的概念和使用
- 负载均衡的几种算法
- 熔断器的作用
加分项
- 分布式事务的解决方案
- 配置中心的使用
- 链路追踪的原理
- 服务网格(Service Mesh)
高频题
1. 什么是微服务?有什么优势?
答:微服务是将大型应用拆分成多个小型、独立的服务。
优势:
- 独立部署和扩展
- 技术多样性
- 团队自治
- 故障隔离
2. 服务注册与发现是什么?
答:服务启动时将自己的地址注册到注册中心(如 Consul),其他服务从注册中心查询服务地址并调用。
3. 如何解决分布式事务问题?
答:常见方案:
- Saga 模式:定义补偿操作
- 消息队列:最终一致性
- TCC(Try-Confirm-Cancel)
下一步:阅读 07-性能优化.md 学习性能优化