互联网开放平台的高可用架构
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
互联网开放平台的高可用架构
京麦是京东商家的多端开放式工作平台,是京东十万商家唯一的店铺运营管理平台,为京东商家提供在移动和桌面端的操作业务,京麦本身是一个开放的端体系架构,由京东官方和ISV 为商家提供多样的应用服务。
京麦开发平台是京东系统与外部系统通讯的重要平台,技术架构从早期的单一Nginx+Tomcat 部署,到现在的单一职责,独立部署,去中心化,以及自主研发了JSF/HTTP 等多种协议下的API 网关、TCP 消息推送、APNs 推送、降级、限流等技术。
京麦开放平台每天承载海量的API 调用、消息推送,经历了4 年京东618 的流量洗礼。本文将为您揭开京麦开放平台高性能API 网关、高可靠的消息服务的技术内幕。
高性能API 网关
京东内部的数据分布在各个独立的业务系统中,包括订单中心、商品中心、商家中心等,各个独立系统间通过JSF(Jingdong Service Framework)进行数据交换。而API 网关基于OAuth2 协议提供,ISV 调用是通过HTTP 的JSON 协议。
如何将这些内部数据安全可控地开放给外部ISV 进行服务调用,以及如何快速地进行API 接入实现数据报文转化,在这个背景下API 网关诞生。
API 网关在架构设计上采用了多层接口,到达网关的请求首先由网关接入层拦截处理,在接入层进行两个主要环节的处理:
1. 网关防御校验:这里包含降级和限流,以及多级缓存等,进行数据正确性校验;
2. 网关接入分发:网关分发会根据网关注册中心的数据进行协议解析,之后动态构建调用实例,完成服务泛化调用。
API 网关是为了满足618 高并发请求下的应用场景,网关在服务调度、身份授权、报文转换、负载与缓存、监控与日志等关键点上进行了针对性的架构优化。
API 元数据统一配置
API 的调用依赖对元数据获取,比如API 的字段信息、流控信息、APP 密钥、IP 白名单等、权限配置等。在618 场景下,元数据获取性能是API 网关的关键点。基于DB 元数据读取是不可取的,即使对DB 做分库分表处理也不行,因为DB 就不是用来抗量的。
其次,要考虑到元数据的更新问题,定时的轮训更新会产生极大延迟性,而且空轮训也是对系统资源的极大浪费,采用MQ 广播通知不失为一种解决办法,但MQ 仅仅解决数据同步的问题,数据缓存在集群里服务如何保证数据一致性和数据容灾,又极大的增加了系统复杂度。
所以综合考虑服务器性能和网络IO 等因素,在API 元数据读取采用基于ZooKeeper 的统一配置,并自研实现多级缓存容灾架构方案,从ZooKeeper、内存和本地文件等进行多级缓存,同时支持数据变更时即时同步,以及系统宕机网络异常等情况下的数据自动容灾等策略。
以读为例,网关首先从内存中读取配置,如无数据,从ZooKeeper 读取,读取后同步到内存,并异步保存本次快照。如果ZooKeeper 数据变更,通过监听ZooKeeper 的DataChangeWatcher 变更同步数据。如果ZooKeeper 宕机,重启服务器,系统还可以通过本地快照恢复最近一次的元数据配置。
TCP 全双工的长链接会话通道
API HTTP 网关通过接口提供服务调用获取请求数据的,而搭建客户端与服务平台的TCP 网关的双向通道,以保持客户端与服务平台的会话状态,则可以在HTTP 网关基础上提供更多、更灵活的技术实现和业务实现。
在业务服务调用上通过HTTP 网关,在平台服务调用上则通过TCP 网关,实现平台与业务解耦,并且平台采用TCP 通道还可以增加对平台的控制力,在此背景下诞生了TCP 网关。
TCP 网关采用长连接通道,实现全双工会话。TCP 网关采用Netty 作为TCP 容器,在ChannelPipe 中加载自定义ChannelHandler,构建Container 容器,将每个TCP Connection 封装到一个Session 会话中,保存在Container 容器中,由Container 容器构建Session 会话层提供逻辑层请求调用。
自研构建Session 会话层是因为HTTP 属于OSI 的应用层,而TCP 属于OSI 的传输层,面向连接的编程极大的增加程序复杂度,所以将Connection 封装在每一个Session 会话里,再以微服务的方式提供服务调用,极大的精简了TCP 编程。
断线重连
客户端与服务端通过TCP 长连接进行通信,但在中国复杂的网络环境下,移动客户端可能由于网络抖动、弱网络情况下,遭遇非正常网络闪断,如何处理断开后的断线重连,保证客户端与服务端的通讯稳定呢?
客户端每通过TCP 与服务端进行一次建连,都会在服务容器里创建一个Session 会话,该会话保存Connection 的句柄,对应Netty 的一个Channel 通道。建连成功后,通过定时的心跳保持Channel 属于Active 活跃。但客户端进入弱网络环境下,客户端可能已经掉线,但并未向服务端主动
发送关闭Channel 请求,而服务端仍认为该Channel 仍存活。直到在由服务端的会话存活检测机制检测到Channel 已经InActive,才会由服务端销毁该Channel。
服务端的会话存活检测是5 分钟一次,所以存在客户端掉线后,在5 分钟内又重新建连,而这时服务端的建连逻辑,不是重新创建一个Session,而是去寻找上一次的Session,并更新标识存活。具体的实现是在每次建连的Channel 里存入SessionId,当网络闪断后,判断Channel 是否存在Session,之所以实现是得益于Netty 的ChannelHandlerContext,可以存储一个自定义属性到Channel 的上下文中。
当然,TCP 网关一定是集群,所以,断线重连也是极有可能请求到不同的服务器上,而这种情况按照新Connection 创建的Session 处理,只有出现重连到同一服务器时,才需要考虑上述的处理逻辑。
Protobuf 数据交换格式
HTTP 网关基于JSON 进行数据传输,JSON 是key-value 的键值对通信协议,所以生成报文会很大,所以影响传输性能。考虑到报文传输大小,在TCP 网关中则通过Protobuf 定义通信协议,提升数据传输效率。