今天的文章来自李贝宁(Ben),SAP成都研究院的资深程序猿和架构师。
作为成都研究院里同时精通Java, JavaScript和ABAP这三门编程语言的数位同事之一,Ben曾经先后担任了成都CRM Fiori开发团队,S4CRM开发团队和尚未发布的某款云产品开发团队的架构师。
Ben在这三个团队的职责都是产品架构设计和部分功能代码的编写,以及组内其他同事的代码审查。
除了自身架构设计和编程相关的技能过硬之外,Ben在传业授道解惑方面也很有心得。Ben是SAP研究院内部的Agile Software Enginnering教练,也是SAP成都研究院若干内部培训课程的讲师。他的课程帮助了很多刚刚走出大学校园的年轻同事们从在学校书写玩具代码到走向真正的企业软件开发的专业之路。
每位同时精通数门风格截然不同的编程语言的开发人员,总有自己的一套心得和办法,把这些语言融为一体,为自己所用。那么Ben又是如何做到的呢?或许可以从Ben的业余爱好看出点端倪。Ben喜欢足球和围棋,并且水平在业余爱好者里不算太差。能同时驾驭这一动一静,一刚一柔,一阳一阴的两个爱好,除了Ben以外,我能想到的也就只有这几位高手了:
1. 人到中年,把降龙十八掌练到超过洪七公造诣的大侠郭靖。
岂知郭靖近二十年来勤练九阴真经,初时真力还不显露,数十招后,降龙十八掌的劲力忽强忽弱,忽吞忽吐,从至刚之中竟生出至柔的妙用,那已是洪七公当年所领悟不到的神功
2. 左手短刀,右手长鞭的峨眉美女掌门周芷若。
周芷若取出软鞭,右手一抖,鞭子登时卷成十多个大大小小的圈子,好看已极,左手翻处,青光闪动,露出了一柄短刀。群雄昨日已见识了她软鞭的威力,不意她左手尚能同时用刀,一长一短,一柔一刚,那是两般截然相异的兵刃。群雄惊佩之下,精神都为之一振。
- 天微星九纹龙史进。
水浒传里虽然有几位武力值爆表的好汉,比如卢俊义,史文恭,林冲这些,但是书中他们从始至终都只使用一种武器。而史大郎在战场上和别人拼命时,曾先后使用了三种不同的武器,其中还包含中国古代武将很少有敢尝试的高难度武器——流星锤。
史进大怒道:“贼回子敢如此猖獗!”便轮着三尖两刃四窍八环刀,直取兰生。兰生急举独足铜人,敌住史进。两下各显武艺,奋勇大斗。
史进换了一支点钢丈八蛇矛,骤马出来。哈芸生见了,便挺着手中五股托天叉,一马冲来,直取史进。二人也不打话,两马相交,叉矛并举,一来一去。只见史进那枝矛,忽高忽低,忽前忽后,忽左冲,忽右掠,挥身上下,尽是一片矛影。
说时迟,那时快,史进早已手提流星锤,换了一匹高头大马,赶到阵前。兰生飞起铜人打去,沙冕二人一齐攒上。史进耍圆那颗流星锤,挡住三人。
书中提到的史大郎在八十万禁军教头王进的指导下,十八般武艺样样精通,果然名不虚传。
而李贝宁,在SAP成都研究院三支分别使用Java, JavaScript和ABAP的开发团队里都被任命为架构师,技术的全面性不输于史大郎。
据我所知李贝宁喜欢的球星是被球迷冠以“拼命三郎”,“铁人”称号的内德维德,喜欢他在球场上不惜体力奔跑那种铁血作风。李贝宁希望自己在球场上也能做一个像内德维德那样的拼命三郎。
Jerry不是球迷,只知道咱历史上也有一位拼命三郎:
作为一个八零后,Jerry幼年在这些卡片上没少花钱。如果您有同样的收藏爱好,欢迎后台交流。
下面是李贝宁的正文。
大家好,我叫李贝宁,也可以叫我Ben, 目前在SAP成都研究院某云产品项目组担任高级开发工程师和架构师。
我是09年加入SAP的, 之前在上海花旗集团软件中心做了4年银行系统开发, 进到SAP之后先在SAP上海研究院工作了两年,于11年底转到了SAP成都研究院直至现在,算起来在成都呆了快七年了。
除了编程之外,我还有两个铁打不动的爱好,足球和围棋,水平嘛分别算得上小区球星级和街道业余高手级... 我认为这两件事一个可以保持身体上的活力,一个可以保持头脑上的活力,所以至今一直坚持每周踢一场球和下几盘棋的节奏,当然同时也作为工作之余的放松。
这篇文章就SAP Hybris某款正在开发的云产品在SAP云平台上用到的一个组件Application Router(以下简称App Router)做一个介绍。
SCP App Router是SAP云平台(以下简称SCP)上的核心模块之一,作为独立运行在SCP Cloud Foundry环境中的一个应用程序,它主要支持以下两大核心功能:
-
反向代理:将外部请求分发给SCP Cloud Foundry环境内不同的应用程序。
-
安全集成:和SCP Cloud Foundry上的核心安全组件UAA无缝集成,提供了用户认证,会话管理等安全相关的功能。
说到这里您也许马上会想到Nginx,一款优秀的开源Web服务器,用来做类似反向代理的功能。如果我的应用程序想要用Nginx,可不可以呢?其实SCP并没有限制只能用App Router——它是一个完全开放的平台,您可以部署任意你想要的组件为应用程序服务,只是SAP在上面已经提供了一系列的基础设施组件,这套SAP原生组件之间提供了更佳的集成和协同,App Router就是其中之一。
理解App Router的技术选型
App Router是一个用Node.js构建的标准的Web应用。
众所周知Node.js作为一门开放的技术环境,在构建基于HTTP的Web应用上有先天的优势: 简单,高效。并且Node.js经过近几年的快速迭代和发展,已经非常成熟和稳定,再加上开源社区提供了丰富的库,Node.js已经成为了服务器端强大的应用开发环境。SAP选择Node.js作为其云战略平台上的核心组件的技术栈,从这个选择我们也能看出SAP在云战略上的思路是逐步走向开放。
您或许会问,Node.js是单线程模型,根据上面的示例图,所有对于部署在SCP Cloud Foundry上的后端访问都通过App Router,这会带来性能问题吗?其实这是对于Node.js运行时模型的一个误解,参考一张Node.js的运行时架构图:
Node.js对于应用程序端只提供了单线程的编程模型,但是其底层的运行架构并非是单线程模型。在Node.js中各种HTTP访问,数据库的读写,文件IO的访问都是以异步的方式代理给了底层的V8引擎,主线程不会被阻塞,而底层V8引擎具备非常强大的并发处理能力,会迅速将各个事件并发的处理结果通过事件轮询的方式返回给主线程。只要在Node.js的主线程中不做大量的CPU运算(比如大规模业务逻辑运算,科学计算等),这样的Node.js应用程序是可以具备良好的性能的。
而App Router恰好具有上述所说的那些一典型特征:在用户认证中将识别用户身份和权限的工作代理给Cloud Foundry UAA来做,业务请求转发给各个独立的部署Cloud Foundry应用,自己仅仅做一些简单的HTTP参数的转换和校验,请求的转发,以及请求响应的返回。
App Router上的routing(路由)
在App Router上路由的实现是通过定义一系列destination来实现的,具体来说就是在App Router的xs-app.json中配置route和destination,以及在manifest.yml中配置对应destination的url:
manifest.yml:
简单解释一下主要的参数:
Routes
-
source:可以是一个URL,也可以是一个正则表达式,定义了当前的route是匹配什么样的请求路径
-
target: 当前请求如何被重写到目标地址
-
destination: 当前请求路由到manifest中的哪个目标地址
-
authenticationType: 有三种选择,xsuaa, none和basic,xsuaa和none分别代表了是否对当前请求在App Router上做用户安全认证,下一节会具体介绍。Basic是和SAP HANA集成的时候提供默认的安全验证支持。
Destination
-
Name:用来跟xs-app.json中的destination配置相匹配
-
URL:目标应用程序真实的Clould Foundry地址
-
ForwardAuthToken: 如果请求中带有oauth token,是否将oauth token转发给目标应用程序. App Router也支持oauth token的部分校验功能,所以用户也可以根据具体情况选择不转发oauth token,就在App Router端校验
除了基本的路由功能,App Router还提供了丰富的Web应用程序相关的功能支持,比如连接管理,session管理,扩展http头,跨域,Web Socket等等。
App Router和SCP UAA的安全集成
如上一节提到的,App Router在路由的时候提供了用户的安全认证支持。将路由的Authentication Type配置为xsuaa,App Router则会检查前端发过来的请求是否带有合法的session。如果没有,App Router会将用户导向SCP UAA的用户认证界面,当用户重新认证成功之后,会生成新的合法session,并将此session返回给前端应用程序。
整个认证的流程是是SCP App Router和SCP UAA协同完成的,SCP UAA是SAP对Cloud Foundry上提供的安全组件UAA (User Account and Authentication Service)的一个封装,Cloud Foundry UAA是一个实现了标准Oauth 2.0协议的authorization server,SAP在此基础上做了一些自定义的增强,但是在接口上和原生的UAA保持了一致,这样可以尽可能的对OAuth Client端程序提供兼容性。
Cloud Foundry UAA官方文档:
https://docs.cloudfoundry.org/api/uaa/version/4.10.0/index.html#overview
SCP标准的OAuth2.0流程:
如果熟悉OAuth2.0协议,从这张流程图上很快就能看出App Router和UAA之间是通过Authorization Code Grant Flow来交互的,在交互过程中它们分别充当了OAuth Client和OAuth Server的角色。
关于OAuth2.0,请参见: https://oauth.net/2/
看到这里您也许会问,为什么不是前端浏览器作为OAuth Client?除了安全性的考虑, App Router将OAuth流程对前端隐藏的另一个好处是,各种前端应用程序不需要知道UAA上诸如Client ID, Client Secret的细节,提供了更好的安全性。
其次还有SAP在产品层面的考量,为了其标准的产品在UI技术上的一致性,包括SCP上的产品在内大多数都是基于SAP UI5来构建前端UI,而UI5又是基于HTML5技术而来,即这些产品都是基于浏览器的富客户端应用。如此一来,在标准的App Router里面实现OAuth2.0流程可以使SAP的各种前端应用并不需要关注认证流程的细节。如上图所示,App Router在完成了认证流程并最终拿到token之后,并没有将token返回给浏览器端,而是在App Router上生成一个session,并且将session和token关联起来,App Router在这里起到一个中介者的角色,对于前端统一用session进行交互,对于后端统一用token进行交互。
SCP除了将标准的实现默认支持浏览器端应用程序外,作为一个开放的平台,当然也支持移动端原生应用程序的集成,这里不作赘述,具体细节可以参考SCP的开发文档。
App Router上的session管理
App Router上的session管理利用了Node.js的session-express框架,默认将session缓存在instance memory中(下图第79行):
然后采用session stickiness策略来保证在多实例部署的情况下,相同会话的请求会被发送到同一个实例上以保证会话能继续进行。
Session Stickiness:
https://stackoverflow.com/questions/10494431/sticky-and-non-sticky-sessions
这样做的好处是既利用了instance memory的高性能,也可以在一定程度上保证高可靠性。不过代价是牺牲了动态伸缩的能力,一旦某个App Router实例上还有正在使用中的session,这个实例就不能被关闭。
好在App Router使用的是开源的express-session框架,该框架并非只能将session存储在instance memory中,在Node.js开源社区已经提供了多种express-session的外部存储方案。至少在技术上,可以将App Router提供的instance memory存储替换为外部存储,而不需要做太多的定制化开发,这样一来多个App Router实例就可以共享同一套session存储。
App Router的可扩展性
只要说到SAP的产品,extensibility是一个不可避免的话题,这是由SAP的业务是面向企业级客户这一特质决定的。SAP也一直致力于从平台到框架,再到上层的产品,尽可能多的给SAP客户提供良好的可扩展性。App Router同样也不例外,因为直接使用了Node.js的connect框架,这是一款本身就提供了丰富扩展的中间件框架,可以通过可插拔的方式对Node.js的请求和响应提供过滤和拦截,具体大家可以参考connect的主页。
App Router基于connect,当然App Router的用户就可以直接获得connect提供的各种中间件,除此之外App Router还提供了自己的一些中间件:
是不是非常简单和直接?使用这些中间件而不需要修改原生App Router里面的代码。
这里不再对App Router上的各种中间件一一赘述,具体细节可以参考App Router的Github文档。
总结说来,App Router是一款设计简单,使用方便,提供了良好可扩展性的反向代理组件,为广大SAP用户在SCP上开发应用程序提供了更多的选择和方便。
感谢大家阅读。
要获取更多Jerry的原创技术文章,请关注公众号"汪子熙"或者扫描下面二维码: