读完这篇,你会明白为什么有些网关改配置不用重启,而有些必须 reload。附路由匹配算法源码级分析。前言上篇文章我们搭了一套 API 网关集群,通过 Admin API 下发路由规则后,不到 1 秒即可生效,全程零中断。你有没有想过:这背后的原理是什么?配置从 Admin API 一路流转到真正生效,中间经历了什么?为什么有些网关写个新路由必须 reload Nginx,而我们的网关可以丝滑热更新?今天这篇,我就带你把动态路由热更新的完整链路拆开来看。本文将基于一个真实开源网关的架构来讲解,为保持通用性,不出现具体项目名,统一称为"网关 G"。一、整体架构回顾先回顾一下网关 G 的架构分层:┌──────────────────────────────────────────────────┐ │ 数据面 (Data Plane) │ │ ┌──────────┐ ┌──────────┐ ┌───────────────┐ │ │ │ 路由匹配器 │ │ 插件链执行 │ │ 负载均衡/代理 │ │ │ └──────────┘ └──────────┘ └───────────────┘ │ │ ↑ │ │ ┌──────┴──────┐ │ │ │ 本地缓存层 │ ← LRU Cache │ │ └──────┬──────┘ │ │ │ watch │ ├──────────────────────┼───────────────────────────┤ │ 控制面 (Control Plane) │ │ ┌──────────┐ ┌────┴─────┐ ┌────────────────┐ │ │ │ Admin API │→│ 配置中心 │←→│ Dashboard │ │ │ └──────────┘ │ (etcd) │ └────────────────┘ │ │ └──────────┘ │ └──────────────────────────────────────────────────┘两个关键设计:控制面与数据面分离:Admin API 只管往 etcd 写配置,网关节点通过 watch 机制拉取配置本地缓存层:每个网关节点把路由数据缓存在本地内存中,避免每次请求都查 etcd二、从 Admin API 到配置生效:完整时序以一个"下发新路由规则"的操作为例,完整时序如下:时刻 T0: 用户调用 Admin API curl -X PUT /apisix/admin/routes/1 -d '{...}' 时刻 T1: Admin API 校验请求参数 → 写入 etcd key: /demo-gateway/routes/1 value: { "uri": "/api/*", "upstream": {...} } 时刻 T2: etcd 通知所有 watch 该 key 的网关节点 时刻 T3: 每个网关节点的 watch 回调触发 时刻 T4: 节点从 etcd 拉取最新路由配置 时刻 T5: 节点重建本地路由索引(前缀树) 时刻 T6: 新路由正式生效,客户端请求开始命中从 T0 到 T6 的总耗时通常在 100ms ~ 500ms 之间,这就是"秒级生效"的来源。接下来,我们逐个环节拆开来看。三、环节一:配置写入——Admin API 做了啥当用户调用 Admin API 时,网关干了三件事:3.1 请求校验-- demo: admin/init.lua 简化的请求处理流程localfunctionhandle_request()localuri=ngx.var.uri-- 请求路径localmethod=ngx.req.get_method()-- 请求方法localbody=get_request_body()-- 请求体 JSON-- Step 1: 鉴权localapi_key=ngx.req.get_headers()["X-API-KEY"]ifapi_key~=config.admin_keythenreturnerror_response(401,"Unauthorized")end-- Step 2: 参数校验(JSON Schema 验证)localok,err=validate_schema("route",body)ifnotokthenreturnerror_response(400,"Invalid schema: "..err)end-- Step 3: 写入 etcdlocalkey="/demo-gateway/routes/"..route_idlocalok,err=etcd_client:set(key,body)ifnotokthenreturnerror_response(500,"etcd write failed: "..err)endreturnsuccess_response(body)endSchema 验证 Demo——一条路由规则的结构要求:-- demo: admin/schema.lua 中的路由 Schema 定义localroute_schema={type="object",properties={uri={type="string"},-- 匹配路径uris={type="array",items={type="string"}},-- 多条路径host={type="string"},-- 匹配域名methods={type="array",items={enum={"GET","POST","PUT","DELETE","PATCH","HEAD"}}},upstream={type="object",properties={type={enum={"roundrobin","chash","ewma","least_conn"}},nodes={type="object"},-- 后端节点列表timeout={type="object",properties={connect={type="number",default=6},send={type="number",default=6},read={type="number",default=6},}}}},plugins=