微服务治理-注册中心

一、介绍

1.1 什么是注册中心

注册中心可以理解为:

整个微服务系统的“通讯录”或“服务目录”。

在单体应用中:

Web
Controller
Service
Repository

所有模块都运行在同一个进程中,方法之间直接调用: $user = $this->userService->getUser($id);

开发者无需关心:

  • 服务在哪里?
  • IP 是多少?
  • 端口是多少?

因为它们都在同一个应用中。


而在微服务架构中:

                User Service

                10.0.0.10


Order Service ---------------- Product Service

10.0.0.11                  10.0.0.12

现在 Order Service 想调用 User Service。

问题来了:Order Service 怎么知道 User Service 在哪里?

如果直接写 IP:虽然可以运行,但会产生很多问题。

1.2 为什么不能写死 IP?

假设:今天:User Service 10.0.0.10

后面因为扩容:User Service 10.0.0.20 或者增加服务器:10.0.0.xxx

那么:

所有调用 User Service 的项目:都要修改配置。

到底调用哪一个?

于是:

需要一个统一管理所有服务信息的地方。

这个地方就是:

注册中心(Registry)

1.4 注册中心解决什么问题?

1.统一管理服务地址

所有服务启动后都会向注册中心注册:

user-service
10.0.0.5:9501
10.0.0.6:9501
10.0.0.7:9501

其他服务无需关心具体 IP,只需要知道服务名: user-service

2.动态更新

新增实例:10.0.0.8

自动加入注册中心。

无需修改业务代码。

3. 自动下线

服务器宕机:10.0.0.6

注册中心:

自动删除。

调用方不会再访问已经失效的实例。

4.为其它治理能力提供基础

很多微服务能力都依赖注册中心。

二、原理

2.1 注册中心整体架构

典型架构如下:

                  +----------------------+
                  |   Service Registry   |
                  |   (Nacos/Consul)     |
                  +----------+-----------+
           Register          │         Register
      +----------------+     │     +----------------+
      | User Service   |-----+-----| Order Service  |
      +----------------+           +----------------+
              ▲                              │
              │                              │ Discover
              │                              ▼
                         Payment Service

流程:

  1. 服务启动。
  2. 向注册中心注册自己。
  3. 注册中心保存服务信息。
  4. 调用方从注册中心获取服务地址。

2.2 服务注册流程

以 User Service 为例:

User Service 启动
读取配置
获取本机 IP、端口
发送 Register 请求
Registry 保存:
user-service
10.0.0.5:9501

以后:

所有服务都能找到它。

2.3 注册信息包含什么?

通常包括:

字段说明
ServiceName服务名称
InstanceId实例 ID
IP服务地址
Port服务端口
Version服务版本
Weight权重
Metadata元数据
Status服务状态

例如:

{
    "service": "user-service",
    "ip": "10.0.0.5",
    "port": 9501,
    "version": "1.0.0",
    "weight": 100,
    "status": "UP"
}

2.4 注册中心如何保存数据?

可以理解为一个服务目录:

user-service
├── 10.0.0.5:9501
├── 10.0.0.6:9501
└── 10.0.0.7:9501

order-service
├── 10.0.0.10:9502
└── 10.0.0.11:9502

调用方查询:user-service

返回:

[ 10.0.0.5, 10.0.0.6, 10.0.0.7 ]

然后再由负载均衡选择一个实例。

2.5 服务生命周期

一个服务实例通常会经历:

启动
注册(Register)
心跳(Heartbeat)
正常运行
优雅下线(Deregister)

如果服务异常退出:

心跳停止


注册中心检测超时


自动移除实例

因此,心跳机制是注册中心的重要组成部分。

三、实现

3.1 最简单的注册中心(PHP 示例)

假设我们不用 Nacos,而是自己实现一个极简版注册中心。

服务注册:

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;

class RegistryController
{
    public function register(Request $request)
    {
        $service = $request->input('service');
        $instance = [
            'ip' => $request->input('ip'),
            'port' => $request->input('port'),
            'time' => time(),
        ];

        $instances = Cache::get($service, []);
        $instances[] = $instance;

        Cache::put($service, $instances, now()->addMinutes(5));

        return response()->json(['success' => true]);
    }
}

这里只是演示原理,实际生产环境通常不会直接使用缓存存储服务目录。

3.2 主流注册中心对比

产品语言生态一致性协议特点
NacosJava、Spring、PHP 等AP(支持 CP 模式)注册中心 + 配置中心,国内应用广泛
Consul多语言Raft(CP)服务发现、KV 配置、健康检查能力完善
EurekaJavaAPSpring Cloud Netflix 经典方案,现已较少用于新项目
EtcdGo、KubernetesRaft(CP)Kubernetes 默认存储,适合基础设施场景

对于 PHP 微服务来说,Nacos 和 Consul 是更常见的选择。

四、实践

1. 服务名称保持唯一

建议采用统一命名,例如:

user-service
order-service
inventory-service
payment-service

2. 不要使用固定 IP 调用

正确方式:

先通过注册中心获取可用实例,再进行调用。

3. 服务下线要优雅

实例准备下线时:

  1. 从注册中心注销(Deregister)。
  2. 等待当前请求处理完成。
  3. 再关闭进程。

避免请求打到即将退出的实例。

4. 注册信息不要过于复杂

注册中心保存的是服务元数据,而不是业务数据。

例如:

  • 服务名
  • IP
  • 端口
  • 权重
  • 标签
  • 版本

不要把用户信息、订单数据等业务内容放入注册中心。