我们的系统引入了API网关,用了一个月之后,发现了不少问题。本文记录了使用网关过程中遇到的各种坑,包括性能问题、配置复杂、调试困难、安全风险、监控不足等。每个问题都有具体的现象、原因分析和解决方案。如果你在考虑引入API网关,或者正在使用网关,希望这篇文章能帮你提前避坑。

一、为什么引入网关

先说说我们为什么引入API网关。

我们的系统是微服务架构,有十几个服务。之前前端直接调用各个微服务,带来了很多问题:前端要维护多个服务的地址,跨域问题麻烦,每个服务都要自己做鉴权和限流,接口协议不统一。

为了解决这些问题,我们决定引入API网关。网关作为系统的统一入口,负责路由转发、鉴权、限流、日志、协议转换等功能。这样前端只需要和网关交互,后端的服务也可以专注于业务逻辑。

我们选了一款开源的API网关,功能比较丰富,社区也比较活跃。部署上线之后,刚开始用着还不错,路由转发、鉴权、限流这些基本功能都正常。

但是用了一个月之后,各种问题开始暴露出来。有些是网关本身的问题,有些是我们使用不当的问题,还有一些是架构层面的问题。下面详细说说。

二、问题1:性能瓶颈

第一个问题是性能瓶颈。

现象

上线初期,流量不大,网关的性能还可以。但是随着业务增长,QPS上来之后,网关的延迟明显增加。尤其是在高峰期,网关的P99延迟达到了几百毫秒,而后端服务的延迟只有几十毫秒。也就是说,大部分延迟都消耗在了网关上。

而且网关的CPU使用率很高,经常达到80%以上,内存也涨得很快。有一次流量突增,网关直接OOM了,导致整个系统不可用。

原因分析

经过分析,我们发现性能瓶颈主要来自几个方面:

  1. 插件太多:我们在网关上配置了很多插件,鉴权、限流、日志、监控、转换、缓存等,每个请求都要经过十几个插件的处理,每个插件都有开销。
  2. 同步阻塞:这款网关的部分插件是同步阻塞的,比如调用远程鉴权服务的时候,会阻塞请求线程,导致线程被占满。
  3. 配置热更新:网关支持配置热更新,但是每次更新配置都会重新加载所有路由和插件,期间会有短暂的卡顿。
  4. 日志打印过多:我们为了调试,开了很详细的日志,每个请求都打印大量日志,IO开销很大。

解决方案

针对这些问题,我们做了以下优化:

  1. 精简插件:去掉了不必要的插件,只保留核心功能。一些非核心的功能移到了后端服务处理。
  2. 本地缓存:把鉴权信息、路由配置等缓存在网关本地,减少远程调用。
  3. 异步处理:把日志、监控等非核心操作改成异步处理,不阻塞请求线程。
  4. 调整日志级别:生产环境只打印必要的日志,详细日志只在调试时开启。
  5. 水平扩展:网关是无状态的,可以水平扩展。我们增加了网关实例,用负载均衡分摊流量。

优化之后,网关的延迟降下来了,CPU使用率也正常了。

三、问题2:配置复杂且容易出错

第二个问题是配置太复杂,而且容易出错。

现象

网关的配置项非常多,路由、插件、限流规则、鉴权策略等,每一项都有很多参数。我们的系统有十几个服务,每个服务有十几个接口,配置下来有几百条规则。

这些配置都是用YAML或者JSON写的,没有图形化界面(或者图形化界面不好用)。配置多了之后,管理起来非常混乱,经常出现配置错误。

有一次,一个同事修改限流规则的时候,把一个接口的限流阈值改错了,导致那个接口被大量限流,用户投诉很多。还有一次,路由配置写错了,把A服务的请求转发到了B服务,导致数据错乱。

原因分析

  1. 配置格式不友好:YAML格式对缩进敏感,很容易因为缩进错误导致配置失效。
  2. 缺少校验:网关的配置校验不够严格,很多错误要到运行时才发现。
  3. 没有版本管理:配置直接在线上修改,没有版本控制,出错了不好回滚。
  4. 配置分散:有的配置在配置文件里,有的在数据库里,有的在管理界面上,分散在多个地方。

解决方案

  1. 引入配置中心:把网关配置统一放到配置中心管理,支持版本控制和回滚。
  2. 增加配置校验:在配置发布前做校验,检查格式、引用、冲突等问题。
  3. 编写配置模板:为常见的场景编写配置模板,减少手写配置的错误。
  4. 灰度发布:配置变更先在灰度环境验证,确认没问题再全量发布。
  5. 配置审查:重要的配置变更需要两人审查,避免单人操作失误。

四、问题3:调试困难

第三个问题是调试困难。

现象

网关出问题的时候,排查起来非常麻烦。一个请求经过网关,要经过路由匹配、鉴权、限流、转发、响应处理等多个环节,任何一个环节出问题都可能导致请求失败。

但是网关的日志不够详细,出了问题不知道是哪个环节出的错。而且网关和后端服务的日志是分开的,要把一个请求在网关和后端的日志串联起来,需要手动查,非常耗时。

有一次,一个用户反馈某个接口偶发失败。我们查了网关日志,发现请求转发了;查了后端日志,发现请求没收到。中间到底发生了什么,查了半天才发现是网关的超时设置太短,后端还没处理完,网关就超时断开了。

原因分析

  1. 日志不完整:网关的日志只记录了部分信息,缺少请求的完整链路。
  2. 缺少链路追踪:网关没有集成链路追踪,无法和后端服务的日志串联。
  3. 调试模式不友好:网关的调试模式需要改配置、重启,不能动态开启。
  4. 错误信息不明确:网关返回的错误信息太笼统,不知道具体是哪里出的问题。

解决方案

  1. 集成链路追踪:在网关上集成了链路追踪(比如SkyWalking、Jaeger),每个请求生成唯一的traceId,贯穿网关和后端服务。
  2. 增强日志:在日志中增加请求ID、路由信息、插件执行情况、耗时等详细信息。
  3. 动态调试:支持动态开启某个请求或者某个接口的详细日志,不需要重启网关。
  4. 完善错误信息:网关返回的错误信息中包含具体的错误原因和建议,方便排查。

五、问题4:安全风险

第四个问题是安全风险。

现象

网关作为系统的统一入口,是攻击的重点目标。上线之后,我们遇到了几次安全问题。

有一次,有人通过网关的一个配置漏洞,绕过了鉴权,直接访问了后端的内部接口。还有一次,网关被大量恶意请求攻击,导致正常用户的请求被限流。

另外,网关本身也有一些安全漏洞,比如某些版本有已知的CVE漏洞,如果不及时升级,可能被利用。

原因分析

  1. 鉴权配置不严谨:有些接口的鉴权规则配置有误,导致可以被绕过。
  2. 缺少WAF功能:网关本身没有Web应用防火墙的功能,不能有效防御SQL注入、XSS等攻击。
  3. 限流粒度不够:限流是基于IP或者接口的,不能有效识别和拦截恶意请求。
  4. 版本升级不及时:网关的版本更新不及时,已知的安全漏洞没有修复。

解决方案

  1. 安全审计:定期审计网关的安全配置,检查鉴权规则、路由配置、限流策略等。
  2. 接入WAF:在网关前面加了一层WAF,防御常见的Web攻击。
  3. 增强限流:增加了基于用户、设备、行为的更精细的限流策略。
  4. 及时升级:关注网关的安全公告,及时升级到安全版本。
  5. 最小权限:网关的管理后台设置严格的权限控制,避免未授权访问。

六、问题5:监控和告警不足

第五个问题是监控和告警不足。

现象

刚上线的时候,网关的监控很简单,只有CPU、内存、QPS这些基础指标。有一次网关的某个插件出了问题,导致大量请求失败,但是我们没有及时收到告警,等用户反馈了才知道。

还有一次,网关的磁盘满了,因为日志没有轮转,把磁盘占满了,导致网关无法写入日志,请求全部失败。

原因分析

  1. 监控指标不全:只监控了系统指标,没有监控业务指标(比如错误率、延迟、插件执行情况)。
  2. 告警阈值不合理:有些指标没有设置告警,有些告警阈值设置得太宽松。
  3. 缺少日志监控:没有监控日志的大小和错误日志的数量。
  4. 没有链路监控:不能从整体上监控请求的链路状态。

解决方案

  1. 完善监控指标:增加了错误率、延迟分布、插件耗时、路由命中率等业务指标。
  2. 合理设置告警:为每个关键指标设置了合理的告警阈值,并且分级告警。
  3. 日志监控:监控日志文件的大小和增长速度,自动轮转和清理旧日志。
  4. 链路监控:通过链路追踪系统,监控整个请求链路的健康状态。
  5. 大盘展示:做了一个网关监控大盘,实时展示网关的运行状态,一目了然。

七、问题6:服务依赖和耦合

第六个问题是服务依赖和耦合。

现象

网关本来应该是薄的,只做转发和通用功能。但是用着用着,越来越多的业务逻辑被加到了网关上。

比如,我们在网关上做了用户信息的组装、接口参数的转换、甚至一些业务规则的判断。这样网关就变得越来越重,和业务服务的耦合越来越深。

有一次,后端服务改了一个接口的参数格式,因为网关里有对应的转换逻辑,也要跟着改。而且网关的发布流程比后端服务复杂,导致一个简单的参数变更,要等网关发布才能生效。

原因分析

  1. 图方便:有些功能在网关上做比较方便,就直接加在网关上了,没有考虑长期维护。
  2. 职责不清:网关和后端服务的职责边界没有明确,导致功能越界。
  3. 缺少规范:没有制定网关的使用规范,什么功能该放在网关,什么功能该放在后端,没有明确的规定。

解决方案

  1. 明确职责:制定了网关使用规范,明确网关只做通用的、与业务无关的功能(路由、鉴权、限流、日志等),业务逻辑一律放在后端服务。
  2. 清理网关:把网关上的业务逻辑逐步迁移到后端服务,让网关回归"薄"的本质。
  3. 代码审查:网关的变更需要严格审查,防止业务逻辑被加进来。
  4. 独立发布:网关和后端服务独立发布,互不影响。

八、总结和建议

用了一个月网关,踩了不少坑,也总结了一些经验。

网关的价值

虽然有这么多问题,但是网关的价值还是很大的。它统一了系统入口,简化了前端调用,集中处理了鉴权、限流、日志等通用功能,让后端服务更专注于业务。这些好处是实实在在的。

使用建议

如果你在考虑引入API网关,这里有一些建议:

  1. 选型要谨慎:根据自己的需求选择合适的网关,不要盲目追求功能多。性能、稳定性、社区活跃度都是重要的考量因素。
  2. 从简单开始:刚开始不要配置太多插件和功能,先把核心的路由和鉴权跑通,再逐步增加功能。
  3. 做好监控:上线之前就要把监控和告警做好,不要等出了问题才补。
  4. 保持网关薄:不要把业务逻辑加到网关上,网关只做通用功能。
  5. 配置管理:用配置中心管理网关配置,做好版本控制和审查。
  6. 性能测试:上线前做充分的性能测试,找到网关的性能瓶颈和极限。
  7. 安全第一:网关是系统的入口,安全非常重要,做好鉴权、限流、WAF等安全防护。

什么情况下不需要网关

不是所有系统都需要网关。如果你的系统只有一两个服务,或者流量很小,直接用Nginx做反向代理就够了,不需要引入重量级的API网关。网关本身也有运维成本和性能开销,要根据实际情况来决定。

九、写在最后

API网关是微服务架构中的重要组件,用好了能大大提升系统的可维护性和安全性。但是网关不是银弹,它也有自己的问题和局限性。

我们用了一个月,踩了不少坑,但是也通过不断优化,让网关稳定地运行了下来。这些问题和解决方案,希望能给正在使用或者准备使用网关的同学一些参考。

技术选型没有最好的,只有最合适的。在引入任何新技术之前,都要充分评估它的优缺点,以及自己团队的维护能力。不要因为别人都在用就跟风,也不要因为有坑就完全否定。

最后用一句话结束本文:"网关是入口,也是瓶颈。用好了是利器,用不好是累赘。"愿每一个团队都能根据自己的实际情况,做出最合适的架构选择。