云计算百科
云计算领域专业知识百科平台

【基于 Swoole+Hyperf 的微服务实战】 第四周·周五:将文章系统和用户服务全量接入 Consul + Nacos,验证无感扩容

今天是第二阶段“微服务通信与治理”的收官之战。今天我们将完成一个关键实战:将文章系统和用户服务全量接入 Consul + Nacos,验证无感扩容。前面四天我们分别完成了服务注册、服务发现、配置中心集成和多环境配置管理,今天要把这些能力串联起来,模拟生产环境中服务实例动态伸缩的场景,让消费者在不重启的情况下自动感知变化,实现真正的弹性伸缩。


在这里插入图片描述

今日目标

  • 确保文章服务(HTTP) 和用户服务(JSON-RPC) 均已接入 Consul 和 Nacos。
  • 以用户服务为例,通过启动多个实例来模拟扩容,通过停止实例模拟缩容。
  • 观察文章服务通过 Consul 服务发现动态获取最新的用户服务节点列表,负载均衡器自动将流量分配到新旧实例。
  • 结合 Nacos 动态配置,实时调整限流阈值,验证配置变更无需重启。
  • 使用压测工具观察整个过程中的服务连续性和错误率,确保“无感”。

  • 一、环境准备与现状确认(约 30 分钟)

    继续在 hyperf-app 项目中,确保 Docker 已启动并进入容器:

    docker-compose exec swoole bash
    cd /var/www/hyperf-app

    1. 确认当前服务架构
    • HTTP 服务(文章/订单):监听 0.0.0.0:9501
    • 用户服务(UserService):监听 0.0.0.0:9502(我们之前只保留了一个节点用于演示)
    • 商品服务(ProductService):监听 0.0.0.0:9504

    Consul 中应该已经注册了这两个服务(可以通过 UI http://localhost:8500 查看)。Nacos 中也已经有了 hyperf-app 配置(dev 命名空间),包含限流参数等。

    2. 启停问题

    由于我们只有一个 Docker PHP 容器,要启动多个用户服务实例,我们有两个选择:

    • 在同一个 Hyperf 进程中添加另一个 JSON-RPC 服务器,监听不同端口(如 9503),并确保它也被注册到 Consul(需要另一个 @RpcService 实现或手动注册)。
    • 使用 Docker 再启动一个相同的 PHP 容器(或用不同端口启动另一个 Hyperf 进程),但需要共享代码。

    考虑到开发环境简单性,我们采用在同一个 Hyperf 应用中启用第二个 JSON-RPC 用户服务节点,并手动将其注册到 Consul。以前我们的 server.php 中曾配置过 jsonrpc2(端口 9503),今天恢复它,并让用户服务也绑定到该服务器,以便注册两个实例。


    二、知识核心回顾(约 20 分钟)

    • 服务注册:Provider 启动时自动向 Consul 注册,健康检查维持心跳。
    • 服务发现:Consumer 通过 Consul 定期拉取健康的节点列表,配合负载均衡器使用。
    • 动态扩容:新实例注册 → Consul 通知或消费者刷新列表 → 流量自然导入新实例。
    • 动态缩容:实例下线或健康检查失败 → Consul 标记不健康 → 消费者刷新后剔除该节点。
    • 配置动态下发:Nacos 配置变更 → 应用热加载,无需重启。

    今天要验证的核心就是扩容和缩容的过程对调用方完全透明,消费者自动适应。


    三、实战:模拟动态伸缩全过程(约 3 小时)

    步骤 1:恢复多节点用户服务

    编辑 config/autoload/server.php,在 servers 数组中加入第二个 JSON-RPC 服务器(如果之前注释掉了):

    [
    'name' => 'jsonrpc2',
    'type' => Server::SERVER_HTTP,
    'host' => '0.0.0.0',
    'port' => 9503,
    'sock_type' => SWOOLE_SOCK_TCP,
    'callbacks' => [
    Event::ON_REQUEST => [\\Hyperf\\JsonRpc\\HttpServer::class, 'onRequest'],
    ],
    ],

    为了让第二个端口也服务于 UserService,我们需要一个额外的 @RpcService 实现类。简单地,我们可以复制 UserService 并修改注解中的 server 为 jsonrpc2。创建 app/JsonRpc/UserService2.php:

    <?php
    namespace App\\JsonRpc;

    use Hyperf\\RpcServer\\Annotation\\RpcService;

    #[RpcService(name: "UserService", protocol: "jsonrpc-http", server: "jsonrpc2")]
    class UserService2 extends UserService
    {
    // 直接继承,行为一致
    }

    同样在 dependencies.php 中可能需要绑定,但 Hyperf 会自动扫描注解并注册为服务,因此只要我们配置了 jsonrpc2 服务端,这个类就会被注册为一个 RPC 服务提供者,端口 9503 也会加入 UserService 的节点列表。

    注意:此时 UserService 和 UserService2 都实现了 UserServiceInterface?UserService2 继承了 UserService,而 UserService 已经实现了 UserServiceInterface,所以没问题。

    步骤 2:确认 Consul 注册配置

    在 config/autoload/services.php 的 drivers.consul 中,确保 check 配置存在(昨天已配)。同时,确保 consumers.UserService 使用 registry 指向 Consul,refresh_time 设为较小的值(如 5 秒)以便快速观察。

    步骤 3:启动多实例用户服务

    重启 Hyperf 应用:

    php bin/hyperf.php start

    观察控制台输出,应显示 jsonrpc (9502) 和 jsonrpc2 (9503) 均启动。查看 Consul UI (http://localhost:8500),UserService 下应出现两个实例,分别对应 9502 和 9503,且健康状态都为绿色。

    步骤 4:验证消费者发现双节点

    调用订单接口或文章详情接口(都会远程调用用户服务):

    curl http://localhost:9501/orders/1

    查看 hyperf.log,负载均衡器日志应显示类似:

    RPC负载均衡,可用节点: [{"host":"127.0.0.1","port":9502},{"host":"127.0.0.1","port":9503}]
    RPC请求路由到节点: 127.0.0.1:9502

    连续请求几次,会看到交替路由到 9502 和 9503,说明双节点负载均衡生效,扩容成功。

    步骤 5:模拟缩容——摘除一个节点

    暂时停止第二个用户服务节点,我们可以通过修改 server.php 将 jsonrpc2 注释掉,或者更简单:在 Consul API 中手动将第二个节点标记为不健康。但为了真实,我们热停止第二个 JSON-RPC 服务器端口。由于它们运行在同一个 Worker 进程中,无法单独停止端口。我们可以临时注释掉 server.php 中的 jsonrpc2 配置,然后重启服务来模拟缩容。但重启会导致短暂中断,不符合“无感”。更好的方法是:我们在另一个终端中手动向 Consul 发送该节点下线请求,让 Consul 标记为 critical,从而消费者会自动移除它。

    使用 API 下线 9503 实例:
    首先需要知道该实例的 Service ID。在 Consul UI 中点击 UserService,可以看到每个实例的 ID(通常是类名或随机 ID)。例如可能是 UserService-jsonrpc2-…。我们也可以通过 API 注销它:

    # 列出 UserService 的所有实例
    curl http://consul:8500/v1/health/service/UserService
    # 找到对应 9503 的 ServiceID,然后调用注销
    curl -X PUT http://consul:8500/v1/agent/service/deregister/<ServiceID>

    注销后,消费者会在下一次刷新(5 秒内)更新节点列表,之后请求只会路由到 9502。观察日志,可用节点列表变成只有一个。

    无感验证:在注销前后持续发送请求:

    # 在另一个终端循环发送请求
    while true; do curl -s http://localhost:9501/orders/1 | jq .; sleep 0.2; done

    在注销瞬间,可能会有一次请求失败(如果恰好发往被注销的节点且该节点真的停止了服务),但因为我们的 9503 服务实际并未真正停止进程(只是注销了 Consul),请求仍然能到达,所以不会出错。若要真正模拟宕机,可同时停止 9503 端口的监听(但这里无法单独停止)。不过我们主要展示的是消费者节点列表的变化,这已经证明了动态感知能力。

    更极致的模拟:使用两个独立的 Docker 容器分别运行不同的 Hyperf 实例,这样就能真正停止一个容器。受限于环境,我们通过 Consul 注销来等效演示。

    步骤 6:结合 Nacos 动态调整限流

    在 Nacos 控制台(dev 命名空间)修改配置,将 rate_limit.like_per_minute 从 10 改为 3,发布。
    无需重启服务,立即测试点赞接口:

    for i in {1..5}; do curl -X POST http://localhost:9501/articles/1/like; echo; sleep 0.5; done

    前 3 次应该成功(可能受之前计数影响),之后返回 429,证明动态限流生效。这就是配置中心的威力。

    步骤 7:全链路压测与观察

    使用 ab 对订单详情接口进行 200 并发请求,查看日志中的负载均衡分布、错误率:

    ab -n 200 -c 20 http://localhost:9501/orders/1

    观察:

    • 请求失败数应为 0。
    • 日志中两个用户服务节点被均匀路由(如果都在线)。
    • 熔断器没有打开。
    • 连接池工作正常。

    然后模拟缩容(注销一个节点),再次压测,观察错误率:由于负载均衡器会选择剩余节点,可能刚开始会有个别连接失败(如果注销的同时有请求正在发往那个节点且节点已拒绝),但很快稳定,错误率应该接近 0。说明具有高可用性。


    四、成果测试与检验(约 1 小时)

    测试清单
    检验项方法通过标准
    双节点注册 Consul UI 或 API 查看 UserService 两个实例,端口 9502 和 9503,健康
    消费者发现双节点 查看 hyperf.log 负载均衡器日志 可用节点列表包含两个节点,请求轮询到两个节点
    缩容自动剔除 注销 9503 节点,等待刷新,再次请求 日志中节点列表只剩 9502,请求不再路由到 9503
    配置动态更新 修改 Nacos 中的限流值,测试点赞 新阈值生效,无重启
    无感扩容/缩容 持续发送请求过程中执行缩容操作 请求失败率 < 1%(理想 0)
    全链路压测 ab 压测订单接口 QPS 稳定,错误率 0,熔断未触发
    常见问题与定位
    • 第二个节点没有注册到 Consul:检查 UserService2 类的 #[RpcService] 注解是否正确,server 名称是否与 server.php 中的配置一致;检查是否触发了 Composer 自动加载(可能需要 composer dump-autoload)。
    • 负载均衡器日志不打印:检查日志级别是否为 INFO,确认 CustomRoundRobin 的 select 是否被调用。
    • 配置中心更新延迟:Nacos 客户端长轮询间隔可临时调为 1 秒,更快感知变化。
    • 端口冲突:确保 9503 未被其他服务占用。

    五、今日作业与学习产出

  • 提交代码:将 UserService2、修改后的 server.php 等提交到 Git,附上今天的测试截图或日志示例。
  • 绘制架构演进图:
    • 对比最初硬编码节点 → 注册中心 + 手动多节点 → 动态伸缩的演变过程。
    • 画出完整的服务调用链路图,包含 Nacos 配置下发和 Consul 节点变更的流程。
  • 学习笔记:
    • 总结服务无感扩容的关键要素:注册中心、健康检查、客户端负载均衡、配置中心协同。
    • 思考:如果注册中心本身宕机,消费者还能调用服务吗?(答案:可以,因为消费者有本地缓存。)
  • 挑战任务:
    • 使用 Docker Compose 扩容命令 启动多个 PHP 容器实例(不同端口)作为独立的用户服务节点,观察 Consul 中自动出现多个实例,并测试真实缩容(docker stop 一个容器)时的无感效果。
    • 尝试使用 Nacos 的灰度发布功能,仅对特定消费者下发新配置。
  • 恭喜你完成了第四周的全部内容!经过这一周,你的微服务已经具备了动态服务治理的能力:服务能够自动注册和发现,配置可实时变更,实例可弹性伸缩,整个系统向着生产级迈进了一大步。下周我们将进入 API 网关的世界,将所有这些后端服务统一管理起来。

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 【基于 Swoole+Hyperf 的微服务实战】 第四周·周五:将文章系统和用户服务全量接入 Consul + Nacos,验证无感扩容
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!