我們遇到了什麼?
我們有這麼一個業務場景,就是某供應商會去爬取某些資料,爬到後會發到一個FTP上,然後我們定時去獲取這些資料
這個資料有大有小,小的30多M資料量百萬級,大的資料量能到數百M上千萬資料
然後當這些資料到達的時候,我們需要在有限的時間內把這些資料寫入到我們自己的資料庫裡.
而寫入的過程包括先進行一輪資料清洗,按照指定的規則對映到我們自己的資料後在寫進去並不是簡單無腦的資料來了就batch insert那麼簡單
原來的實現方案
傳統的Sql Server硬抗,DBA叫苦連天,經常投訴,但是你投訴我也無能為力
由於資料量大小問題也只能存7天有效資料
經常遇到要查歷史資料什麼的,我未來資料都存的夠吃力了你還想要歷史?
現在的方案
後面就想著基於Azure用雲上的方案來徹底解決下這個問題
如下是我們整個方案的架構圖(視情況抹掉了一些敏感資訊)
其中核心就是CosmosDb
上面紅色字的標號是整個流程的執行順序
先簡單說下整個步驟:
1.使用VM執行一個windows service,然後定時檢測供應商的FTP,如果有檔案的話就拉取回來
2.將獲取回來的原始檔案原封不動的先儲存到Azure Storage裡的Data Lakge Gen2
3.將資料寫入到對口的儲存系統,其中分為幾個子步驟
3.1 用一個Azure SqlDatabase產生一個批次日誌
3.2 將資料寫入到Azure CosmosDb
3.3 將資料寫入到Azure Table Storage
4.通過Azure Service Bus傳送一個佇列訊息,內網一個站點訂閱該佇列,獲取訊息後去獲取訊息處理資料
5.如果後續內網裡的系統要用相關資料的時候通過一個Web App去訪問雲上的資料
各步驟解釋:
步驟1:沒什麼好說就一個傳統爬蟲的樣子
步驟2:將原始資料先儲存下來,而之所以儲存到Data Lake Gen2是考慮到後續如果我們團隊有大資料能力的話,就可以分析這裡面的內容,也因此選擇了Date Lake而不是Blob來作為儲存
步驟3: 這裡可能會比較好奇3.2和3.3為什麼資料要寫入2份,規劃裡業務系統主力用的是CosmosDb,後面會簡單介紹下這個,而Table Storage更多相當於是一個快照形式(稍後也會介紹這個),2個儲存各自有各自的側重點
步驟4: 沒專線情況下的曲線救國方案
步驟5: Web App統一對外入口,雲上資料儲存原則上不應該對外網暴露,這樣可以更好控制安全
在整個方案中用的幾個核心技術:
1.CosmosDB
具體的可以看微軟官方解釋: Azure Cosmos Db
我用站在我開發的角度以我們使用的視角簡單說一下,想詳細瞭解的請具體參考上面連結裡微軟官方的介紹
首先我們給它的定位是:費用較高的高效能儲存,用於直接給業務系統對接使用
這是微軟一個支援多種模式(Sql/Mongodb/圖資料庫/或者其他幾個形式)的能自動分庫分表(設計好Partition)全域性索引(不用坑爹的考慮索引優化)效能和你掏的錢成正比的資料庫
由於這個玩意支援Sql Api,我們之前系統用了EfCore來做Orm,而Ef Core 3是支援以CosmosDb作為Provider
所以這個切換不用太爽
我們在上雲的時候發生一個小插曲就是預訂要上線的日期結果上面還有些功能不ok,但是別的業務又急著要上線,怎麼辦呢?UseCosmos改回UseSqlServer切回老的資料來源先唄
然後按照自己的業務邏輯,對CosmosDb設定好分割槽鍵的話,他背後就能自動幫你分庫分表,在全命中你分割槽鍵的前提下將會提供較高的效率保證,而如果沒命中的話效率可能會下降但是結果也能出來(相當於要跨庫查詢了)
具體可以參考 Azure Cosmos DB 中的分割槽
CosmoDb的費用主要有2部分構成,一個是你儲存的資料大小,另一個就是你購買的RU
關於RU
CosmosDb的效能是以RU(request unit)作為計量單位,具體可以參考 Azure Cosmos DB 中的請求單位
RU看起來蠻複雜的,我怎麼知道要設定多少RU?
RU配置是可以支援動態配置的,你設定好一個你允許的最大RU,然後它平時會維持較低的RU運作,只有噹噹前RU不能滿足請求的前提下它會自動擴充直到你設定的最大值為止
不過這個功能有點小限制,就是隻能擴充10倍,比如你設定最大RU是10000,那麼它平常運作的最小值只能是1000,且自動擴充的話每RU的費用是比手動指定RU貴了50%
關於這個我自己感覺可能是先用自動RU來觀察下程式平日運作的模式,以後用Azure Function來自己調整可能會比較能節省費用
當前我們是全自動
2.Table Storage
上面那個CosmosDb是費用較高的高效能儲存
那麼這個就是費用較低的廉價大容量儲存
說起這個表儲存,大概2013年時候那會Microsoft Azure還叫Windows Azure的時候我就用過,對這玩意還是有點兒親切的,而這個服務在Azure裡也算是老字號了
Table Storage有3個特殊欄位Partitionkey,RowKey,Timestamp,其中Timestamp是自動生成不用管,重點是Partitionkey和RowKey
Partitionkey分割槽鍵
用資料庫分庫分表的思路來說就是你存在哪個庫裡
Table的效率和這個是強相關,一個好的Partitionkey的話應該滿足:絕大多數查詢都需要查這個,同一個分割槽下資料量不能太多,不要存在熱分割槽(比如同時大批量寫入,因此一般時間做分割槽就不是那麼好)
RowKey行鍵
用資料庫的角度理解相當於主鍵,但是由於PartitionKey的存在,所以是在同一個PartitionKey下RowKey不能重複,但是跨PartitionKey的話(相當於不同庫了)是可以重複的
Table的查詢效率最高效的是同時命中PartitionKey和RowKey,其次是隻命中PartitionKey,再次是隻命中RowKey,如果PartitionKey和RowKey都不命中則會相當緩慢
Table一個優勢在於它儲存比較廉價,世紀互聯版是4毛5一個GB你還想要什麼飛機?在我們內部廣泛用於各種亂七八糟的日誌儲存
成果
我們整個方案9月初上的,然後就迎來了國慶大考
就說CosmoDb
上圖是我們監控的情況
藍色線是當前系統實際使用的RU
橙色線是請求量
注:RU和請求並不是1:1的關係所以不用在意藍色線比橙色先更高,主要看趨勢
可以看到當請求量上漲的時候,RU(效能)也跟著上漲
要明白這是一個資料庫,資料庫也能做到和Web一樣彈性伸縮
當請求量下去的時候我們RU也能下去維持較低的執行成本
整體國慶期間整個系統運作平穩,新的架構能有效滿足我們業務需要
回想下我們這個場景是屬於典型瞬時併發高,常規併發較低的一個場景,如果用傳統自建資料庫來處理的話
起碼也要達到峰值80%以上的效能把?但是就算這樣也意味著絕大多數的閒時是浪費的,而高峰時刻也不是那麼夠用
而CosmosDb的特性則很好滿足我們的需要,通過動態調整RU的形式滿足我們波峰波谷的需要
後續
後面幾個規劃要演進的功能
1.嘗試使用Web App裡的Web Job替換掉VM裡的windows service,純粹為這個開個vm臺浪費了,而且vm真的一點都不cloud
2.考慮能否自己控制cosmosdb的縮放(通過Azure Function)以便實現更大倍率的自動伸縮以及降低成本
3.琢磨Azure Databricks看看能否從Data Lake Gen2裡存的資料分析出個啥