mTCP
マルチコアシステムのユーザーモードネットワークプロトコルスタックです
カーネル状態プロトコルスタックの欠陥
インターネットの発達により、ユーザーのネットワークアプリケーションに対するパフォーマンス要件はますます高くなっています。人々は常にCPU処理能力の向上とコア数の追加に取り組んでいますが、これによりネットワークデバイスのスループットが直線的に増加することはありません。理由の1つは、カーネルプロトコルスタックがネットワークパフォーマンスを制限するボトルネックになっていることです。
相互に排他的なロックのオーバーヘッド
相互に排他的なロックは、マルチコアプラットフォームのパフォーマンスの最大のキラーです。可能な限り高い同時実行性を実現するために、現在のサーバー側アプリケーションは通常、マルチスレッド方式を使用して、クライアントがサービスポートに開始した接続要求を監視します。まず、これにより、複数のスレッド間でaccept
キューへの相互排他アクセスが発生します。第2に、スレッド間のファイル記述子スペースへの相互に排他的なアクセスも、パフォーマンスの低下を引き起こす可能性があります。
メッセージによる非効率的な処理
カーネルのプロトコルスタックは、データパケットを1つずつ処理するため、バッチ処理の機能がありません。
頻繁なシステムコールによる負担
頻繁に短い接続を行うと、多数のユーザーモード/カーネルモードの切り替えが発生し、頻繁なコンテキストの切り替えにより、Cache Miss
ユーザーモードプロトコルスタックの導入
ユーザーモードのプロトコルスタック、つまり、カーネルによって最初に完了されたプロトコルスタックの機能は、ユーザーモードの実装に移されます。
Packet IO
(DPDK
たとえば)既存の高性能ライブラリを使用してコアをバイパスすることにより、ユーザーモードプロトコルスタックは、メッセージ処理がないときにユーザーモードとカーネルモードを切り替えることなく、ネットワークメッセージを直接送受信できます。また、ユーザーモードで完全に実装されているため、スケーラビリティや移植性が向上しています。
mTCPの概要
mTCP
ユーザーモードプロトコルスタックライブラリの実装として、そのアーキテクチャを次の図に示します。
mTCP
関数ライブラリの形式でアプリケーションプロセスにリンクされ、下部は他のユーザーモードPacket IO
ライブラリを使用します。
要約するとmTCP
、次の特性があります。
- 優れたマルチコアスケーラビリティ
- バッチメッセージ処理メカニズム
- クラス
epoll
イベント駆動型システム BSD
スタイルsocket API
- 複数のユーザーモード
Packet IO
ライブラリをサポート - トランスポート層プロトコルのみサポート
TCP
マルチコアのスケーラビリティ
共有リソースへのマルチスレッドアクセスによるオーバーヘッドを回避するため。mTCP
すべてのリソース(などflow pool
socket buffer
)はコアに従って割り当てられます。つまり、各コアには独自の共有があります。そして、これらのデータ構造はcache
整合しています。
上記のアーキテクチャ図からわかるように、mTCP
ユーザーアプリケーションスレッド(など)ごとにThread0
追加のスレッド(mTCP thread0
)を作成する必要があります。これら二つのスレッドが同じコア(セットにバインドされているCPU
使用最大化するために、親和性)CPU
のをCache
。
バッチメッセージ処理メカニズム
スレッドは内部で新しく追加さmTCP
れるため、ユーザースレッドにメッセージを送信する場合、スレッド間の通信は不可避であり、スレッド間の通信はシステムコールよりもはるかにコストがかかる可能性があります。したがってmTCP
、使用される方法はメッセージのバッチ処理であり、各メッセージの平均処理コストははるかに小さくなります。
クラスepoll
イベント駆動型システム
使用に慣れてepoll
、プログラマーのプログラミングmTCP
あまりにも優しい、あなたはそれを行う必要が置いてあるepoll_xxx()
にmtcp_epoll_xxx()
BSDスタイルのソケットAPI
同様に、ちょうどに必要なアプリケーションBSD
のスタイルは、Socket API
が先行するmtcp_
など、十分なmtcp_accept()
複数のユーザーモードのパケットIOライブラリをサポート
ではmTCP
、 Packet IO
ライブラリはとも呼ばれるIO engine
現在のバージョン(バージョン2.1)mTCP
をサポートDPDK
(デフォルト)、 、 、 netmap
4種類。onvm
psio
IO engine
mTCPの実装の詳細
スレッドモデル
前述のように、mTCP
ユーザーアプリケーションスレッドごとに個別のスレッドを作成する必要があります。実際には、各ユーザーアプリケーションスレッドが次のインターフェイスを明示的に呼び出して完了する必要があります。
mctx_t mtcp_create_context(int cpu);
この後、各mTCP
スレッドは独自のスレッドに入り、Main Loop
スレッドの各ペアは、mTCP
作成されたバッファーを介してデータプレーンと通信Queue
し、一連の
各mTCP
スレッドには、リソースの管理を担当する構造struct mtcp_manager
があります。スレッドが初期化されると、リソースの作成が完了します。これらのリソースは、このコアのこのスレッドに属し、接続の4倍の情報の保存flow table
、ソケットリソースプールを含みますsocket pool
ソケットの監視listener hashtable
、送信方向の制御構造sender
など
ユーザーモードソケット
純粋なユーザーモードプロトコルスタックであるため、すべてのソケット操作はglibc
そのセットを使用していません。ソケットmTCP
を使用socket_map
すると、カーネルセットよりもはるかにシンプルに見えます。
struct socket_map
{
int id;
int socktype;
uint32_t opts;
struct sockaddr_in saddr;
union {
struct tcp_stream *stream;
struct tcp_listener *listener;
struct mtcp_epoll *ep;
struct pipe *pp;
};
uint32_t epoll; /* registered events */
uint32_t events; /* available events */
mtcp_epoll_data_t ep_data;
TAILQ_ENTRY (socket_map) free_smap_link;
};
socketype
このソケット構造のタイプを表すもので、その値に応じて、後続の共用体のポインターは別の構造として解釈できます。でmTCP
、通常、ファイル記述子の下部もこのようなsocket_map
enum socket_type
{
MTCP_SOCK_UNUSED,
MTCP_SOCK_STREAM,
MTCP_SOCK_PROXY,
MTCP_SOCK_LISTENER,
MTCP_SOCK_EPOLL,
MTCP_SOCK_PIPE,
};
ユーザーモードEpoll
mTCP
epoll
カーネルのバージョンと比較して、実装も単純化されており、制御構造はstruct mtcp_epoll
次のとおりです。
struct mtcp_epoll
{
struct event_queue *usr_queue;
struct event_queue *usr_shadow_queue;
struct event_queue *mtcp_queue;
uint8_t waiting;
struct mtcp_epoll_stat stat;
pthread_cond_t epoll_cond;
pthread_mutex_t epoll_lock;
};
内部に3つのキューを格納し、3種類のイベントが発生するソケットを格納します。
MTCP_EVENT_QUEUE
イベントは、プロトコルスタックのような、生成されたことを示しているLISTEN
ソケット状態accept
、ESTABLISH
ソケットが読み取り可能なデータを有しています。USR_EVENT_QUEUE
ユーザーのアプリケーションイベントを表します。現在はのみPIPE
です。USR_SHADOW_EVENT_QUEUE
ユーザーモードがまだ処理ESTABLISH
されておらず、最後のソケットデータが読み取られていないなど、生成されたプロトコルスタックイベントをシミュレートする必要があることを示します。
TCPストリーム
mTCP
Use tcp_stream
は、TCP
ストリームのクワッド情報、TCP
接続ステータス、プロトコルパラメータ、およびバッファの場所が格納されるエンドツーエンドのストリームを表します。tcp_stream
各スレッドに保存されているflow table
中
typedef struct tcp_stream
{
socket_map_t socket;
// code omitted...
uint32_t saddr; /* in network order */
uint32_t daddr; /* in network order */
uint16_t sport; /* in network order */
uint16_t dport; /* in network order */
uint8_t state; /* tcp state */
struct tcp_recv_vars *rcvvar;
struct tcp_send_vars *sndvar;
// code omitted...
} tcp_stream;
送信コントローラー
mTCP
使用struct mtcp_sender
の管理は、方向を送る、この構造が存在する場合、各インタフェースあたりのスレッドで終了2番目のmTCP
スレッドは、そこ。3つのネットワークインタフェース、その後の合計がある。6送信コントローラ
struct mtcp_sender
{
int ifidx;
/* TCP layer send queues */
TAILQ_HEAD (control_head, tcp_stream) control_list;
TAILQ_HEAD (send_head, tcp_stream) send_list;
TAILQ_HEAD (ack_head, tcp_stream) ack_list;
int control_list_cnt;
int send_list_cnt;
int ack_list_cnt;
};
各コントローラーには3つのキューが含まれ、キュー内の要素は tcp_stream
Control
キュー:メッセージなど、送信される制御メッセージのバッファリングを担当しSYN-ACK
ますSend
キュー:送信されたデータパケットのバッファリングを担当ACK
キュー:純粋なACK
メッセージのバッファリングを担当
例:サーバーTCP接続確立プロセス
サーバーアプリケーションがアプリケーションスレッドepoll
でソケットとリスニングソケットを作成し、このリスニングソケットを追加epoll
するとします。アプリケーションプロセスはブロックされmtcp_epoll_wait()
、mTCPスレッドは独自にmain Loop
ループします。
- マシンはクライアントによって開始された接続を受信し、最初の
SYN
メッセージを受信します。mTCP
スレッドはメッセージmain Loop
をIO
受信するために最下層を読み取ります。このスレッドflow table
で検索を試行した後、クワッドIDのフロー情報がないことが判明したため、新しいクワッドIDtcp stream
が作成されます。 - このストリームを
Control
キューに書き込みます。状態はTCP_ST_SYNRCVDに切り替えられTCP
、最初のハンドシェイクが受信されたことを示します mTCP
スレッドmain Loop
はControl
キューを読み取り、このストリームだけが存在することを見つけたので、それを取り出し、SYN-ACK
メッセージを組み立てて、それを最下層に送信します。IO
mTCP
スレッドmain Loop
は下部のピアが受信したストリームのACK
ハンドシェイク情報を読み取り、状態をTCP_ST_ESTABLISHED(TCPスリーウェイハンドシェイク完了)に変更してから、このストリームをリスニングソケットのaccept
キューにプラグインします。- リスニングソケットが追加されているので
epoll
、そのmTCP
スレッドはなりMTCP_EVENT_QUEUE
に挿入されたイベントの電子キュー。struct mtcp_epoll
mtcp_queu
- この時点で、ユーザースレッド
mtcp_epoll_wait()
はイベントmtcp_epoll_accept()
をControl
読み取り、次に呼び出しを行ってキューから接続情報を読み取り、接続の確立を完了することができます。
参考文献
mTCP:マルチコアシステム向けの高度にスケーラブルなユーザーレベルのTCPスタック
mTCP Github Repo
拡張データ
カーネルプロトコルスタック最適化スキーム FastSocket
別のユーザーモードプロトコルスタック Fスタック