天天看點

與慢速裝置通訊異步化方案

與慢速裝置通訊異步化方案

一般業務系統在業務線程或程序中,直接調用它們提供的API進行通路,如下圖所示:

與慢速裝置通訊異步化方案

結果造成了以下兩大問題:

1) 性能低:同步阻塞方式;

2) 可靠性差:業務系統和慢速裝置強耦合。

性能低,是因為慢速裝置不能快速響應傳回結果;可靠性差,是因為業務系統和慢速裝置沒有解耦合,比如當慢速裝置的API因異常被長時間挂起時,會導緻業務系統的線程或程序也一同被挂起。

要解決性能低,就需要異步化,也就是業務系統可異步通路慢速裝置;要解決可靠性差,就需要兩者間解耦合。

下圖所示的方案,針對這兩個問題進行了優化,即實作了異步化,也做到了解耦合:

與慢速裝置通訊異步化方案

以MySQL為例,業務系統在向MySQL發起SQL操作時,不再直接調用MySQL的API,而是将SQL放入到隊列中,然後立即傳回。

針對每一個MySQL執行個體,都會有一個侍服線程,與它建立一對一對綁定關系,也就是這個線程專門為它服務的,如果有多個MySQL執行個體,則有相應個數的侍服線程,侍服線程不會跨MySQL執行個體。

侍服線程會實時監聽隊列,當有資料時,立即取出來,然後調用MySQL的API執行SQL操作,這個過程是同步的,侍服線程會阻塞,直到MySQL傳回結果。

對于MySQL傳回的結果,有兩種業務系統的方式:一是由侍服線程回調業務,對結果的處理權在侍服線程;二是将結果存入結果隊列,然後業務可以以epoll的方式取出結果,這種方式可以讓對結果的處理權回歸到業務線程。

1) 侍服線程回調業務實作方式

下面以僞代碼方式,展現實作方式:

void mysql_thread()

{

while (true)

sql = _sql_queue.pop(); // 阻塞等待隊列中有SQL,如果有,則取出SQL

result = mysql.query(sql); // 調用MySQL接口,進行SQL操作,結果存在result中

service->callback(result); // 回調業務接口,讓業務對結果進行處理

}

2) 以epoll的方式取出結果

這種方式讓對結果的處理權回歸到業務線程。實作方式非常簡單,隻需要結果隊列是可以epoll的即可,通常可以借助eventfd或pipe來包裝一個隊列,讓這隊列可以epoll監聽。侍服線程隻需要将結果存入結果隊列,然後會自動喚醒處于等待狀态的epoll。

異步化方案不能支援事務,關鍵原因是事務和MySQL連接配接有綁定關系,同一個連接配接不支援多個并發的事務。