摘要: 近幾年來,人工智能逐漸火熱起來,特別是和大數據一塊兒結合使用。人工智能的主要場景又包括圖像能力、語音能力、天然語言處理能力和用戶畫像能力等等。這些場景咱們都須要處理海量的數據,處理完的數據通常都須要存儲起來,這些數據的特色主要有以下幾點: 大:數據量越大,對咱們後面建模越會有好處; 稀疏:每行數據可能擁有不一樣的屬性,好比用戶畫像數據,每一個人擁有屬性相差很大,可能用戶A擁有這個屬性,可是用戶B沒有這個屬性;那麼咱們但願存儲的系統可以處理這種狀況,沒有的屬性在底層不佔用空間,這樣能夠節約大量的空間使用; 列動態變化:每行數據擁有的列數是不同的。架構
近幾年來,人工智能逐漸火熱起來,特別是和大數據一塊兒結合使用。人工智能的主要場景又包括圖像能力、語音能力、天然語言處理能力和用戶畫像能力等等。這些場景咱們都須要處理海量的數據,處理完的數據通常都須要存儲起來,這些數據的特色主要有以下幾點:併發
爲了更好的介紹 HBase 在人工智能場景下的使用,下面以某人工智能行業的客戶案例進行分析如何利用 HBase 設計出一個快速查找人臉特徵的系統。運維
目前該公司的業務場景裏面有不少人臉相關的特徵數據,總共3400多萬張,每張人臉數據大概 3.2k。這些人臉數據又被分紅不少組,每一個人臉特徵屬於某個組。目前總共有近62W我的臉組,每一個組的人臉張數範圍爲 1 ~ 1W不等,每一個組裏面會包含同一我的不一樣形式的人臉數據。組和人臉的分佈以下:機器學習
如今的業務需求主要有如下兩類:高併發
以前業務數據量比較小的狀況使用的存儲主要爲 MySQL 以及 OSS(對象存儲)。相關表主要有人臉組表group和人臉表face。表的格式以下:性能
group表:學習
group_id | size |
---|---|
1 | 2 |
face表:測試
face_id | group_id | feature |
---|---|---|
"c5085f1ef4b3496d8b4da050cab0efd2" | 1 | "cwI4S/HO/nm6H……" |
其中 feature 大小爲3.2k,是二進制數據 base64 後存入的,這個就是真實的人臉特徵數據。大數據
如今人臉組 id 和人臉 id 對應關係存儲在 MySQL 中,對應上面的 group 表;人臉 id 和人臉相關的特徵數據存儲在 OSS 裏面,對應上面的 face 表。優化
由於每一個人臉組包含的人類特徵數相差很大(1 ~ 1W),因此基於上面的表設計,咱們須要將人臉組以及每張人臉特徵id存儲在每一行,那麼屬於同一我的臉組的數據在MySQL 裏面上實際上存儲了不少行。好比某我的臉組id對應的人臉特徵數爲1W,那麼須要在 MySQL 裏面存儲 1W 行。
咱們若是須要根據人臉組 id 查找該組下面的全部人臉,那麼須要從 MySQL 中讀取不少行的數據,從中獲取到人臉組和人臉對應的關係,而後到 OSS 裏面根據人臉id獲取全部人臉相關的特徵數據,以下圖的左部分所示。
咱們從上圖的查詢路徑能夠看出,這樣的查詢致使鏈路很是長。從上面的設計可看出,若是查詢的組包含的人臉張數比較多的狀況下,那麼咱們須要從 MySQL 裏面掃描不少行,而後再從 OSS 裏面拿到這些人臉的特徵數據,整個查詢時間在10s左右,遠遠不能知足現有業務快速發展的需求。
上面的設計方案有兩個問題:
針對上面兩個問題,咱們進行了分析,得出這個是 HBase 的典型場景,緣由以下:
咱們可使用這三個功能從新設計上面 MySQL + OSS 方案。結合上面應用場景的兩大查詢需求,咱們能夠將人臉組 id 做爲 HBase 的 Rowkey,系統的設計如上圖的右部分顯示,在建立表的時候打開 MOB 功能,以下:
create 'face', {NAME => 'c', IS_MOB => true, MOB_THRESHOLD => 2048}
上面咱們建立了名爲 face 的表,IS_MOB
屬性說明列簇 c 將啓用 MOB 特性,MOB_THRESHOLD
是 MOB 文件大小的閾值,單位是字節,這裏的設置說明文件大於 2k 的列都當作小文件存儲。你們可能注意到上面原始方案中採用了 OSS 對象存儲,那咱們爲何不直接使用 OSS 存儲人臉特徵數據呢,若是有這個疑問,能夠看看下面表的性能測試:
對比屬性 | 對象存儲 | 雲 HBase |
---|---|---|
建模能力 | KV | KV、表格、稀疏表、SQL、 全文索引、時空、時序、圖查詢 |
查詢能力 | 前綴查找 | 前綴查找、過濾器、索引 |
性能 | 優 | 優,特別對小對象有更低的延遲;在複雜 查詢場景下,比對象存儲有10倍以上的性能提高 |
成本 | 按流量,請求次數計費, 適合訪問頻率低的場景 |
託管式,在高併發,高吞吐場景有更低的成本 |
擴展性 | 優 | 優 |
適用對象範圍 | 通用 | <10MB |
根據上面的對比,使用 HBase MOB特性來存儲小於10MB的對象相比直接使用對象存儲有一些優點。
咱們如今來看看具體的表設計,以下圖:
上面 HBase 表的列簇名爲c,咱們使用人臉id做爲列名。咱們只使用了 HBase 的一張表就替換了以前方面的三張表!雖然咱們啓用了 MOB,可是具體插入的方法和正常使用同樣,代碼片斷以下:
String CF_DEFAULT = "c"; Put put = new Put(groupId.getBytes()); put.addColumn(CF_DEFAULT.getBytes(),faceId1.getBytes(), feature1.getBytes()); put.addColumn(CF_DEFAULT.getBytes(),faceId2.getBytes(), feature2.getBytes()); …… put.addColumn(CF_DEFAULT.getBytes(),faceIdn.getBytes(), featuren.getBytes()); table.put(put);
用戶若是須要根據人臉組id獲取全部人臉的數據,可使用下面方法:
Get get = new Get(groupId.getBytes()); Result re=table.get(get);
這樣咱們能夠拿到某我的臉組id對應的全部人臉數據。若是須要根據人臉組id+人臉id查找某我的臉的具體數據,看可使用下面方法:
Get get = new Get(groupId.getBytes()); get.addColumn(CF_DEFAULT.getBytes(), faceId1.getBytes()) Result re=table.get(get);
通過上面的改造,在2臺 HBase worker 節點內存爲32GB,核數爲8,每一個節點掛載四塊大小爲 250GB 的 SSD 磁盤,並寫入 100W 行,每行有1W列,讀取一行的時間在100ms-500ms左右。在每行有1000個face的狀況下,讀取一行的時間基本在20-50ms左右,相比以前的10s提高200~500倍。
下面是各個方案的對比性能對比狀況。
對比屬性 | 對象存儲 | MySQL+對象存儲 | HBase MOB |
---|---|---|---|
讀寫強一致 | Y | N | Y |
查詢能力 | 弱 | 強 | 強 |
查詢響應時間 | 高 | 高 | 低 |
運維成本 | 低 | 高 | 低 |
水平擴展 | Y | Y | Y |
咱們已經將人臉特徵數據存儲在阿里雲 HBase 之中,這個只是數據應用的第一步,如何將隱藏在這些數據背後的價值發揮出來?這就得藉助於數據分析,在這個場景就須要採用機器學習的方法進行聚類之類的操做。咱們能夠藉助 Spark 對存儲於 HBase 之中的數據進行分析,並且 Spark 自己支持機器學習的。可是若是直接採用開源的 Spark 讀取 HBase 中的數據,會對 HBase 自己的讀寫有影響的。
針對這些問題,阿里雲 HBase 團隊對 Spark 進行了相關優化,好比直接讀取 HFile、算子下沉等;而且提供全託管的 Spark 產品,經過SQL服務ThriftServer、做業服務LivyServer簡化Spark的使用等。目前這套 Spark 的技術棧以下圖所示。
經過 Spark 服務,咱們能夠和 HBase 進行很好的整合,將實時流和人臉特徵挖掘整合起來,整個架構圖以下:
咱們能夠收集各類人臉數據源的實時數據,通過 Spark Streaming 進行簡單的 ETL 操做;其次,咱們經過 Spark MLib 類庫對剛剛試試收集到的數據進行人臉特徵挖掘,最後挖掘出來的結果存儲到 HBase 之中。最後,用戶能夠經過訪問 HBase 裏面已經挖掘好的人臉特徵數據進行其餘的應用。