这是微服务架构中"API 网关 + 服务发现"最核心的协作机制。我在项目中使用的API网关是Kong,服务注册中心是Consul,这里就拿他们讲解。
我们来一步步、用通俗易懂的方式详细讲解这个过程,结合微服务项目场景来说明。
一、目标是什么?
想实现的效果是:
用户访问
/goods/list
→ 请求被 Kong 接收 → Kong 自动知道这个请求应该转发给 商品服务(goods-srv) → 并且能自动负载均衡到多个goods-srv
实例上。
而且:
- 不用手动写死 IP 地址
- 商品服务扩容/缩容(实例增减)时,Kong 能自动感知
- 新增一个服务(比如
order-srv
),只需注册进 Consul,Kong 就能路由过去
这就叫:动态路由 + 动态服务发现
二、Kong 和 Consul 分别做什么?
组件 | 角色 |
---|---|
Kong | API 网关,负责接收所有外部请求,决定"这个请求该转发给谁" |
Consul | 服务注册中心,记录"每个服务叫什么名字、有哪些实例(IP+端口)、健康吗?" |
它们配合起来,就像"快递分拣中心(Kong)"和"公司员工花名册(Consul)"。
三、核心机制:Kong 如何知道服务在哪?------"服务(Service)"的概念
Kong 内部有两个关键抽象:
1. Service(服务)
-
表示一个后端微服务(如
goods-srv
) -
它不直接写死 IP,而是告诉 Kong:"你要找的商品服务,在 Consul 里叫
mxshop-goods-srv
" -
配置示例:
bashcurl -X POST http://kong:8001/services \ -d "name=goods-service" \ -d "url=consul://consul:8500/mxshop-goods-srv"
name=goods-service
:这是 Kong 内部给这个后端服务起的名字。url=consul://...
:这是重点!它不是http://192.168.1.10:8001
这种固定地址,而是指向 Consul 中注册的服务名mxshop-goods-srv
。
✅ 所以,Kong 的 "Service" 是一个逻辑概念,它通过 Consul 动态获取真实地址。
2. Route(路由)
-
表示"什么样的请求应该交给哪个 Service 处理"
-
通常是基于 URL 路径或 Host 匹配
-
配置示例:
bashcurl -X POST http://kong:8001/services/goods-service/routes \ -d "paths[]=/goods" \ -d "methods[]=GET" \ -d "methods[]=POST"
- 意思是:所有以
/goods
开头的请求(如/goods/list
,/goods/detail
),都交给goods-service
这个 Service 处理。
- 意思是:所有以
四、完整请求流转过程(以 /goods/list
为例)
我们来走一遍用户请求的完整路径:
步骤 1️⃣:用户发起请求
arduino
GET http://api.example.com/goods/list
步骤 2️⃣:Kong 接收到请求
Kong 检查所有 Route,发现 /goods
路径匹配 goods-service
这个 Service。
步骤 3️⃣:Kong 查询 Consul 获取真实地址
Kong 看到 goods-service
的 url=consul://.../mxshop-goods-srv
,于是:
-
向 Consul 发起查询:
"mxshop-goods-srv" 这个服务现在有哪些健康的实例?"
-
Consul 返回:
css[ {"Address": "192.168.1.10", "Port": 50051}, {"Address": "192.168.1.11", "Port": 50051}, {"Address": "192.168.1.12", "Port": 50051}]
步骤 4️⃣:Kong 选择一个实例并转发
Kong 从这三个地址中按负载均衡策略(如轮询)选一个,比如 192.168.1.11:50051
,然后把请求转发过去:
arduino
GET http://192.168.1.11:50051/goods/list
✅ 最终结果
用户无感知地访问到了商品服务,而 Kong 完全不知道具体 IP,它只认"服务名"。
五、动态性体现在哪里?------服务扩缩容自动适配
假设你现在把商品服务从 3 个实例扩容到 5 个:
- 新的
goods-srv
实例启动 → 自动向 Consul 注册自己(服务名仍是mxshop-goods-srv
) - Consul 更新服务列表,新增两个实例
- Kong 通过 Consul 插件(定期轮询或监听事件)自动获取最新实例列表
- 下次请求来时,Kong 就可能把流量分发到新实例上
👉 整个过程不需要你手动改 Kong 配置!
六、新增一个服务(如 order-srv)怎么办?
-
order-srv
启动 → 向 Consul 注册为mxshop-order-srv
-
在 Kong 中创建新 Service:
bashcurl -X POST http://kong:8001/services \ -d "name=order-service" \ -d "url=consul://consul:8500/mxshop-order-srv"
-
创建对应路由:
bashcurl -X POST http://kong:8001/services/order-service/routes \ -d "paths[]=/order"
-
用户访问
/order/create
→ 自动转发到order-srv
✅ 只要服务在 Consul 注册了,Kong 就能通过服务名找到它。
七、总结:Kong + Consul 动态路由的本质
层级 | 配置项 | 作用 | 是否需要手动配置 |
---|---|---|---|
1. 路由层 | Route (/goods ) |
匹配 URL 路径 | ✅ 需要(一次) |
2. 服务层 | Service (goods-service ) |
指向 Consul 中的服务名 | ✅ 需要(一次) |
3. 发现层 | Consul (mxshop-goods-srv ) |
存储真实 IP 列表 | ❌ 自动注册/更新 |
✅ 优势总结:
- 解耦:Kong 不关心 IP,只关心"服务名"
- 动态:实例增减,自动感知
- 可维护:新增服务只需加 Route + Service,无需改代码
- 高可用:结合健康检查,自动剔除不健康实例
Kong 的 Consul 插件是如何工作的?
Kong 通过内置的 consul
协议支持,或使用 kong-plugin-consul-discovery
插件,实现以下功能:
- 定期向 Consul 查询服务实例列表(默认每 5~10 秒)
- 支持长轮询(Watch)模式,变更更实时
- 支持健康检查过滤,只返回健康实例
- 支持负载均衡(Kong 内置轮询、哈希等策略)
你现在完全可以这样理解:
API网关 是"指挥官",它不亲自打仗(处理业务),而是根据"花名册"(服务注册中心Consul)上的名单,把任务(请求)分配给正确的"士兵"(微服务实例)。名单变了,指挥官自动调整,无需重新训练。
这就是项目中实现的"动态路由"的精髓!