(這是第一篇開篇,成長之路序列會包含多篇,筆者作為這個平台的架構兼技術經理,充分講述其中的迭代心酸之路以及中間遇到的問題和解決方案)
聲明:文章不涉及公司內部技術資料的外泄,涉及的圖片都是重畫的簡易架構圖,主要通過架構的演進,講述分享技術的迭代之路和過程,進行技術交流和探討。
人工智能-智能創意平台架構成長之路(三)--機器學習算法工程服務化
人工智能-智能創意平台架構成長之路(四)-豐富多彩的banner圖生成解密第一部分(對標阿里鹿班的設計)
筆者所在的公司從很早就開始了探索人工智能,而2018年公司專門成立了獨立的人工智能研發中心,標志着開始了大規模的人工智能產品研發,也體現出對人工智能發展的重視,從2018年下半年開始在規划一個類似京東玲瓏和阿里鹿班的一個Banner圖的合成平台項目,初期產品設計的是一個sass化的產品,可以對內也可以對外服務,初期規划時,只有如下幾個模塊。
最終會通過算法自動生成類似這樣的banner圖
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非常適合這種場景。
如果對於Zuul不熟悉,可以參考服務網關組件Zuul工作原理流程如下:
未完待續,請繼續關注
人工智能-智能創意平台架構成長之路(二)--大數據架構篇