京东数据智能部负责维护数据资产和对外提供数据服务,很多业务方要求我们尽快地提供开放的数据 API 供其使用,但开发一个 API 的平均周期在两周左右,遇到 618 大促时还要提供 80 个接口。在这样的情况下,数据开发工程师提出诉求,是否能只贴 SQL 就可以生成开放数据的 API 接口,同时又能保证接口的性能、支持传入动态的 SQL 参数。基于该诉求而开发了一套解决方案的框架:EZD 框架。
上图为解决方案的示意图,这是相对传统固定的 API 开发模式。最下面的JavaScript 和 Java 是 API 的消费方,上面为 API 的提供方,右边是所有 API 需要用到的数据源。将数据源通过 JDBC 从存储系统中读取出来,然后通过 HTTP 协议或者 RPC 协议开放给业务方使用。基于此套框架,数据开发工程师只需要填写 SQL 后点击发布,系统就会根据 SQL 的内容,通过热部署的方式生成 API 接口,达到一键发布的敏捷交付目标。2. 接口性能
平台第一个版本的性能存在一些瓶颈,如上图最上面一行为数据库查找 API 的各个环节耗时。系统需要先去查找 SQL 的定义,如果 SQL 是存放在数据库里,那么每一个请求进来时,系统都要先去寻址找到 SQL 后再去数据库里查询,这样的效率并不高。后来把 SQL 都缓存到各个节点组成一张内存路由表来去查找 API 的定义,查找的过程就变得非常地快。后面连接池更换成性能更加高的 Hikari 连接池。最后经过一系列的调优,平台的耗时占比从优化前的 97% 下降到优化后的 1%。3. 接口的灵活性
好多 API 希望能传入参数,比如查询某条 SQL 时传入部门的 ID,再比如使用 IN 关键字时能否传入一个集合。这些又怎么来处理呢?如上图右小角所示,通过使用冒号的语法将 API 传入的参数注入到 SQL 语句中。
一些查询条件是动态变化的,比如 WHERE 关键词后边到底是使用哪个条件?A、B、C 3 个条件构成的排列组合非常多,从而导致接口的数量较多,能否使用某种方式减少接口的数量?系统使用 SQL 与 FreeMarker 模板结合的方式来解决上述难题,从而减少 API 的数量,比如上图最左边使用 IF 模块判断,只有 IF 语句为 true 时系统才会使用其内部嵌套的 AND 语句。基于这种方法,所有的查询条件都可以是动态,同时它还支持 Switch Case、遍历集合等操作。通过这种形式,可以将原来的 80 个接口减少到 5 个接口。
02
扛鼎:数据服务化 – 从 1 到 10京东 618 大促期间对外公布的成交额、热门品类、公关媒体的数据,各平台的实时销量,PV、UV、优惠券的发放情况都需要有看板去支撑,看板上特别多的指标数据都是通过上述提到的数据 API 展示出来的。系统是如何在短期内迅速地支持这么多的指标呢?比如京东的年货节,需要在两周内完成几百个指标的开发。另外,一些响应比较慢的存储,能不能一键添加缓存?如何充分利用存量的 API?接口之间会形成一个特别复杂的请求链路,怎么来调试这个复杂的链路呢?一些业务方有自己的 elasticsearch、Redis、HBase,这些存储怎么去开放这个 API 呢?