一般来说,网关分为外网网关和内网网关。外网网关主要负责做限流、入侵预防、请求转发等工作,常见方式是使用 Nginx + Lua 做类似的工作;而最近几年,内网网关发展出现了各种定制功能的网关,比如 ServiceMesh、SideCar 等方式,以及类似 Kong、Nginx Unit 等,它们的用途虽然有差异,但是主要功能还是做负载均衡、流量管理调度和入侵预防这些工作。

外网网关功能

爬虫嗅探

非法引用:

  • 大量引用我们的网络资源,可以用检测请求 refer 方式来预防,如果 refer 不是本站域名就拒绝用户请求。

机器人抓取:

  • 划定范围:匿名请求,请求频率过高的 IP 会被筛选关注;登陆用户请求,记录单个用户的请求次数及频率,超过一定程度就拒绝请求,同时将用户列入怀疑名单,后续进行进一步确认。
  • 想要确认怀疑名单中用户的行为:通过网关对特定用户或 IP 动态注入 JS 嗅探代码,这个代码会在 Cookie 及 LocalStorage 内写入特殊密文。前端 JS 代码检测到密文后,就会进入反机器人模式。反机器人模式可以识别客户端是否有鼠标移动及点击动作,以此判断用户是否为机器人。不过这种设计有一个缺点——对 SEO 很不友好,各大搜索引擎的机器人都会被拒绝。可以考虑用白名单方式避免机器人被阻拦,具体会根据机器人的 UserAgent 放行各大引擎的机器人,并定期人工审核确认搜索引擎机器人的 IP。
  • 对于一些核心重要的接口,我们可以增加“必须增加带时间的签名,方可请求,否则拒绝服务”这样的规则,来避免一些机器人抓取。

网关鉴权与用户校验

用户校验有两种方式,一种是用户中心 SDK+JWT 解码,一种是请求用户中心 API 进行鉴权。
前者会因为 SDK 版本升级等问题不易维护,后者可能会遇到重复请求问题。
将用户登陆鉴权放在网关去做,就可以缓解业务服务处理用户信息的负担。
除了常见的登陆鉴权外,我们可以对一些域名开启 RBAC 服务,根据不同业务的需要定制不同的 RBAC、ABAC 服务,并且通过网关对不同的用户开启不同的权限以及灰度测试等功能。

内网网关功能

内网网关可以提供失败重试服务和平滑重启机制。
平滑重启:在我们的服务升级时,可以不让服务进程收到 kill 信号后直接退出,而是制作平滑重启功能,即先让服务停止接收新的请求,等待之前的请求处理完成,如果等待超过 10 秒则直接退出。

内外网关综合应用

服务接口缓存

首先来看网关接口缓存功能,也就是利用网关实现一些接口返回内容的缓存,适合用在服务降级场景,用它短暂地缓解用户流量的冲击,或者用于降低内网流量的冲击。
当用户请求服务端时,被缓存的 API 如果之前已经被请求过,并且缓存还没有过期的话,就会直接返回缓存内容给客户端。这个方式能大大降低后端的数据服务压力。这个方式是牺牲了数据的强一致性才实现的。另外,这个方式对缓存能力的性能要求比较高,必须保证网关缓存可以扛得住外网流量的 QPS。
如果想预防穿透流量过多,也可以通过脚本定期刷新缓存数据,网关查到相关缓存就直接返回,如果没有命中,才会将真正请求到服务器后端服务上并缓存结果。
23网关编程:如何通过用户网关和缓存降低研发成本?.png
当然这种缓存的数据长度建议不超过 5KB(10w QPS X 5KB = 488MB/s),因为数据太长,会拖慢我们的缓存服务响应速度。

服务监控

大部分系统都是通过网关的日志做监控的。我们可以通过网关访问日志中的 Http Code 来判断业务是否正常。配合不同请求的耗时信息,就能完成简单的系统监控功能。

总结

23网关编程:如何通过用户网关和缓存降低研发成本?-1.png

思考题

为什么内网都在用网关或实现服务发现功能,而不用内网 DNS 服务来实现这一功能呢?
DNS 记录在 TTL 失效前无法生效更新,一般情况下服务器会配置 DNS 缓存,本地缓存+内网 DNS 增加了记录生效时间的不一致,还需要确保本地 DNS 换成和内网 DNS 服务保持一致,增加了运维难度。如果使用网关实现服务发现,新服务启动后在网关注册一下,更新后再重新注册,只要客户端定时或者实时监听网关中这个服务的注册记录就可以及时发现服务注册变更情况,简化了运维难度,提升了运维效率。