在AIGC、視頻處理等複雜的模型推理情境中,由於推理耗時較長,存在長連線逾時導致請求失敗或執行個體負載不均衡等問題,不適用於同步推理情境。為瞭解決這些問題,PAI提供了非同步推理服務,支援通過訂閱或輪詢的方式來擷取推理結果。本文為您介紹如何使用非同步推理服務。
背景資訊
功能介紹
非同步推理
對於即時性要求比較高的線上推理情境,通常使用同步推理,即用戶端發送一個請求,同步等待結果返回。
對於推理耗時比較長或者推理時間無法確定的情境,同步等待結果會帶來HTTP長串連斷開、用戶端逾時等諸多問題。通常需要使用非同步推理來解決上述問題,即請求發送至服務端,用戶端不再同步等待結果,而是選擇定期去查詢結果,或通過訂閱的方式在請求計算完成後等待服務端的結果推送。
佇列服務
對於准即時推理情境,比如短視頻、視頻流或語音流的處理或計算複雜度很高的影像處理等情境,不需要即時返回結果,但需要在指定時間內擷取推理結果,該情境存在以下幾類問題:
負載平衡演算法不能選擇round robin演算法,需要根據各個執行個體的實際負載情況進行請求的分發。
執行個體異常,該執行個體尚未完成計算的任務需要重新分配給其他執行個體進行計算。
PAI推出了一套獨立的佇列服務架構,用來解決以上請求分發的問題。
實現原理
在建立非同步推理服務時,會在服務內部整合兩個子服務,分別是推理子服務和隊列子服務。隊列子服務擁有兩個內建的訊息佇列,即輸入(input)隊列和輸出(sink)隊列。服務要求會先發送到隊列子服務的輸入隊列中,推理子服務執行個體中的EAS服務架構會自動訂閱隊列以流式地方式擷取請求資料,調用推理子服務中的介面對收到的請求資料進行推理,並將響應結果寫入到輸出隊列中。
當輸出隊列滿時,即無法向輸出隊列中寫入資料時,服務架構也會停止從輸入隊列中接收資料,避免無法將推理結果輸出到輸出隊列。
如果您不需要輸出隊列,例如將推理結果直接輸出到OSS或者您自己的訊息中介軟體中,則可以在同步的HTTP推理介面中返回空,此時輸出隊列會被忽略。
建立一個高可用的隊列子服務,用於接收用戶端發送的請求。推理子服務的執行個體根據自己所能承受的並發度來訂閱指定個數的請求,隊列子服務會保證每個推理子服務執行個體上處理的請求不會超過訂閱的視窗大小,通過該方式來保證不會存在執行個體過載,最終將訂閱或查詢的資料返回給用戶端。
說明比如每個推理子服務執行個體只能處理5路語音流,則從隊裡子服務中訂閱訊息時,將window size配置為5。當推理子服務執行個體處理完一路語音流後將結果commit,隊列子服務會為推理子服務執行個體重新推送一路新的語音流,保證該執行個體上處理的語音流最多不超過5路。
隊列子服務通過檢測推理子服務執行個體的串連狀態,對其進行健全狀態檢查,如果因該執行個體異常導致串連斷開,隊列子服務會將該執行個體標記為異常,已經分發給該執行個體進行處理的請求會重新推送給其他正常執行個體進行處理,以此來保證在異常情況下請求資料不會丟失。
建立非同步推理服務
在建立非同步推理服務時,為了方便您的使用和理解,系統會自動建立和非同步推理服務同名的服務分組。同時,隊列子服務會隨非同步推理服務自動建立,並整合到非同步推理服務內。隊列子服務預設啟動1個執行個體,並根據推理子服務的執行個體數量動態伸縮,但最多不超過2個執行個體,每個執行個體預設配置為1核和4 GB記憶體。如果隊列子服務的執行個體數的預設配置不能滿足您的需求,請參照隊列子服務參數配置及說明進行配置。
EAS的非同步推理服務可以實現同步推理邏輯到非同步推理的轉換,支援以下兩種部署方式:
通過控制台部署服務
進入部署服務頁面,並配置以下關鍵參數,其他參數配置詳情,請參見服務部署:控制台。
部署方式:選擇鏡像部署服務或模型+processor部署服務。
非同步服務:開啟非同步服務開關。
參數配置完成後,單擊部署。
通過eascmd用戶端部署服務
準備服務的設定檔service.json。
部署方式為模型+processor部署服務。
{ "processor": "pmml", "model_path": "http://example.oss-cn-shanghai.aliyuncs.com/models/lr.pmml", "metadata": { "name": "pmmlasync", "type": "Async", "cpu": 4, "instance": 1, "memory": 8000 } }
其中關鍵參數說明如下。其他參數配置說明,請參見服務模型所有相關參數說明。
type:配置為Async,即可建立非同步推理服務。
model_path:替換為您的模型的地址。
部署方式為鏡像部署服務。
{ "metadata": { "name": "image_async", "instance": 1, "rpc.worker_threads": 4, "type": "Async" }, "cloud": { "computing": { "instance_type": "ecs.gn6i-c16g1.4xlarge" } }, "queue": { "cpu": 1, "min_replica": 1, "memory": 4000, "resource": "" }, "containers": [ { "image": "eas-registry-vpc.cn-beijing.cr.aliyuncs.com/pai-eas/chat-llm-webui:3.0.1", "script": "python webui/webui_server.py --port=8000 --model-path=Qwen/Qwen-7B-Chat", "port": 8000 } ] }
其中關鍵參數說明如下。其他參數配置說明,請參見服務模型所有相關參數說明。
type:配置該參數為Async,即可建立非同步推理服務。
instance:推理子服務的執行個體數量,不包含隊列子服務的執行個體。
rpc.worker_threads:為非同步推理服務中EAS服務架構的線程數,該參數與訂閱隊列資料的視窗大小一致。線程數設定為4,即一次最多隻能從隊列中訂閱4條資料,在這4條資料處理完成前,隊列子服務不會給推理子服務推送新資料。
例如:某視頻流處理服務,單個推理子服務執行個體一次只能處理2條視頻流,則該參數可以設定為2,隊列子服務最多將2個視頻流的地址推送給推理子服務,在推理子服務返回結果前,不會再推送新的視頻流地址。如果推理子服務完成了其中一個視頻流的處理並返回結果,則隊列子服務會繼續再推送一個新的視頻流地址給該推理子服務的執行個體,保證一個推理子服務的執行個體最多同時處理不超過2路視頻流。
建立服務。
您可以登入eascmd用戶端後使用create命令建立非同步推理服務,如何登入eascmd用戶端,請參見下載並認證用戶端,使用樣本如下。
eascmd create service.json
訪問非同步推理服務
如上文介紹,系統會預設為您建立和非同步推理服務同名的服務分組,因分組內的隊列子服務擁有分組流量入口,您可以直接通過下述路徑訪問隊列子服務,詳情請參見訪問佇列服務。
地址類型 | 地址格式 | 樣本 |
輸入隊列地址 |
|
|
輸出隊列地址 |
|
|
管理非同步推理服務
您可以像管理普通服務一樣管理非同步推理服務,該服務的子服務會由系統自動管理。比如,當您刪除非同步推理服務時,隊列子服務和推理子服務都將被同時刪除。或者當您更新推理子服務時,隊列子服務維持不變以擷取最大的可用性。
由於採用了子服務架構,雖然您為非同步推理子服務配置了1個執行個體,執行個體列表中仍會額外顯示一個隊列子服務執行個體。
非同步推理服務的執行個體數量指的是推理子服務執行個體的數量,隊列子服務的執行個體數量會隨著推理子服務的執行個體數量自動變化。比如,當您將推理子服務執行個體數量擴容到3時,隊列子服務的執行個體數量擴容到了2。
兩個子服務間的執行個體數量配比規則如下:
當非同步推理服務被停止,則隊列子服務和推理子服務的執行個體數量均會縮容到0,這時看到的執行個體列表為空白。
當推理子服務的執行個體數量為1時,隊列子服務的執行個體數量也將為1,除非您配置了隊列子服務的參數。
當推理子服務的執行個體數量超過2時,隊列子服務的執行個體數量將保持為2,除非您配置了隊列子服務的參數。
當您為非同步推理服務配置了自動擴縮容功能,且配置了最小的執行個體數量為0,則當推理子服務縮容到0時,隊列子服務將保持1個執行個體待命。
隊列子服務參數配置及說明
大多數情況下,隊列子服務使用預設配置即可正常使用。如果有特殊需求,您可以通過在JSON檔案中最外層的queue配置塊來配置隊列執行個體。樣本如下:
{
"queue": {
"sink": {
"memory_ratio": 0.3
},
"source": {
"auto_evict": true,
}
}
下面介紹具體的配置項。
配置隊列子服務資源
隊列子服務的資源會預設按照metadata中的欄位進行配置,但是在有些使用情境下,您需要參考本章節,對隊列子服務的資源進行單獨配置。
通過queue.resource聲明隊列子服務所使用的資源群組。
{ "queue": { "resource": eas-r-slzkbq4tw0p6xd**** # 預設跟隨推理子服務資源群組。 } }
隊列子服務預設跟隨推理子服務的資源群組。
當您需要使用公用資源群組部署隊列子服務時,可以聲明resource為空白字串(""),這在您的專屬資源群組CPU和記憶體不充足時非常有用。
說明推薦使用公用資源群組部署隊列子服務。
通過queue.cpu和queue.memory聲明每個隊列子服務執行個體所使用的CPU(單位:核心數)和記憶體大小(單位:MB)。
{ "queue": { "cpu": 2, # 預設值為1。 "memory": 8000 # 預設值為4000。 } }
如果您沒有進行資源配置,隊列子服務將按照1 CPU核、4 GB記憶體進行預設配置。這可以滿足大多數情境的需求。
重要如果您的訂閱者(比如推理子服務執行個體的數量)數量超過200時,建議將CPU核心數配置為2核以上。
不建議在生產環境中縮小隊列子服務的記憶體配置。
通過queue.min_replica配置隊列子服務執行個體的最小數量。
{ "queue": { "min_replica": 3 # 預設為1。 } }
在使用非同步推理服務時,隊列子服務執行個體的數量將根據推理子服務執行個體的運行時數量自動調整,預設的調整區間為
[1, min{2, 推理子服務執行個體的數量}]
。特殊情況下,如果配置非同步推理服務的自動擴縮容規則並允許將執行個體數量縮小到0時,將自動保留1個隊列子服務執行個體。您也可以通過queue.min_replica調整最小保留的隊列子服務執行個體數量。說明增加隊列子服務執行個體的數量可以提高可用性,但不能提高隊列子服務的效能。
配置隊列子服務功能
隊列子服務擁有多項可配置的功能,您可以通過以下配置方法進行調整。
通過queue.sink.auto_evict或者queue.source.auto_evict分別配置輸出/輸入隊列自動資料驅逐功能。
{ "queue": { "sink": { "auto_evict": true # 輸出隊列開啟自動驅逐,預設為false。 }, "source": { "auto_evict": true # 輸入隊列開啟自動驅逐,預設為false。 } } }
預設情況下隊列子服務的自動資料驅逐功能處於關閉狀態,如果您的隊列已滿將無法繼續輸入資料。在某些情境下,如果您允許資料在隊列中溢出,可以選擇開啟自動資料驅逐功能,隊列將自動驅逐最老的資料以允許新資料寫入。
通過queue.max_delivery配置最大投遞次數。
{ "queue": { "max_delivery": 10 # 最大投遞次數為10,預設值:5。當配置為0時,最大投遞次數關閉, 資料可以被無限次投遞。 } }
當單條資料的嘗試投遞次數超過設定閾值時,該資料將被視為無法處理,並將其標記為死信。詳情請參見隊列執行個體的死信策略。
通過queue.max_idle配置資料的最大處理時間。
{ "queue": { "max_idle": "1m" # 配置單條資料最大處理時間長度為1分鐘,如果超過該時間將被投遞給其它訂閱者, 投遞完畢後投遞次數+1。預設值為0,即沒有最大處理時間長度。 } }
樣本中配置的時間長度為1分鐘,支援多種時間單位,如h(小時)、m(分鐘)、s(秒)。如果單條資料處理的時間超過了這裡配置的時間長度,則有兩種可能:
如果未超過queue.max_delivery設定的閾值,該條資料會被投遞給其他訂閱者。
如果已超過queue.max_delivery設定的閾值,該條資料將會被執行死信策略。
通過queue.dead_message_policy配置死信策略。
{ "queue": { "dead_message_policy": "Rear" # 枚舉值為Rear(預設值)或者Drop, Rear即為放入隊列末尾,Drop將該條資料刪除。 } }
配置隊列最大長度或最巨量資料體積
隊列子服務的最大長度和最巨量資料體積是此消彼長的關係,計算關係如下所示:
隊列子服務執行個體記憶體是固定的,因此如果調整單條資料最大體積,則會導致該隊列最大長度減小。
在4 GB記憶體的預設配置下,由於最巨量資料體積預設為8 KB,則輸入輸出隊列均可以存放230399條資料,如果您需要在隊列子服務中存放更多資料項目,可以參考上文中的記憶體配置,將記憶體大小按照需要提高。系統將佔用總記憶體的10%。
對於同一個隊列,不能同時配置最大長度和最巨量資料體積。
通過queue.sink.max_length或者queue.source.max_length分別配置輸出隊列/輸入隊列的最大長度。
{ "queue": { "sink": { "max_length": 8000 # 配置輸出隊列最大長度為8000條資料。 }, "source": { "max_length": 2000 # 配置輸入隊列最大長度為2000條資料。 } } }
通過queue.sink.max_payload_size_kb或者queue.source.max_payload_size_kb分別配置輸出隊列/輸入隊列單條資料最巨量資料體積。
{ "queue": { "sink": { "max_payload_size_kb": 10 # 配置輸出隊列單條資料最大體積是10 KB, 預設8 kB。 }, "source": { "max_payload_size_kb": 1024 # 配置輸入隊列單條資料最大體積是1024 KB(1MB), 預設是8 kB。 } } }
配置記憶體配置傾斜
通過queue.sink.memory_ratio來調整輸入輸出兩個隊列佔用的記憶體大小。
{ "queue": { "sink": { "memory_ratio": 0.9 # 配置輸出隊列記憶體佔比,預設值為0.5。 } } }
說明預設配置下,輸入隊列和輸出隊列均分隊列子服務執行個體的記憶體。如果您的服務需要輸入文本、輸出圖片,並期望在輸出隊列存放更多資料,則可以將queue.sink.memory_ratio相應提高;相反,如果您期望輸入圖片、輸出文本,則可以將queue.sink.memory_ratio相應減小。
配置水平自動擴縮容
非同步推理服務水平自動擴縮容配置方法,請參見自動擴縮容。