写分布式服务的人都有过这种体验:一个接口逻辑只有二十行,但前后各塞了十行——鉴权、限流、日志、重试、熔断。业务代码被横切关注点淹没,改一个路由规则要重新部署三个服务。代理架构要解决的就是这个问题:让组件只管业务,通信协调和系统质量相关的活交给代理。
代理在分布式系统中的角色
代理架构的核心思路很简单——组件之间不直接调用,而是通过代理间接交互。代理坐在这条链路上,既转发请求,也拦截请求。它不是简单的"传话筒",而是一个具备决策能力的中间层。
典型拓扑是这样的:
Service A → Proxy → Proxy → Service B
每个组件只知道自己要跟哪个代理对话,不知道对方的真实地址。代理之间可以组成网格,也可以集中为网关形态。无论哪种部署形式,代理承担的职责是一致的:
- 路由:把请求导向正确的实例或版本,支持灰度、流量拆分
- 安全:TLS 终止、身份校验、访问控制,业务服务不再自己处理证书轮换
- 熔断与容错:下游异常时快速失败,避免级联雪崩
- 缓存:对高频读请求做响应缓存,减轻后端压力
- 日志与可观测性:统一采集调用链路指标,业务服务零侵入接入监控
这些功能如果写在业务代码里,每个服务都要重复实现一遍。代理把它们抽出来,变成基础设施能力。
两种主流部署形态
代理架构落地时,通常走向两种形态,各有适用场景:
集中式网关——所有外部流量先经过一个代理集群再进入内部服务。适合南北向流量(客户端到服务端),典型实现是 Kong、Nginx Ingress Controller。优点是管控集中、配置一处生效;缺点是网关成为单点,规模大时需要仔细做高可用。
分布式 Sidecar——每个服务实例旁部署一个轻量代理,服务间调用都经过各自的 Sidecar。适合东西向流量(服务到服务),典型实现是 Istio 的 Envoy Sidecar。优点是无单点、策略可按服务细粒度定制;缺点是代理数量多,运维和资源开销更高。
实际系统中两种形态经常共存:网关挡外部流量,Sidecar 管内部网格。
用 Envoy Sidecar 搭一个最小代理层
下面用一个 Kubernetes + Envoy 的最小示例,展示代理架构怎么把鉴权、路由、熔断从业务代码里拿走。假设你有两个服务:order-service 和 payment-service,订单服务调用支付服务。我们给订单服务加一个 Envoy Sidecar 代理,让它接管所有出站流量。
先定义 Envoy 的配置——这是代理架构中最核心的文件,所有路由、熔断、安全策略都在这里声明:
# envoy-config.yaml — Envoy Sidecar 配置
static_resources:
listeners:
- name: outbound_listener
address:
socket_address:
address: 0.0.0.0
port_value: 15001
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: outbound
route_config:
name: local_route
virtual_hosts:
- name: payment_service
domains: ["payment-service"]
routes:
- match:
prefix: "/"
route:
cluster: payment_cluster
timeout: 3s # 请求超时,替代业务代码里的 retry timeout
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: payment_cluster
type: STRICT_DNS
connect_timeout: 1s
lb_policy: ROUND_ROBIN
circuit_breakers: # 熔断配置,替代业务代码里的 circuit breaker
thresholds:
- priority: DEFAULT
max_connections: 100
max_pending_requests: 50
max_requests: 200
max_retries: 3
outlier_detection: # 异常实例自动摘除
consecutive_5xx: 3
interval: 10s
base_ejection_time: 30s
load_assignment:
cluster_name: payment_cluster
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: payment-service
port_value: 8080
这份配置做了三件业务代码不再需要做的事:
- 路由:访问
payment-service的请求全部走payment_cluster,业务代码只需用服务名发起调用,不用知道真实 IP。 - 超时与熔断:3 秒请求超时、100 连接上限、连续 3 次 5xx 自动摘除实例——这些参数原来要写在每个服务的 SDK 里。
- 负载均衡:ROUND_ROBIN 策略由代理执行,业务侧无需引入客户端负载均衡库。
接下来把 Envoy 作为 Sidecar 部署到订单服务所在的 Pod:
# order-deployment.yaml — 带 Sidecar 的订单服务部署
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
spec:
replicas: 2
selector:
matchLabels:
app: order-service
template:
metadata:
labels:
app: order-service
spec:
containers:
# 业务容器:只管订单逻辑
- name: order-app
image: order-service:v1
env:
- name: PAYMENT_URL
value: "http://127.0.0.1:15001" # 出站流量走本地 Sidecar
ports:
- containerPort: 8080
# 代理容器:接管通信、安全、熔断
- name: envoy-sidecar
image: envoyproxy/envoy:v1.28-latest
volumeMounts:
- name: envoy-config
mountPath: /etc/envoy
readOnly: true
volumes:
- name: envoy-config
configMap:
name: envoy-outbound-config
部署到集群:
# 创建 ConfigMap 存放 Envoy 配置
kubectl create configmap envoy-outbound-config \
--from-file=envoy.yaml=envoy-config.yaml \
-n default
# 部署带 Sidecar 的订单服务
kubectl apply -f order-deployment.yaml -n default
# 验证 Sidecar 正常启动
kubectl logs deployment/order-service -c envoy-sidecar -n default | head -5
# 期望看到:starting main dispatch loop
关键变化在 PAYMENT_URL 这个环境变量:业务代码不再直连支付服务,而是请求本地 Sidecar 的 15001 端口。Envoy 根据配置中的路由规则,把请求转发到真实的 payment-service:8080。业务代码里所有关于重试、超时、熔断的逻辑都可以删掉——代理已经接管了。
如果后续要加鉴权,只需在 Envoy 配置里增加一个 envoy.filters.http.ext_authz 过滤器指向外部鉴权服务,业务代码一行不用改:
# 在 http_filters 中插入鉴权过滤器(加在 router 之前)
http_filters:
- name: envoy.filters.http.ext_authz
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz
grpc_service:
envoy_grpc:
cluster_name: auth_cluster
timeout: 0.5s
- name: envoy.filters.http.router
代理架构的代价与取舍
代理不是免费的午餐,引入前要算清楚几笔账:
延迟增加。每多一层代理就多一次网络跳转,Sidecar 模式下本地调用额外增加约 1-2ms。对延迟敏感的场景(高频交易、实时游戏)要评估是否可接受。
运维复杂度上升。集中式网关要管高可用和容量规划;Sidecar 模式下代理数量等于服务实例数,配置变更的滚动生效需要自动化支撑。Istio 的控制平面正是为此而生——用 Pilot 统一下发配置,避免手动管理数百份 Envoy YAML。
调试链路变长。请求从 A → Proxy → Proxy → B,排查问题时需要穿过代理层查看日志和指标。好在代理本身是可观测性的天然采集点——Envoy 暴露的 /stats 端点和访问日志,反而让全链路追踪比裸调用更容易。
功能边界。代理适合处理与通信相关的横切关注点,不适合承载业务逻辑。如果代理里开始写条件分支做订单金额校验,那就是在把业务塞回基础设施,方向反了。
落地前的检查清单
决定引入代理架构之前,逐项确认:
- ✅ 是否有三个以上服务存在重复的鉴权/限流/熔断/日志代码?——这是代理最直接的收益点
- ✅ 延迟预算是否允许额外 1-2ms 跳转?——不允许的话考虑集中式网关(跳转少一次)或绕过代理的直连通道
- ✅ 配置管理是否有自动化方案?——手动维护几十份代理配置会很快失控
- ✅ 团队是否具备代理运维能力?——Envoy/Nginx 的调优、故障排查需要专门知识
- ✅ 是否明确了代理与业务逻辑的边界?——代理只管通信质量和安全,不碰业务规则
代理架构的本质是职责分离:让业务开发者专注领域逻辑,让基础设施团队统一管控通信质量。它不是万能解,但在服务数量超过一定规模、横切代码开始到处复制的时候,是把系统从混乱拉回秩序的有效手段。