一捅到底的架構

今天的主角是JSON。

故事要從J2EE這個罪惡的東西說起,多年以前,在Java語言得到一定程度上的成功之後,SUN將Java本身分為三塊,一塊是精簡版,主要目的是給手機使用的J2ME,一塊是標準版J2SE,最後一塊是擴展版,在原有的J2SE基礎之上,加多了一些額外的包,並定義成J2EE,其核心是EJB,EJB是普通Java Bean的擴展。

當時SUN認為,一個複雜的挨踢系統,應該分為前端,後端和資料庫端幾個tier層面,客戶端,前端,後端和資料庫一般不在一個物理主機上,如下圖:

可以看到J2EE Server裡面有兩層,分別對應著俗稱的前端和後端,那前端就是JSP,後端就是EJB了,他們該怎麼通信呢?

當時SUN腦洞大開滴將所有的EJB分成兩個部分,一個是後端的Skeleton,另外一個是放在前端的Stub,前端通過調用Stub上的方法,就可以跟Skeleton通信,並獲取結果。

這種設計不能說是錯的,但是對於大多數公司來說,前端和後端只需要在邏輯層面上做切割就好了,沒有必要在物理層面上強行切割,SUN的設計,哪怕是同一台虛擬機上使用EJB,也需要用一個所謂的Local Stub,如果是不同虛擬機上,則是Remote Stub,這就麻煩了不是?所以Spring提出,不要搞那麼複雜啦,一台機器上,我們在邏輯層面上切割就好了,不需要搞什麼垮虛擬機方法調用,如果真需要,我們可以借鑒Web Service等架構來調用嘛,於是經過一段時間的調整,尤其是Rod Johnson的《J2EE Without EJB》的橫行,主流的架構變成了這個樣子:

EJB逐步淡出人們視野,Spring的各個組件(Controller, Service&DAO)開始在同一台虛擬機中出現,又過了一段時間,人們發現,Java用來寫前端,似乎不那麼方便,所以Node.js開始大行其道,那前後端得分離啊,架構就演變成了這樣:

前端用Node.js,後端用Java應該是這些年的主流,後台有些公司會將Java換成Go。

好,到目前為止,所有的分工,都是按照前端,後端,資料庫這種層面來做切割的,不管怎麼換,無非是前端從JSP換到Node.js,後端從Spring MVC&Tomcat換到Go,或者再換回來,等等,都很正常,這樣做的好處就在於,系統的兼容性較強,但是壞處也很明顯,就是一個哪怕是再細微的服務流程,都會被切割成幾段,哪怕是最簡單的查詢,你也需要經過前端JSP/Node,然後再經過後端Spring/Go,最後再到資料庫,IO層次比較多,同時我們也會看到,在不同層次之間,數據結構發生了改變,而且比較難以統一,比如瀏覽器發給前端的,一般是JSON,Java前端收到之後轉換成POJO,EJB有Entity Bean,DAO需要做ORM,最後資料庫存的是Table格式,每一次請求,從發起到最後的結束,都需要在不同層次之間頻繁扭轉,同時對象會被頻繁生成並轉換,比較浪費資源,同時也比較浪費開發的人力,維護成本也不低。

一句話就是開發,維護和運行成本都不低。

下面介紹一種以服務為中心的架構,如果你願意,可以稱之為微服務的架構。

先介紹兩個概念,軟體工程中模塊切割辦法分為橫向和縱向:

  1. 橫向分割根據輸入輸出等功能的不同來分割模塊;
  2. 縱向分割根據系統對信息進行處理過程中不同的階段來分割。

由此可見,之前介紹的所謂前後端分離等架構,全部是縱向切割的架構,那麼我們需要將其轉換成橫向切割法,同時分配給每個開發人員。請注意,我們不再區分前端,後端,資料庫的挨踢人員,而是按照功能予以切割,這意味著,對於挨踢從業人員的要求將會提高,我們需要從業人員是真的全棧開發者,必需從前端到最後的存儲全部都要搞定,而非像過往一樣分成前端做,後端做還有DBA做,不不不,全棧意味著什麼都要做,會有所側重,但是多少都會遇到。

既然要橫向切割,將每一個模塊分成具體的服務Service,那麼我們去找懂上訴所有技術的挨踢人員,似乎不太現實,當然不是沒有,但是學習成本在這裡,不太容易找到,所以我們需要降低從業人員的上手成本。

首先,有鑒於之前數據結構的複雜化導致的數據本身被頻繁轉換造成的巨大的浪費,我們需要找一個共通的數據結構,讓不同軟體能夠很好滴協作起來,建議這裡用JSON,原因如下:

  1. 大多數計算機語言都支持JSON格式
  2. JSON格式也被多數NoSQL資料庫所支持,RDBMS比如Postgresql也加入了JSON的支持
  3. JSON本身便於理解,易於閱讀
  4. JSON可以很方便地轉換成String,which在很多語言環境中都是immutable的存在,可以減少傳輸過程中的拷貝次數

經過我們多次對比各個資料庫的功能以及性能,同時跟同行的交流之後,我們建議採用Postgresql(PG)作為數據存儲工具,版本最好在9.4+,因為PG本身是RDBMS,具有關係型資料庫的所有主要功能,同時PG對於JSON的支持走在所有RDBMS的前面,可以針對JSON裡面的某個Field建索引和做條件查詢等,這很重要。

其次,鑒於PG只是一個資料庫,CAP理論告訴我們,資料庫具備有CA的特性,本身並不具備有解決P的能力,所以最好搭配一個AP的NoSQL資料庫配合,我們推薦Cassandra,因為AP可以tune成CP,反過來,嗯,好像普遍不行。

這是資料庫的選擇,然後我們要選擇一個軟體伺服器,鑒於我們已經決定將JSON作為主要的數據結構,那麼需要一個對於JSON支持得比較好的軟體伺服器,這裡推薦Vert.x啦,Vert.x僅有兩個依賴,分別是Netty和Jackson,後者是比較流行活躍的JSON處理庫,所以使用Vert.x,不需要額外增加新的JSON處理依賴,便可很方便滴處理JSON。同時這裡建議取消前端和後端的區分,或者將前後端從物理隔離做成邏輯隔離,在Vert.x中分別建立前端Verticle和後端Verticle予以對應,Vert.x中連接不同Verticle的Eventbus支持JSON類型。

好,到目前為止,軟體伺服器和資料庫都已經統一起來了,還剩下跟客戶端的連接啦。

那其實就更簡單了,一般的瀏覽器上Javascript發送和接收JSON都有非常成熟的框架可以直接使用了,那剩下的就是API Gateway啦,將API Gateway做成Restful Web Service等支持JSON類型的應用也有很多方案啦,不再贅述。

哇啦,我們的架構到此為止基本上大功告成啦,可以看到,無論是客戶端,還是伺服器端,還是數據端,都支持JSON類型,那麼我們可以很容易地實現一個簡單的CRUD功能,並將其通用化,具體的實現細節留給讀者自己去思考吧,並不困難,在AWS上已經有了類似的實現,名稱是Serverless,已經成功滴降低了可口可樂公司的挨踢成本並提升相應的運行效率,是不是很方便呢?

後續:

用Vert.x實現Serverless架構

PG(PostgreSQL)在一捅到底架構中的使用

參考鏈接:

Dynamic Routing in Serverless Microservice with Vert.x Event Bus

Serverless - The Serverless Application Framework powered by AWS Lambda and API Gateway

註:以上圖片均來自網路,侵刪


推薦閱讀:

Bumpover.js - 牢固而趁手的數據校驗轉換庫
JSON适合大数据传输吗?跨语言JSON数据传输需要注意什么?

TAG:JSON | 微服务架构 | PostgreSQL |