MetaProtocol Proxy 程式碼解讀:Connection Manager

語言: CN / TW / HK

ConnectionManager 是 MeataProtocol Proxy 的入口類。想要了解 MetaProtocol Proxy 的實現原理,可以從該類著手。

Envoy Network Filter 介紹

MetaProtocol Proxy 框架部分實現為 Envoy 中的一個 Network Filter。Enovy 通過 Listener 接收 Downstream 的連線,然後將收取到的 TCP 資料流傳送給 TCP filter chain 中的 MetaProtocol Proxy 處理。MetaProtocol Proxy 呼叫應用協議的 codec 實現進行解碼,然後再將解碼得到的元資料(Metadata)傳遞給限流、路由等七層 filter 進行處理。

Envoy Network Filter 機制:

Envoy 將從 Downstream 套接字中讀取到的資料放到 buffer 中,傳遞給 Network Filter chain 進行處理,由 Network Filter chain 處理後,一般會由 chain 中最後一個 filter 傳送給 Upstream。

注意:

  • 上圖來自於 Enovy 文件 ,圖中 Network filter chain 中最後一個 Filter 是 HCM(HTTP Connection Manager)。在 Aeraki Mesh 中,該 Network filter chain 中其實只有一個 filter,就是 MetaProtocol Proxy。

  • Listener 還有一個 Listener filter chain,用於在 Network filter chain 前進行一些公共邏輯的處理,例如通過 tls inspector 拿到 sni 和 application protocol,http 協議嗅探等。

在 Aeraki Mesh 中,MetaProtocol Proxy 是 Network Filter Chain 中唯一的 Filter。 MetaProtocol Proxy 處理 Downstream 資料後將通過 Router 這個 七層 Filter 將訊息傳送到 Upstream。

Envoy 中有兩種型別的 Network Filter:

  • ReadFilter:在收到 Downstream 的資料後,Enovy 會將資料中從 Downstream 套接字中讀出,並依次呼叫 ReadFilter 對這些資料進行處理。
  • WriteFilter:在向 Downstream 套接字寫入資料前,Envoy 會依次呼叫 WriteFilter 對資料進行處理後,再寫入 Downstream。

MetaProtocol Proxy 是一個 ReadFilter 型別的 Network Filter。(MetaProtocol Proxy 是 Network Filter Chain 中最後一個 Filter,直接接收 Upstream 的響應訊息並返回給 Downstream,因此沒有必要實現對 Response 資料進行處理的 WriteFilter。)

ReadFilter 介面包含下面的方法:

class ReadFilter {
public:

  // 將從 Downstream 連線中讀取到的資料傳遞給 filter 進行處理
  virtual FilterStatus onData(Buffer::Instance& data, bool end_stream) PURE;

  // 建立 Downstream 連線時會呼叫該方法
  virtual FilterStatus onNewConnection() PURE;

  // Enovy 傳遞一個 ReadFilterCallbacks 回撥介面給 ReadFilter。ReadFilter 可以通過該
  // 回撥介面從 Envoy 框架層獲取一些有用的資訊。例如該 ReadFilter 關聯的 Dowstream Connection。
  virtual void initializeReadFilterCallbacks(ReadFilterCallbacks& callbacks) PURE;
};

ReadFilterCallbacks 繼承了 NetworkFilterCallbacks ,MetaProtocol Proxy 的 ConnectionManager 主要使用到了 NetworkFilterCallbacks 中的 connection 方法來獲取 Downstream 連線。

class ReadFilterCallbacks : public virtual NetworkFilterCallbacks {
public:
  不重要,略過......
};
class NetworkFilterCallbacks {
public:
  
  // 通過該方法獲取 Network Filter 關聯的 Downstream Connection
  virtual Connection& connection() PURE;
};

Connection Manager 結構

Connection Manager 實現了三個重要的介面:

  • Network::ReadFilter 對 Downstream 連線中讀取到的資料進行處理,包括解碼和呼叫七層 filter。
  • MetaProtocolProxy::RequestDecoderCallbacks 為 MetaProtocol 的七層 filter 提供的回撥介面。
  • Network::ConnectionCallbacks Downstream 連接回調介面,主要用於連線事件(連線和斷開)和流控的處理。
@startuml
ConnectionManager <|-- ReadFilter
ConnectionManager <|-- ConnectionCallbacks
ConnectionManager <|-- RequestDecoderCallbacks

ReadFilter : FilterStatus onData(Buffer::Instance& data)
ReadFilter : FilterStatus onNewConnection()
ReadFilter : initializeReadFilterCallbacks(ReadFilterCallbacks& callbacks)

ConnectionCallbacks : onEvent(ConnectionEvent event)
ConnectionCallbacks : onAboveWriteBufferHighWatermark()
ConnectionCallbacks : onBelowWriteBufferLowWatermark()

RequestDecoderCallbacks : newMessageHandler()
RequestDecoderCallbacks : onHeartbeat(MetadataSharedPtr)
@enduml

Downstream 請求處理

在 Network::ReadFilter 介面的 onData 方式實現中對來自 Downstream 的資料進行處理。Envoy 會將 Downstream 連線中收到的資料放到一個 buffer 中,通過 回撥 onData 方法的引數傳遞給 Connection Manager。

Network::FilterStatus ConnectionManager::onData(Buffer::Instance& data, bool end_stream) {

  // 對來著 Downstream 連線中的資料進行分發處理
  dispatch();

  不重要,略過......

  // MetaProtocolProxy 是 Network Filter Chain 中的最後一個 Filter,不再繼續執行。
  return Network::FilterStatus::StopIteration;
}

MetaProtocol Proxy 在 onData 方法中呼叫 dispatch 方法,在 dispatch 方法中會迴圈呼叫 decoder 的 decode 方法。decoder 依次處理 buffer 中的請求,處理完的資料會被 decoder 從 buffer 中移除。如果一個請求未接收完整,或者 buffer 中的資料被全部處理完畢,decoder 會通過 underflow 標誌告訴 Connection Manager 需要更多資料。 Connection Manager 會退出本次 onData 處理,envoy 收到更多資料後將再次呼叫 Connection manager 的 onData 方法。

void ConnectionManager::dispatch() {
  不重要,略過......

  try {
    bool underflow = false;
    while (!underflow) {
      decoder_->onData(request_buffer_, underflow);
    }
    return;
  } 

  不重要,略過......
}

Envoy 流控機制

Envoy 為 TCP filter 提供了一個 流控機制 。其原理是為 TCP filter 的 buffer 設定了一個最大值(水位線),並在 buffer 中實際的資料大小超過該值,或者資料大小從該值之上回落到到該值以內時通過 ConnectionCallbacks 回撥通知 TCP filter。

MetaProtocol Proxy 實現了 ConnectionCallbacks 介面,並在 ReadFilterinitializeReadFilterCallbacks 回撥方法中向 Downstream connection 註冊了該回調。

void ConnectionManager::initializeReadFilterCallbacks(Network::ReadFilterCallbacks& callbacks) {
  read_callbacks_ = &callbacks;
  // 向 Downstream connection 註冊流控相關的回撥方法
  read_callbacks_->connection().addConnectionCallbacks(*this);
  read_callbacks_->connection().enableHalfClose(true);
  read_callbacks_->connection().setBufferLimits(BufferLimit);
}

當 buffer 中的資料超過水位線時,Envoy 通過 onAboveWriteBufferHighWatermark 回撥通知到 MetaProtocol Proxy。該回調說明此時 MetaProtocol Proxy 的處理速度慢於 Downstream 的資料傳送速度,造成資料積壓。此時 MetaProtocol Proxy 會呼叫 connection.readDisable(true) 方法,要求 Envoy 暫停從 Downstream 中讀取資料,將資料保留在核心的 TCP 接收 buffer 中,最終通過 TCP 的擁塞控制對 Downstream 造成背壓(Backpressure),降低 Downstream 的傳送速率。

當 buffer 中的資料被 MetaProtocol Proxy 處理,低於水位線後,Envoy 通過 onBelowWriteBufferLowWatermark 回撥通知到 MetaProtocol Proxy。此時 MetaProtocol Proxy 會呼叫 connection.readDisable(false) 方法,要求 Envoy 恢復從 Downstream 中讀取資料。

void ConnectionManager::onAboveWriteBufferHighWatermark() {
  read_callbacks_->connection().readDisable(true);
}

void ConnectionManager::onBelowWriteBufferLowWatermark() {
  read_callbacks_->connection().readDisable(false);
}

擴充套件閱讀