• 一、引言
  • 二、背景
  • 三、Linkis的设计初衷
  • 四、Linkis的技术架构
  • 五、Linkis业务架构
  • 六、Linkis处理流程
  • 七、Linkis如何保证高实时性?
  • 八、Linkis如何支撑高并发?
  • 九、Linkis如何保证用户级隔离度和调度时效性
  • 十、总结

    Linkis是微众银行开源的一款数据中间件,用于解决前台各种工具、应用,和后台各种计算存储引擎间的连接、访问和复用问题。

    一、引言

    Linkis Github repo: https://github.com/WeBankFinTech/Linkis

    Linkis,一个打通了多个计算存储引擎如Spark、TiSpark、Hive、Python和HBase等,对外提供统一REST/WebSocket/JDBC接口,提交执行SQL、Pyspark、HiveQL、Scala等脚本的数据中间件。

    Linkis基于微服务架构,提供了金融级多租户隔离、资源管控、权限隔离等企业级特性,支持统一变量、UDF、函数、用户资源文件管理,具备高并发、高性能、高可用的大数据作业/请求全生命周期管理能力。

    二、背景

    大数据技术的广泛应用,催生出层出不穷的上层应用和下层计算引擎。

    通过引入多个开源组件来实现业务需求,不断更新和丰富大数据平台架构,几乎是现阶段所有企业的通用做法。

    如下图所示,当我们的上层应用、工具系统,和底层的计算存储组件越来越多时,整个数据平台的情况就会变成如上图的网状结构。

    原大数据生态图


    不断引入新组件来实现业务需求,越来越多的痛点也随之产生:

    1. 业务需求变化多端,上层组件各具特色,用户使用起来割裂感强烈,学习成本高昂。

    2. 数据种类繁多,存储和计算非常复杂,一个组件一般只解决一个问题,开发人员必须具备完善的技术栈。

    3. 新组件的引入,在多租户隔离、用户资源管理、用户权限管理等无法兼容原有数据平台,自上而下的定制化开发,不仅工程浩大,而且重复造轮子。

    4. 上层应用直接对接底层计算存储引擎,一旦底层环境发生任何改变,都会直接影响业务产品的正常使用。

    三、Linkis的设计初衷

    如何提供统一的数据中间件,对接上层应用工具,屏蔽掉底层的各种调用和使用细节,真正做到让业务用户只需关注业务实现,就算底层平台机房扩建、整体搬迁都不受影响,是Linkis的设计初衷!

    Linkis解决方案

    四、Linkis的技术架构

    技术架构

    如上图所示,我们基于SpringCloud微服务技术,新建了多个微服务集群,来打造Linkis的中间件能力。

    每个微服务集群都承担系统的一部分功能职责,我们对其进行了如下明确的划分。如:

    • 统一作业执行服务:一个分布式的REST/WebSocket服务,用于接收上层系统提交的各种访问请求。

      目前支持的计算引擎有:Spark、Python、TiSpark、Hive和Shell等。

      支持的脚本语言有:SparkSQL、Spark Scala、Pyspark、R、Python、HQL和Shell等;

    • 资源管理服务: 支持实时管控每个系统和用户的资源使用情况,限制系统和用户的资源使用量和并发数,并提供实时的资源动态图表,方便查看和管理系统和用户的资源;

      目前已支持的资源类型:Yarn队列资源、服务器(CPU和内存)、用户并发个数等。

    • 统一存储服务:通用的IO架构,能快速对接各种存储系统,提供统一调用入口,支持所有常用格式数据,集成度高,简单易用;
    • 统一上下文服务:统一用户和系统的资源文件(用户脚本、JAR、ZIP、Properties等),用户、系统、计算引擎的参数和变量统一管理,一处设置,处处自动引用;
    • 物料库服务:系统和用户级物料管理,可分享和流转,支持全生命周期自动管理;
    • 元数据服务:实时的Hive库表结构和分区情况展示。

    依赖这些微服务集群的相互协作,我们改善了整个大数据平台对外服务的方式和流程。

    五、Linkis业务架构

    业务架构

    名词解释:

    1) Gateway网关:

    基于Spring Cloud Gateway进行了插件化功能增强,新增了前端Client与后台多WebSocket微服务1多N支持(详细架构实现,主要用于解析和路由转发用户的请求到指定微服务。

    2) 统一入口:

    统一入口是用户某一类引擎作业的Job生命周期管理者。

    从接收作业、作业提交给执行引擎、到作业执行信息反馈给用户,再到作业完成,Entrance管理了一个作业的全生命周期。

    3) 引擎管理器:

    引擎管理器负责管理引擎的全生命周期。

    负责向资源管理服务申请和锁定资源,并实例化新的引擎,也负责监控引擎的生命状态。

    4) 执行引擎:

    执行引擎是真正执行用户作业的微服务,它由引擎管理器启动。

    为了提升交互性能,执行引擎直接跟统一入口进行交互,实时推送执行的日志、进度、状态和结果集给统一入口。

    5) 资源管理服务

    实时管控每个系统和每个用户的资源使用情况,管理引擎管理器的资源使用和实际负载,限制系统和用户的资源使用量和并发数。

    6) Eureka

    Eureka是Netflix开发的服务发现框架,SpringCloud将它集成在其子项目spring-cloud-netflix中,以实现SpringCloud的服务发现功能。

    每个微服务都内置了Eureka Client,可以访问Eureka Server,实时获得服务发现的能力。

    六、Linkis处理流程

    Linkis如何处理上层系统提交的一条SparkSQL?

    流程时序图

    1. 上层系统的用户提交一个SQL,先经过Gateway,Gateway负责解析用户请求,并路由转发给合适的统一入口Entrance

    2. entrance会先寻找该系统的该用户是否存在可用的Spark引擎服务,如果存在,则直接将请求提交给Spark引擎服务

    3. 不存在可用Spark引擎服务,开始通过Eureka的服务注册发现功能,拿到所有的引擎管理器列表,通过请求RM实时获取引擎管理器的实际负载

    4. Entrance拿到负载最低的引擎管理器,开始要求引擎管理器启动一个Spark引擎服务

    5. 引擎管理器接收到请求,开始询问RM该系统下的该用户,是否可以启动新引擎

    6. 如果可以启动,则开始请求资源并锁定;否则返回启动失败的异常给到Entrance

    7. 锁定资源成功,开始启动新的spark引擎服务;启动成功后,将新Spark新引擎返回给Entrance

    8. Entrance拿到新引擎后,开始向新引擎请求执行SQL

    9. Spark新引擎接收SQL请求,开始向Yarn提交执行SQL,并实时推送日志、进度和状态给Entrance

    10. Entrance将获取的日志、进度和状态实时推送给Gateway

    11. Gateway回推日志、进度和状态给前端

    12. 一旦SQL执行成功,Engine主动将结果集推给Entrance,Entrance通知前端拿取结果。

      七、Linkis如何保证高实时性?

      众所周知,Spring Cloud集成了Feign来作为微服务之间的通信工具。

      基于Feign的微服务之间HTTP接口调用,只支持A微服务实例根据简单规则随机访问B微服务的某个实例。

      但Linkis的执行引擎,却可以直接主动推送日志、进度和状态给请求它的统一入口,Linkis是如何做到的?

      Linkis基于Feign实现了一套自己的底层RPC通信方案。

      Linkis RPC架构图

      如上图所示,我们在Feign的基础上,封装出了Sender和Receiver。

      Sender作为发送端直接可用,用户可以指定访问某个微服务实例,也可以随机访问,还支持广播。

      Receiver作为接收端,需要用户实现Receiver接口,用于处理真正的业务逻辑即可。

      Sender提供三种访问方式,如下:

    13. ask方法为同步请求响应方法,要求接收端必须同步返回响应;

    14. send方法为同步请求方法,只负责同步将请求发送给接收端,不要求接收端给出答复;

    15. deliver则为异步请求方法,只要发送端的进程不异常退出,在稍后会通过其它线程将请求发送给接收端。

    八、Linkis如何支撑高并发?

    Linkis设计了5大异步消息队列和线程池,Job每次占用线程不到1毫秒,保证每个统一入口可承接超1万+TPS常驻型Job请求。

    全异步调用线程池

    • 如何提高上层的请求吞吐能力?

      Entrance的WebSocket处理器,内置一个处理线程池和处理队列,接收Spring Cloud Gateway路由转发的上层请求。

    • 如何保证不同系统不同用户的执行请求,互相隔离?

      Entrance的Job调度池,每个系统的每个用户,都有一个专用线程,保证隔离度

    • 如何保证Job执行高效?

      Job执行池,只用于提交Job,一旦Job提交给了Engine端,则立马放入Job执行队列,保证每个Job占用执行池线程的时间不超过1毫秒。

      RPC请求接收池,用于接收和处理Engine端推来的日志、进度、状态和结果集,并实时更新Job的相关信息。

    • 如何实时将Job的日志、进度和状态推给上层系统?

      WebSocket发送池,专门用于处理Job的日志、进度和状态,将信息推给上层系统。

    九、Linkis如何保证用户级隔离度和调度时效性

    Linkis设计了Scheduler模块——可智能监控扩展的分组调度消费模块,用于实现Linkis的高并发能力。

    分组调度消费架构

    每个系统的每个用户,都会单独分组,来保证系统级和用户级的隔离度。

    每个消费器均有一个独立的监控线程,统计消费器中等待队列的长度、正在执行的事件数量、执行时间的增长比例等指标。

    消费器所对应的分组对象,会对这些指标设置阈值和告警比例,一旦某个指标超过阈值,或多个指标间的比例超过限定范围(比如监控到平均执行时间大于分发间隔参数,即认为超过阈值),监控线程就会立即对消费器进行相应的扩展。

    扩展时,会充分利用上述的调参过程,具有针对性的调大某个参数,其它参数会自动随之得到扩展。

    十、总结

    Linkis作为数据中间件,为实现对下层调用细节的屏蔽,做了许多的尝试和努力。

    比如:Linkis如何实现统一存储服务?Linkis如何统一UDF、函数和用户变量?

    由于篇幅所限,本文不再详细论述,如您感兴趣,欢迎您访问我们的开源Github Wiki:https://github.com/WeBankFinTech/Linkis/wiki。

    有没有一套真正基于开源,经过金融级生产环境和场景的自研打磨完善,再回到开源社区的数据中间件,让人能相对放心的拿去服务于生产,支持金融级业务,具备企业级特性保障?

    我们希望Linkis成为答案。

    同时,我们也期待更多的社区力量,一起推动Linkis的成长。