日200亿次调用,喜马拉雅网关的架构设计( 三 )

上述提到的所有功能都是对流量进行管理 , 我们每个功能都作为一个 filter , 处理失败都不会影响转发流程 , 而且所有这些规则的元数据在网关启动时就会全部初始化好 。
在执行过程中 , 不会进行 IO 操作 , 目前有些设计会对多个 filter 进行并发执行 , 由于我们的操作都是在内存中进行 , 开销并不大 , 所以我们目前并未支持并发执行 。
另外 , 规则可能会发生变化 , 所有需要进行规则的动态刷新 。
我们在修改规则时 , 会通知网关服务 , 进行实时刷新 , 我们对内部自己的这种元数据更新请求 , 通过独立的线程处理 , 防止 IO 操作时影响业务线程 。
2.3 服务调用层服务调用对于代理网关服务非常关键 , 这个环节 , 性能必须很高:必须采用异步方式 , 
我们利用 Netty 实现了这一目标 , 同时也充分利用了 Netty 提供的连接池 , 实现了获取和释放的无锁操作 。
2.3.1 异步 Push在发起服务调用后 , 网关允许工作线程继续处理其他请求 , 而无需等待服务端返回 。
在这个设计中 , 我们为每个请求创建一个上下文 , 发送请求后 , 将该请求的 context 绑定到相应的连接上 , 当 Netty 收到服务端响应时 , 会在连接上执行 read 操作 。
解码完成后 , 再从连接上获取相应的 context , 通过 context 可以获取到接入端的 session 。
这样 , push 通过 session 将响应写回客户端 , 这个设计基于 HTTP 连接的独占性 , 即连接和请求上下文绑定 。
2.3.2 连接池连接池的原理如下图:

日200亿次调用,喜马拉雅网关的架构设计

文章插图
注意:请点击图像以查看清晰的视图!
服务调用层除了异步发起远程调用外 , 还需要管理后端服务的连接 。
HTTP 与 RPC 不同 , HTTP 连接是独占的 , 所以在释放连接时需要特别小心 , 必须等待服务端响应完成后才能释放 , 此外 , 连接关闭的处理也需要谨慎 。
总结如下几点:
  • 1)Connection:close;
  • 2)空闲超时 , 关闭连接;
  • 3)读超时关闭连接;
  • 4)写超时 , 关闭连接;
  • 5)Fin、Reset 。
上面几种需要关闭连接的场景 , 下面主要说下 Connection:close 和空闲写超时两种 , 其他情况如读超时、连接空闲超时、收到 fin、reset 码等都比较常见 。
2.3.3 Connection:close后端服务采用的是 Tomcat , 它对连接的重用次数有规定 , 默认为 100 次 。
当达到 100 次限制时 , Tomcat 会在响应头中添加 Connection:close , 要求客户端关闭该连接 , 否则再次使用该连接发送请求会出现 400 错误 。
还有就是如果前端的请求带了 


推荐阅读