HAProxy研究ノート--TCP接続処理フロー

7643 ワード

本文はHAProxy 1.5-dev 7バージョンに基づいています.
ディレクトリ1.キーデータ構造session 2.関連初期化
2.1 TCP接続を初期化する方法2.2.listener を初期化する
2.3.登録済みプロトコルのすべてをバインドするlisteners 2.4.登録済みプロトコルのすべてのlisteners を有効にする
3.TCP接続の処理フロー
3.1新規接続受付3.2.TCP接続上の受信イベント3.3.TCP接続上の送信イベント3.4.http要求の処理1.キーデータ構造sessionhaproxyは要求を処理するコアデータ構造をstruct sessionとし、本文ではこのデータ構造を分析しない.
業務の処理の観点から、sessionに対する理解を簡単に紹介します.
haproxyはclientの接続を受信するごとにsession構造を作成します.この構造は接続の処理に伴って、接続がオフになるまで、sessionは解放されます.
haproxy他のデータ構造は、引用によってsessionと関連づけられることが多いです.
一つの業務セッションには二つのTCP接続があります.一つはclientからhaproxy、もう一つはhaproxyからバックエンドserverです.また、sessionは通常、taskに対応していますが、最終的にはhaproxyはtaskを通じてスケジュールを行うために使われます.
2.関連初期化
haproxy正式な処理要求の前に、一連の初期化動作があります.ここでは、処理に関するいくつかの初期化を紹介し、要求する.
2.1.TCP接続を初期化する方法
TCPプロトコルを初期化処理する関連データ構造は、主にsocketに関する方法に関する声明である.詳しくは次のプロトを見てください.tcpv 4の初期化:
static struct protocol proto_tcpv4 = {
	.name = "tcpv4",
	.sock_domain = AF_INET,
	.sock_type = SOCK_STREAM,
	.sock_prot = IPPROTO_TCP,
	.sock_family = AF_INET,
	.sock_addrlen = sizeof(struct sockaddr_in),
	.l3_addrlen = 32/8,
	.accept = &stream_sock_accept,
	.read = &stream_sock_read,
	.write = &stream_sock_write,
	.bind = tcp_bind_listener,
	.bind_all = tcp_bind_listeners,
	.unbind_all = unbind_all_listeners,
	.enable_all = enable_all_listeners,
	.listeners = LIST_HEAD_INIT(proto_tcpv4.listeners),
	.nb_listeners = 0,
};
2.2.初期化listener
listenerは名前の通り、監聴に関するロジックを処理するために用いられます.
haproxy解析bind配置時にlistenerのプロトメンバーに値を与えます.関数コールの流れは以下の通りです.
cfgparse.c
-> cfg_parse_listen
-> str2listener
-> tcpv4_add_listener
-> listener->proto = &proto_tcpv4;
ここで初期化するのはlistener処理socketのいくつかの方法です.haproxy受信client新規接続の入口関数はprotocol構造体におけるaccpet方法であるべきと推測される.tcpv 4にとってはstreamです.sock_accept()関数この関数は1.5-dev 19にlistener_と改名されました.accept()これは後の話です.
listenerの他の初期化
cfgparse.c
-> check_config_validity
-> listener->accept = session_accept;
   listener->frontend = curproxy; (   frontend  ,     : curproxy->accept = frontend_accept)
   listener->handler = process_session;
全体のhaproxyプロファイル解析が完了し、listenerも初期化されました.いくつかのaccept方法の設計ロジックを簡単に整理できます.
ストリームsock_accept():新規TCP接続を受信し、listener自身のacceptメソッドsession_をトリガする.accept()session_accept():sessionを作成し、sessionメンバーの初期化を行い、frontendのaccept方法front_を呼び出します.accetp()fron ted_accept():この関数は主にsessionフロントエンドのTCP接続の初期化を担当しています.socket設定、log設定、セッション部分の初期化を含みます.
以下、TCP新規接続処理手順を分析します.基本的にはこの3つの関数の分析です.
2.3.登録済みプロトコルのすべてのlistenersをバインドする
haproxy.c 
-> protocol_bind_all 
-> all registered protocol bind_all
-> tcp_bind_listeners (TCP)
-> tcp_bind_listener 
-> [ fdtab[fd].cb[DIR_RD].f = listener->proto->accept ]
この関数の指針はproto_を指します.tcpv 4構造体のacceptメンバー、すなわち関数stream ausock_accept
2.4.登録済みプロトコルのすべてのlistenersを有効にする
すべてのlistenersのfdをpolling listsに追加します.enabale_all->all registered protocol enableall->enable_all_listeners(TCP)->enable_listener関数はLI_になります.LISTENのlistenerの状態をLI_に変更します.READYは、Cur pollerのset方法を呼び出して、例えばsepollを使うと、__u u uを呼び出します.fd_セット
3.TCP接続の処理フロー
3.1新規接続の受付
前のいくつかの態様の分析は、主に要求が来たときに、処理中の実際の関数呼び出し関係を明らかにするためである.以下はTCPの建設過程を分析する.
haproxy.c 
-> run_poll_loop 
-> cur_poller.poll 
-> __do_poll (         sepoll,    ev_sepoll.c    poll   ) 
-> fdtab[fd].cb[DIR_RD].f(fd) (TCP            stream_sock_accept )
-> stream_sock_accept
->    global.tune.maxaccept                accept,      l->accept(),  listener   accept    session_accept
-> session_accept
session_acceptは主に以下の機能を完成します.
pool_を呼び出しますalloc 2は、session構造を割り当てる.
task_を呼び出しますnew新しいタスクを割り当てます.
新たに割り当てられたセッションをグローバルsessionsチェーンに追加するsessionとtaskの初期化、いくつかの重要なメンバーの初期化は以下の通りです.
t->process=l->handler:つまりt->processはprocessを指します.セッションt->context=s:タスクのコンテキストがsession に向けられます.
s->listener=l:sessionのlistenerメンバーは現在のlistener を指します.
s->si[]の初期化、acceptシステム呼び出しが戻ったcfdなどを記録する初期化s->txn s->reqとs->repのそれぞれにメモリを割り当て、対応する初期化を行う.
s->req=pool_alloc 2(pool 2 bauffer)s->rep=pool_alloc 2(pool 2 bauffer)コードから見れば、tune.bufsize+size of struct bufferサイズはそれぞれ独立して割り当てられたメモリであるべきです.
新しい接続cfdのいくつかの初期化
cfdは非ブロッキングに設定されている.
fdtab[]にcfdを追加し、cfgを接続するreadとwriteを新規に登録する方法fdtab[cfd].cb[DIRD].f=l->proto->readを設定し、cfdのreadの関数l->proto->readを設定し、TCPがstream_であることに対応する.sock_read、バッファを読んでs->reqを指して、fdtab[cfd].cb[DIRuWR].f=l->proto->writeを設定して、cfdのwrite関数l->proto->writeを設定して、TCPに対応するのはstrem_です.sock_write,書込バッファ指向s->rep p->acceptがproxyのacceptを実行する方法はfrontend_です.accept
session構造体のロゴメンバーを設定します.
設定の場合、TCP_を含む新規接続ソケットのオプションをそれぞれ設定します.NODELAY/KEEPALIVE/LINGER/SNDBUF/RCVBUFなどmodeがhttpであれば、sessionのtxnメンバーに関する設定と初期化を行う.
3.2.TCP接続上の受信イベント
haproxy.c 
-> run_poll_loop 
-> cur_poller.poll 
-> __do_poll (         sepoll,    ev_sepoll.c    poll   ) 
-> fdtab[fd].cb[DIR_RD].f(fd) (                   read   ,   TCP   ,  stream_sock_read )
-> stream_sock_read
ストリームsock_readは主に以下の機能を完成します.
現在接続されているリードバッファ、すなわち現在セッションのreq bufferが見つかりました.
    struct buffer *b = si->ib
設定によれば、spliceまたはrecvを呼び出してソケット上のデータを読み出し、読み出しバッファに充填すると、b>r(初期位置はb−>data)から始まるメモリに充填される.
0バイトを読み込むと、エンドのクローズ要求を受信して、stream auを呼び出します.sock_shutrで処理します
バッファマークSI->>ib->flagsのBF_を読みます.SHUTRセットは、現在のfdのepoll読み出しイベントをクリアし、このfdからを読み込まない.
バッファを書いたら->OB->flagsのBF_SHUTWはすでにビットを置きました.ローカルによって最初に開始されるべき接続を閉じる動作を説明します.
fdをfdset[]からクリアし、epollからfdを除去し、システム呼び出しclose(fd)、fd.stateセットビットFD_を実行する.STCLOSE stream interfaceの状態を修正しsi->state=SI_同前DIS ミッションtaskを起動しますwakeupは、現在のタスクをrun queueに追加します.その後、runnable taskysを検出すると、このタスクを処理します.3.3.TCP接続上の送信イベント
haproxy.c 
-> run_poll_loop 
-> cur_poller.poll 
-> __do_poll (         sepoll,    ev_sepoll.c    poll   ) 
-> fdtab[fd].cb[DIR_WR].f(fd) (                   write   ,   TCP   ,  stream_sock_write )
-> stream_sock_write
ストリームsock_writeは主に以下の機能を完成しています.
現在接続されている書き込みバッファが見つかりました.すなわち、現在セッションのrep buffer:
    struct buffer *b = si->ob
送信するデータをsendシステム呼び出して送信するまたはデータの発送が完了しましたので、接続を閉じる動作を送る必要があります.sock_shutw->システム呼び出しshutdown ミッションtaskを起動しますwakeupは、現在のタスクをrun queueに追加します.その後、runnable taskysを検出すると、このタスクを処理します.3.4.http依頼の処理
haproxy.c 
-> run_poll_loop 
-> process_runnable_tasks,             tasks,      task->process(       process_session)     
-> process_session
process.sessionは主に以下の機能を完成します.
接続をクローズする必要がある場合は、ブランチreync_ストリームインターフェース要求を処理して、分支reync_request(read event)
s->req->analsersのフラグビットに従って、異なるanalserを呼び出して処理要求を行う.
アナルリスト&AN_REQ_WAIT_HTTP:http_waitfor_request アナルリスト&AN_REQ_HTTP_PROCESS_FE:http_process.req_.common アナルリスト&AN_REQ_SWICHING_RULES:process_スウィッチrules レスポンス、ブランチレスポンスレスポンス(writeイベント)
s->rep->analsersのマーカービットに従って、異なるanalserを呼び出して処理要求を行う.
アナルリスト&AN_RES_WAIT_HTTP:http_waitfor_レスポンスアナルリスト&AN_RES_HTTP_PROCESS_BE:http_process.レススcommon forward bufferを扱う関連動作reqとrepのブザーをオフにして、pool 2_を呼び出します.freeはsessionとその申請の関連メモリを釈放して、読み書きバッファ(read 0 bytes)を含みます.
pool_free 2(pool 2 bauffer、s->req)pool_free 2(pool 2 bauffer、s->rep)pool_free 2(pool 2_session,s)taskは実行タスクのキューからクリアし、pool 2_を呼び出します.freeリリースtask申請のメモリ:task_delete();task_free()この論文では、TCP接続の処理過程を簡単に分析し、詳細な分析に偏らず、バックエンドserverの選択及び接続などが不足しており、Haproxy処理TCP接続の枠組みを示したいと考えています.