1. 程式人生 > >蘇寧人工智慧研發中心智慧創意平臺架構成長之路(一)--長篇開篇

蘇寧人工智慧研發中心智慧創意平臺架構成長之路(一)--長篇開篇

 (這是第一篇開篇,成長之路序列會包含多篇,筆者作為這個平臺的架構兼技術經理,充分講述其中的迭代心酸之路以及中間遇到的問題和解決方案)

宣告:文章不涉及公司內部技術資料的外洩,涉及的圖片都是重畫的簡易架構圖,主要通過架構的演進,講述分享技術的迭代之路和過程

蘇寧人工智慧研發中心成立了於2018年,從2018年下半年開始在規劃一個類似京東玲瓏和阿里鹿班的一個Banner圖的合成平臺專案,初期產品設計的是一個sass化的產品,可以對內也可以對外服務,初期規劃時,只有如下幾個模組。

1、 服務:主要是對外提供統一的restful api服務,服務包括離線服務和實時服務。

2、 工作臺:指的是一個使用者操作合成banner介面,供使用者做操作,在鹿班和玲瓏中都有。

智慧合成,指的是使用者可以選擇風格標籤後,然後平臺依靠人工智慧自動生成banner圖。

手動合成:指的是人可以手工干預合成,比如可以自己選擇素材和上傳素材(比如banner圖的背景,裝飾圖等)

3、 後臺管理指的一個供管理用的介面。

由於一期在規劃時,先實現工作臺和後臺管理兩部分,服務一開始不實現,所以初期架構設計如下:

設計的思路如下:

1、 考慮到系統的高可拓展性以及未來平臺可能會增加很多其它的服務,並且可能會朝著智慧創意來發展,所以在web 框架選型時,我這邊選是springcloud+springboot。雖然一開始模組很少,使用springcloud會有點大材小用,但是這個是一個長期不斷迭代的專案,所以系統的擴充套件性在前期一定要先準備好。

2、 由於服務一開始我們並不實現,所以我們其實只有一個模組,就是iwogh-web這個模組。

3、 我們所有的請求還是使用springcloud中的Zuul模組來做理由控制。Eureka來負責服務註冊中心。

4、 資料庫使用的Mysql資料庫,因為一開始資料並不大,關心型的mysql可以滿足要求,並不需要一開始就去考慮大資料的方案。

5、 由於演算法基本都是python來實現的,所以我們會把python實現的演算法包裝一個http的服務,包裝的時候我們開始選擇的是python中的flask框架。

6、 演算法的叢集實現,我們使用的是nginx來做反向代理轉發,一個nginx叢集,可以控制很多個不同的演算法叢集(比如每個不同型別的演算法構建一個叢集),因為我們可以利用nginx中的location

location的語法:

 location [=|~|~*|^~] patt { }  //中括號中為修飾符,可以不寫任何引數,此時稱為一般匹配,也可以寫引數

因此,大型別可以分為三種:

 location = patt {} [精準匹配]

location patt{}     [普通匹配]

 location ~ patt{}  [正則匹配]

 server {

        listen 80;

        server_name localhost;

        location =/text.html { #精準匹配,瀏覽器輸入IP地址/text.html,定位到伺服器/var/www/html/text.html檔案

            root /var/www/html;  

            index text.html;

        }

        location / { #普通匹配,瀏覽器輸入IP地址,定位到伺服器/usr/local/nginx/html/default.html檔案

            root html;  

            index default.html;

        }

    location ~ image { #正則匹配,瀏覽器輸入IP/image..地址會被命中,定位到/var/www/image/index.html

      root /var/www/image;

      index index.html;

    }

}

當然還有一種思路,就是通過sidecar元件,把演算法服務也註冊到springcloud中作為一個服務,然後呼叫演算法服務採用spingcloud內部服務的方式來實現。

不過最終經過一些考慮,否決了這種想法,

1) 、演算法更偏底層,不太適合在應用層的服務中管理,在架構設計時,本來也會給演算法設計一層演算法工程化服務層,結構大致會這樣,演算法服務只專注於演算法的處理,不會涉及任何的處理邏輯。

2) 、演算法一般是python來實現的,所以工程化的封裝一般也是會使用python來包裝服務,納入到以java為主的springcloud服務中來管理,在持續整合釋出時,不是非常方便管理。

1、 redis主要用來做分散式的會話session,而且我們還使用session做了另一個設計,由於banner合成時一次是批量合成5張圖出來,但是演算法底層由於是深度機器學習框架,所以演算法處理的速度並不會很快,如果使用者在工作臺中等待5張圖全部合成完,使用者的體驗會很差,因為等待的時間會很長,所以我們採用了輪詢 按照一張一張來載入,並不是等5張banner圖全部出來後再一次加載出來,而是出來一張就載入一張。

如下圖,在第一步呼叫演算法服務處理完後,生成了banner圖後會先存入到圖片儲存中,然後寫入時,會往redis和mysql中同時寫入,redis中會有一定的實效時間,因為使用者有不可能會在頁面一直等,總歸是會超時的,實效時間一般設定在了5-10分鐘左右。此時頁面會輪詢的按照requestId+圖片序號來獲取banner圖(每一個請求都會有一個請求的requestId,由於一次是5張圖,所以圖片是有序號的,可以輪詢的獲取),輪詢獲取時,就介面的API服務就可以直接去查詢redis了,因為這樣查詢速度很快,使用者體驗會更好,圖片就會類似實時查詢一樣,頻繁的查詢也不影響效能。其實你如果看過鹿班的話,你也會看到,他們的結果圖也是分批出來,不是一次出來全部。

在第一輪上線後,由於使用者使用體驗還可以,給了更多的時間來做第二輪的產品迭代,所以到第二輪迭代時,我們為了支撐服務和其他更多的需求,對架構做了比較大的調整。

在第二輪迭代時,架構圖就變成了這樣

 

 

1、 我們需要支撐介面API服務了,包括實時服務,離線服務,供其他的業務來呼叫使用。初期API主要分這幾種情況

介面API的設計主要包括這幾點

1)、客戶端每次請求需要帶入一個時間戳,服務端會校驗這個時間戳,超過一定時間範圍內的請求,服務端作為無效的請求自動丟棄,也可以避免介面服務被機器人進行攻擊。

2)、每個請求需要帶入一個Appid,這個Appid由平臺自動分配。

3)、每個請求需要用一個祕鑰來生成簽名,生成的簽名sign也是需要作為一個引數在介面中傳入。 每個Appid會分配一個祕鑰,這個祕鑰是保密不公開的提供給使用者。

4)、簽名的生成會按照時間戳+appid,然後使用祕鑰來生成簽名。

5)、每次請求返回(不管實時還是離線),都會返回一個唯一的requestID給使用者。使用者可以用這個requestID來呼叫查詢介面查詢已經實時合成過的banner圖,也可以查詢離線合成的banner圖。

2、在離線請求中,如果使用者傳入了回撥的url地址,那麼在離線處理完後,我們會自動進行回撥,在設計時,我們特別做了考慮。

3、kafka也可以作為一個入口,比如大量的合成,使用者可以直接推入到kafka中,因為通過http請求進行離線合成,還是會有非常大的請求消耗。

4、在架構圖中,我們設計了

Iwogh-service:主要做介面API服務,不涉及邏輯處理,接收到的離線合成是,直接把請求放入到kafka中。

Iwogh-pps-web:使用者工作臺模組,包括智慧合成和手動合成

Iwogh-web:後臺管理模組,在第二輪迭代中,我們把工作臺和後臺管理進行了拆分,拆成了兩個web服務,作為兩個war包

Iwogh-offline-merge:負責離線合成處理,負責消費kafka中的離線請求資料,並且去呼叫演算法服務處理,處理完的結果放入到新的kafka中。

Iwogh-online-merge:負責處理實時請求服務,去呼叫演算法處理。並且負責工作臺過來的banner圖處理請求。處理完成的請求,統一發送到kafka中。

Iwogh-data-process:消費處理完成的kafka結果資料,負責結果資料的統一入庫處理,以及離線請求的回撥處理。

由於我們儲存了所有的處理請求和結果,在這裡,我們不是選用的mysql來儲存這些資料,而是hbase,hbase很適用於我們的場景,由於requestId永遠是唯一的,所以hbase的rowkey可以用requestId就可以了。

而且hbase支援batch查詢,也就是一次可以傳入多個requestId來進行查詢,效率也是非常高。

5、我們使用springcloud中的Zuul來作為我們的介面服務請求中的sign簽名認證校驗,Zuul非常適合這種場景。

未完待續