http://www.infoq.com/cn/articles/suning-11-11-api-gateway?utm_campaign=infoq_content&utm_source=infoq&utm_medium=feed&utm_term=global
2012年,在开放云融推动各产业全面发展的大背景下,苏宁API对外开放。基于苏宁各内部业务系统的资源,开放丰富的API服务,提供给苏宁商家、供应商、售后服务商、物流公司、软件服务商等合作伙伴所需的数据和信息。实现外部系统与苏宁的完美对接,使业务的处理更加高效、便捷。
通过阅读该文章你会了解到如下信息:
- 一切皆基于标准
- 系统重构详解
- 高可用设计
- 监控之道
- 应对O2O购物节
到现在为止,苏宁已开放了平台业务、自营业务、自采业务、O2O业务、政企业务、特卖业务、4PS业务等几百个API接口,每天承载海量的API接口调用。
另外,由InfoQ举办的ArchSummit全球架构师峰会即将于12月8-11日北京举行,大会与阿里巴巴合作策划了双11架构专场,并邀请了顶级技术专家担任出品人,设置了“新一代DevOps”、“人工智能与业务应用”、“架构升级与优化”等17个热门话题,目前大会日程已出,欢迎前来讨论交流。
一、一切皆基于标准
俗话说“无标准不平台”,苏宁API设计之初,没认识到标准的重要性,遇到过很多问题,走过很多弯路,接下来细说下苏宁API的标准化设计的过程。
1. 从接口名开始
谈起API接口,首先会想到接口名(接口英文名)。
先来看一组接口名:
suning.order.get
suning.selfmarket.order1.query
suning.custom.book.item.query
suning.retuenBadArticleHandleResults.add
suning.shoppingmallsalesdata.saveandupdate
以上接口名有如下问题:
- 长度不一。
- 风格不一致。
而一个标准的接口名应该有如下特征:
- 风格统一(都为英文小写)
- 模式固定(xx.xx.xx.xx)
- 简洁明了
- 有扩展性
- 分类与分层
举例:suning.custom.order.get
格式:suning.业务分类.模块简称.操作符
2. 文档规范化
用户通过阅读API文档来使用API接口。一个规范的API文档有助于用户理解API的用途,掌握API的使用。
API文档组成
API文档详情
3. 协议主流化
苏宁API主要是基于Http(s)+OAuth2.0协议实现的。可以使用xml或者json格式进行报文传输。并提供主流(Java、.Net、PHP、Python)四种语言SDK方便用户使用。
API接口为一个全局统一的入口:
https://open.suning.com/api/http/sopRequest
4. 服务契约固定化
这里服务契约是指苏宁API系统与苏宁内部系统之间的服务契约。苏宁API承接着苏宁内部多方系统。如果不固定服务契约,苏宁API就无法做到标准化,这是一个API标准化的一个前提。有了服务契约的固定,才能实现动态发布API,缩短API的研发周期。
5. 异常码标准化
什么是异常码
即调用API接口异常场景下返回的错误码。苏宁的API接口返回异常码的同时也会返回中文详细描述,以增强异常码的可读性。异常码通常表示某种异常场景,具有唯一指向性。
异常码的设计问题
异常码常见的问题包括:无统一风格、无分类、无唯一性、难以理解等。基于以上问题,苏宁的API网关在异常码方面进行一些标准化设计,使异常码变得有如下特征。
改进后的异常码特征
- 唯一性
- 风格一致
- 有层级有分类
- 可扩展
异常码的分类
异常码标准化带来的意义
- 异常码监控
每个异常码都代表不同的异常场景,异常也有主次之分,重要的异常场景可通过异常码配置监控。 - 接口告警
基于异常码监控,一个接口可配置多个异常码监控告警。 - 定位问题
异常码具有唯一指向性,能快速地位问题。 - 解决问题
在基于异常码具有唯一指向性的前提下,能快速解决问题。
6. API接口配置化
在以上标准化的基础上,为了缩短API接口上线周期,我们实现了API接口配置化,能支持自动发布API接口、动态修改配置项。具体界面如下图:
- 基本信息配置
- 外部请求API
- API请求内部
7. SDK自动化
当API接口发布上线后,会自动生成(Java、.Net、PHP、Python)四种语言的SDK,并执行自动化测试,测试通过后上传官网,供外部用户使用。
二、系统重构详解
随着API接口数量越来越多,一些问题逐渐暴露出来,下面详细介绍几个关键问题的重构详解。
1. 响应时间慢
系统上线之初,选用IBM的IHS和Websphere、DB2来部署API系统,系统架构如下:
这套架构的优点是简单,整个API运行在Servlet容器中,API全局入口是一个Spring MVC的Controller。缺点是API系统不是通过服务调用业务系统,而是自己要连接业务数据库,并处理业务逻辑。一个API接口对应一个API Service,实现了简单的流控、校验、权限认证、本地配置功能。随着时间变迁,API接口数量越来越多,API接口开发周期变长、响应时间逐渐变慢了。
2. 并发支持低
为了解决API接口响应时间慢的问题,对系统进行如下重构:
此时API系统架构变成Nginx+Wildfly(JBoss),整个API运行在Servlet容器中,API全局入口是一个Servlet;同时新增了流控、监控、调用器组件;API业务逻辑处理修改为通过Hessian方式调用业务系统;监控组件同步发送日志到kafka,Elasticsearch从kafka消费日志,建立索引。
经过上面系统重构后,系统运行一段时间,发现接口响应返回越来越慢,很多无效调用和攻击影响正常的请求,同时核心链路并发支持低,也是影响接口响应慢的原因。
3. 接口分流
为了解决无效调用、安全攻击、核心并发支持低导致API接口响应时间慢的问题,对系统进行如下重构:
此次系统重构主要是强化接入层的功能,在接入层实现了防攻击、基础校验、日志、降级、流控等功能,同时将核心服务权限认证进行平台化,增加核心链路的并发度和增强系统扩展性,将监控组件异步化。
运行一段时间后,又出现了一个现象,运行快的API接口会被运行慢的接口影响,也变得运行慢。
4. 核心组件重构
为了解决接口之间互相影响的问题,对系统进行如下重构:
在接入层进行接口分流,不同的接口请求到不同的后端服务,这样接口进行应用层的资源隔离;并对应用层进行重构,重写核心组件;整个应用层基于Netty提供API服务;IO线程负责连接的接收与建立;Work线程负责IO的读写;同时支持多组work线程池,用来隔离不同接口和业务直接的互相影响;服务调用组件修改为苏宁自研分布式服务框架(RSF),使用异步回调方式,提高系统的吞吐量,核心权限认证服务,也修改RSF调用方式,提高服务的性能,新增Zookeeper来提供配置管理,来实现分流的动态配置修改。
三、高可用设计
在系统重构过程中,除了提高系统的性能,系统的高可用设计也尤其重要。下面将详细介绍苏宁API的高可用设计包括哪些内容。
1. 安全保障
一次API接口请求链路如下,每个链接职责分离。
- CDN:能够实时地根据网络流量和各节点的连接、负载状况以及到用户的距离和响应时间等综合信息将用户的请求重新导向离用户最近的服务节点上
- 硬件防火墙:重点关照外联链路和外联VPN做了一些通用的防火墙策略
- 负载均衡:能支持域名为维度做并发控制,限制每秒的最大请求数
- WAF:基于Nginx+Lua实现,提供同样的安全攻击防护和域名维度、URL维度、IP+URL维度的准实时流量管控。
- Nginx+Lua,也是基于Nginx+Lua实现,提供API接口维度的安全攻击防护和多层级的流控策略,来保证系统的稳定性。
2. 流量管控
API系统流量管控,主要分为接入层和应用层流控。接入层主要是基于Nginx+Lua来实现的,应用层基于计数器和信号量等实现。具体信息如下:
3. 接口分流
接口分流基于Nginx+Lua实现,预先对每一个API接口进行逻辑执行区域的分类,不同的分类对应不同的后端服务,通过Zookeeper动态管理配置项,一个接口请求会找到对应upstream Server。
4. 服务降级
接口降级同样基于Nginx+Lua实现,Nginx共享内存中存放接口的降级信息,通过Zookeeper动态管理配置项,如果接口被降级就会直接返回异常码,否则接口就会执行接口分流逻辑,请求会找到对应upstream Server。
同时服务降级也支持多个层级,具体如下图:
四、监控之道
当API接口数量和调用量达到一定程度后,面临了如下问题:
- 日志监控
- 如何记录接口完整调用记录?
- 用什么存储接口调用记录?
- 如何准确查询接口调用记录?
- 查询日志能否准实时?
- 接口统计
- 如何实现接口调用统计?
- 是离线统计还是实时统计?
- 按照哪种维度进行统计?
- 如何存储统计数据?
- 如何展示统计数据?
1. 日志明细
第一版日志明细实现系统设计如下图:
上线后,由于Flume采集任务和Hadoop任务导致日志明细不能实时查看,整个日志延迟20分钟。基于上述原因对系统进行重构,结果如下:
去掉Flume采集任务和Hadoop,直接采用Elasticsearch消费kafka数据,实时建索引。
日志源和kafka、Elasticsearch都具备扩展性,满足性能要求。
2. 接口统计
依赖于苏宁数据大数据平台来完成接口的统计。
- 使用Hadoop进行离线统计,根据不同维度编写Hive语句转换为MapReduce任务进行计算,通过Sqoop将计算结果导入到MySQL数据库中。
- 使用Libra实时计算平台进行实时统计,根据不同维度编写epl语句转换为实时计算任务进行计算,计算结果发送到Kafka,应用监听Kafka消费实时计算结果,存储到Redis中,并设置数据过期时间。
Libra实时计算平台是苏宁在Storm的基础上二次开发封装的,通过编写EPL计算语句(EPL是esper中一种类似SQL的语言),转换为一个个计算规则,提供实时计算功能的平台,主要特点为配置简单能够实时计算需求的快速上线、支持分布式计算、支持动态扩容,以满足大数据量的计算需求。
3. 监控的意义
在没有监控之前,存在如下问题:
- 定位问题很困难
- 没有接口运行数据,无法优化接口性能
- 没有接口统计数据,无法考核服务质量
而有了监控之后:
- 方便定位问题
- 优化性能隐患
- 方便考核服务质量
- 方便实现业务扩展
4. 智能告警
苏宁有如下告警平台和告警机制,能够准确地通知开发及运维人员系统的异常状况,有助于快速定位问题和解决问题。
- ZABBIX监控系统。全方位监控操作系统、应用系统层面 (ZABBIX是一个基于WEB界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案)。主要监控项包括CPU、系统负载、内存、网卡流量、磁盘使用量、连接数、宕机检测等。告警方式为短信或者邮件。
- 穆加。苏宁智能告警平台,整合了ZABBIX监控系统、云迹服务端性能监控、Kafka后台管理系统、决策分析平台、机器学习平台、准实时计算平台监控来源,提供更细致化的、丰富的指标种类,提供豆芽(苏宁自研的实时通讯工具)通知、短信、邮件、语言等多种告警方式。
- 云迹异常监管系统。能针对某个系统的某种异常,在单位时间内异常量或环比增长量超过配置的阀值,则进行短信或者邮件告警。
以上都是苏宁系统提供的通用告警机制,接下来介绍苏宁API系统实现的告警机制:
- 提供了基于API接口维度的告警,调用时长、调用次数、失败次数、失败率等维度,在单位时间内超过配置的阀值,则进行短信或者邮件告警。
- 提供了基于API接口异常码维度的告警。在单位时间内异常量或环比增长量超过配置的阀值,则进行短信或者邮件告警。
五、苏宁API网关应对O2O购物节
从2012年开始,每年双十一苏宁都带给消费者一次次购物享受之旅。今年苏宁易购双十一的主题是“不止所见嗨购11天”,换句话说,这场狂欢盛宴将始于购物,但不止于购物,为消费者提供其他电商没法实现的“任性”。
O2O购物节是一次狂欢盛宴,对每一个苏宁人来说是一场必胜的战役,为了保证O2O购物节系统正常,需提前做好系统保障工作,正所谓不打无准备的战役。
O2O购物节中苏宁API网关提供哪些应用场景辅助商家、供应商、服务商进行商品交易?下面列举了主要的应用场景:
- 商品发布
- 获取苏宁采购目录
通过接口suning.custom.category.query获取categoryCode - 获取商品品牌信息
通过接口suning.custom.brand.query获取brandCode - 获取苏宁产品库信息
通过接口suning.custom.product.query获取苏宁产品信息 - 获取苏宁产品详情信息
调用接口suning.custom.productdetail.query - 商品内容维护
调用接口suning.custom.itemcontents.add - 获取商品参数模板
调用接口suning.custom.itemparameters.query - 产品申请
调用接口 suning.custom.item.add
- 获取苏宁采购目录
- 订单同步
- 获取三个月前的订单
调用接口suning.custom.historyorder.query批量获取订单(三个月前的历史订单) - 获取三个月内的订单
调用接口suning.custom.order.query批量获取订单(三个月内的订单)
调用接口suning.custom.ordercode.query批量获取订单号
调用接口suning.custom.order.get查询单笔订单 - 获取增量订单
调用接口suning.custom.ord.query根据订单修改时间批量查询订单信息
- 获取三个月前的订单
- 物流发货
- 苏宁物流或第三方物流配送
调用suning.custom.orderdelivery.add对订单进行发货。 - 商家自配送
调用suning.custom.orderselfdist.add对订单进行发货。
采用该接口发货时,需要填写商户自己执行配送的人员的姓名和手机号。
- 苏宁物流或第三方物流配送
战前
- 容量评估
根据O2O购物节订单预估量,对系统进行容量评估。分场景压测系统得到性能测试结果,再根据结果进行性能达标评估。不达标的系统需进行自动扩容,扩容后需对系统进行性能测试,检验系统容量是否达标。
- 性能测试
每次战前,各个系统都要提前对关键路径进行性能测试,找出性能瓶颈并优化。
- 预案梳理
梳理系统的紧急预案,在O2O购物节中异常事件发生时进行预案处理,如服务降级,关闭非核心功能,保证核心功能。
- 预案演练
根据O2O购物节中异常事件启动对应的紧急预案,看看是否能达到预期效果。
战时
- 集中值班
O2O购物节期间安排24小时集中值班,来监控系统运行情况,应对突发紧急问题,并解决问题。
- 系统监控
- 监控系统运行情况,各项指标(CPU、IO、内存、网卡流量等)
- 苏宁云迹链路监控大盘
- 预案执行
O2O购物节期间发生的异常事件,根据战前准备的预案执行,监控执行结果。并更新预案执行状态,好做后期恢复。
- 问题解决
O2O购物节期间发生的异常事件,会成立问题解决专项小组,严格跟进问题解决状态,直到问题解决才关闭。
战后
- 预案恢复
O2O购物节结束后,针对O2O购物节期间执行过的预案进行恢复,并监控系统运行状态。
- 问题总结
O2O购物节结束后,针对期间发生的问题进行总结和反思,制定方案解决问题。
- 性能优化
O2O购物节结束后,针对期间发生的性能问题进行系统重构和性能优化。
微信公众号: 架构师日常笔记 欢迎关注!