天天看點

SAP成都研究院李三郎:SCP Application Router簡介

今天的文章來自李貝甯(Ben),SAP成都研究院的資深程式猿和架構師。

作為成都研究院裡同時精通Java, JavaScript和ABAP這三門程式設計語言的數位同僚之一,Ben曾經先後擔任了成都CRM Fiori開發團隊,S4CRM開發團隊和尚未釋出的某款雲産品開發團隊的架構師。

Ben在這三個團隊的職責都是産品架構設計和部分功能代碼的編寫,以及組内其他同僚的代碼審查。

除了自身架構設計和程式設計相關的技能過硬之外,Ben在傳業授道解惑方面也很有心得。Ben是SAP研究院内部的Agile Software Enginnering教練,也是SAP成都研究院若幹内部教育訓練課程的講師。他的課程幫助了很多剛剛走出大學校園的年輕同僚們從在學校書寫玩具代碼到走向真正的企業軟體開發的專業之路。

每位同時精通數門風格截然不同的程式設計語言的開發人員,總有自己的一套心得和辦法,把這些語言融為一體,為自己所用。那麼Ben又是如何做到的呢?或許可以從Ben的業餘愛好看出點端倪。Ben喜歡足球和圍棋,并且水準在業餘愛好者裡不算太差。能同時駕馭這一動一靜,一剛一柔,一陽一陰的兩個愛好,除了Ben以外,我能想到的也就隻有這幾位高手了:

1. 人到中年,把降龍十八掌練到超過洪七公造詣的大俠郭靖。

豈知郭靖近二十年來勤練九陰真經,初時真力還不顯露,數十招後,降龍十八掌的勁力忽強忽弱,忽吞忽吐,從至剛之中竟生出至柔的妙用,那已是洪七公當年所領悟不到的神功

2. 左手短刀,右手長鞭的峨眉美女掌門周芷若。

周芷若取出軟鞭,右手一抖,鞭子登時卷成十多個大大小小的圈子,好看已極,左手翻處,青光閃動,露出了一柄短刀。群雄昨日已見識了她軟鞭的威力,不意她左手尚能同時用刀,一長一短,一柔一剛,那是兩般截然相異的兵刃。群雄驚佩之下,精神都為之一振。

3. 天微星九紋龍史進。

水浒傳裡雖然有幾位武力值爆表的好漢,比如盧俊義,史文恭,林沖這些,但是書中他們從始至終都隻使用一種武器。而史大郎在戰場上和别人拼命時,曾先後使用了三種不同的武器,其中還包含中國古代武将很少有敢嘗試的高難度武器——流星錘。

史進大怒道:“賊回子敢如此猖獗!”便輪着三尖兩刃四竅八環刀,直取蘭生。蘭生急舉獨足銅人,敵住史進。兩下各顯武藝,奮勇大鬥。

史進換了一支點鋼丈八蛇矛,驟馬出來。哈芸生見了,便挺着手中五股托天叉,一馬沖來,直取史進。二人也不打話,兩馬相交,叉矛并舉,一來一去。隻見史進那枝矛,忽高忽低,忽前忽後,忽左沖,忽右掠,揮身上下,盡是一片矛影。

說時遲,那時快,史進早已手提流星錘,換了一匹高頭大馬,趕到陣前。蘭生飛起銅人打去,沙冕二人一齊攢上。史進耍圓那顆流星錘,擋住三人。

書中提到的史大郎在八十萬禁軍教頭王進的指導下,十八般武藝樣樣精通,果然名不虛傳。

而李貝甯,在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上開發應用程式提供了更多的選擇和友善。

感謝大家閱讀。