HAProxy 연구 노트 - TCP 연결 처리 프로 세 스

8970 단어 HAProxy
본 고 는 HAProxy 1.5 - dev 7 버 전 을 바탕 으로 한다.
목록 1. 핵심 데이터 구조 세 션 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 과 연 결 됩 니 다 하나의 업무 session 에 두 개의 TCP 연결 이 존재 합 니 다. 하 나 는 client 에서 haproxy, 하 나 는 haproxy 에서 백 엔 드 server 입 니 다.
또한, 하나의 session 은 보통 하나의 task 에 대응 해 야 합 니 다. haproxy 는 최종 적 으로 task 를 통 해 스케줄 링 을 합 니 다.
2. 관련 초기 화
haproxy 가 요청 을 정식으로 처리 하기 전에 일련의 초기 화 동작 이 있 습 니 다.요청 처리 와 관련 된 초기 화 를 소개 합 니 다.
2.1. TCP 연결 을 초기 화 하 는 방법
TCP 프로 토 콜 을 처리 하 는 데이터 구 조 를 초기 화 합 니 다. 주로 socket 과 관련 된 방법 에 대한 설명 입 니 다.아래 proto 자세히 보기tcpv 4 (proto tcp. c) 의 초기 화:
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 의 proto 구성원 에 게 값 을 부여 합 니 다.함수 호출 프로 세 스 는 다음 과 같 습 니 다.
cfgparse.c
-> cfg_parse_listen
-> str2listener
-> tcpv4_add_listener
-> listener->proto = &proto_tcpv4;

여기 서 초기 화 된 것 은 listener 가 socket 을 처리 하 는 방법 이기 때 문 입 니 다.haproxy 가 client 의 새로운 연결 을 받 는 입구 함 수 는 protocol 구조 체 의 accpet 방법 으로 추정 된다.tcpv4 에 게 는 streamsock_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 방법의 디자인 논 리 를 간단하게 정리 할 수 있 습 니 다.
stream_sock_accept (): 새 TCP 연결 을 수신 하고 listener 자신의 accept 방법 session 을 터치 합 니 다.accept()
session_accept (): session 을 만 들 고 session 구성원 의 초기 화 를 담당 하 며 frontend 의 accept 방법 front 을 호출 합 니 다.accetp()
frontend_accept (): 이 함 수 는 주로 session 전단 의 TCP 연결 초기 화 를 담당 합 니 다. socket 설정, log 설정, session 부분 구성원 의 초기 화 를 포함 합 니 다.
다음은 TCP 의 새로운 연결 처리 과정 을 분석 하 는데 기본적으로 이 세 함수 의 분석 이다.
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 ]

이 함수 포인터 prototcpv4 구조 체 의 accept 구성원, 즉 함수 streamsock_accept
2.4. 등 록 된 모든 프로 토 콜 의 listeners 사용 하기
모든 listeners 의 fd 를 polling lists 에 haproxy. c - > protocolenable_all -> all registered protocol enable_all -> enable_all_listeners (TCP) -> enable_listener 함 수 는 LI 에 있 습 니 다.LISTEN 의 listener 상 태 를 LI 로 변경READY, cur poller 의 set 방법 을 호출 합 니 다. 예 를 들 어 sepoll 을 사용 하면fd_set
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 세 션 구조 할당 task 호출new 새로운 퀘 스 트 할당 새로 분 배 된 session 을 전역 sessions 링크 에 추가 합 니 다 session 과 task 의 초기 화, 몇몇 중요 한 구성원 의 초기 화 는 다음 과 같 습 니 다.
t - > process = l - > handler: 즉 t - > process 지향 processsession
t - > context = s: 작업 의 컨 텍스트 지향 session s - > listener = l: session 의 listener 멤버 는 현재 listener 를 가리킨다.
s - > si [] 의 초기 화, accept 시스템 호출 이 되 돌아 오 는 cfd 등 기록 초기 화 s - > txn s - > req 와 s - > rep 에 각각 메모리 할당 및 초기 화
s->req = pool_alloc2(pool2_buffer)
s->rep = pool_alloc2(pool2_buffer)
코드 로 볼 때 각각 tune. bufsize + size of struct buffer 크기 의 메모리 를 독립 적 으로 분배 해 야 합 니 다.

새 연결 cfd 초기 화
cfd 를 비 차단 으로 설정 cfd 를 fdtab [] 에 추가 하고 cfg 를 연결 하 는 read 와 write 를 새로 등록 하 는 방법 fdtab [cfd]. cb [DIR RD]. f = l - > proto - > read, cfd 의 read 를 설정 하 는 함수 l - > proto - > read, 대응 하 는 TCP 는 streamsock_read, 읽 기 캐 시 지향 s - > req, fdtab [cfd]. cb [DIR WR]. f = l - > proto - > write, cfd 의 write 함수 l - > proto - > write 를 설정 하고 TCP 에 대응 하 는 streamsock_write, 쓰기 버퍼 지향 s - > rep

p - > accept 에서 proxy 를 실행 하 는 accept 방법 은 frontendaccept
session 구조 체 를 설정 한 log 멤버 설정 에 따라 TCP 를 포함 하여 새 연결 소켓 을 각각 설정 합 니 다.NODELAY / KEEPALIVE / LINEER / NDBUF / 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

stream_sock_read 는 주로 다음 과 같은 기능 을 완성 합 니 다.
현재 연 결 된 읽 기 버퍼 를 찾 습 니 다. 즉, 현재 session 의 req buffer:
    struct buffer *b = si->ib
설정 에 따라 splice 나 recv 를 호출 하여 소켓 의 데 이 터 를 읽 고 읽 기 버퍼 에 채 웁 니 다. 즉, b - > r (초기 위 치 는 b - > data) 에서 시작 하 는 메모리 에 채 웁 니 다 .
0 바이트 까지 읽 으 면 엔 드 에 대한 닫 기 요청 을 받 고 stream 을 호출 합 니 다.sock_shutr 처리
버퍼 태그 읽 기 si - > ib - > flags 의 BFSHUTR 위치 설정, 현재 fd 의 epoll 읽 기 이 벤트 를 제거 하고 이 fd 에서 읽 지 않 습 니 다 버퍼 si - > ob - > flags 의 BF 를 쓰 면SHUTW 가 설정 되 어 있 습 니 다. 로 컬 에서 먼저 시작 하 는 연결 닫 기 동작 임 을 설명 합 니 다.
fd 를 fdset [] 에서 제거 하고 epoll 에서 fd 를 제거 하 며 시스템 호출 close (fd), fd. state 설치 FDSTCLOSE
stream interface 상태 수정 si - > state = SIST_DIS


각성 퀘 스 트 taskwakeup, 현재 작업 을 run quue 에 추가 합 니 다.나중에 runnable tasks 를 감지 하면 이 작업 을 처리 합 니 다 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

stream_sock_write 는 주로 다음 과 같은 기능 을 완성 합 니 다.
현재 연 결 된 쓰기 버퍼 를 찾 습 니 다. 즉, 현재 session 의 rep buffer:
    struct buffer *b = si->ob
보 낼 데 이 터 를 send 시스템 으로 호출 하여 보 냅 니 다 또는 데이터 가 전송 되 었 거나 연결 을 닫 는 동작 stream 을 보 내야 합 니 다.sock_shutw - > 시스템 호출 shutdown 각성 퀘 스 트 taskwakeup, 현재 작업 을 run quue 에 추가 합 니 다.나중에 runnable tasks 를 감지 하면 이 작업 을 처리 합 니 다 3.4. http 요청 처리
haproxy.c 
-> run_poll_loop 
-> process_runnable_tasks,             tasks,      task->process(       process_session)     
-> process_session

process_session 은 주로 다음 과 같은 기능 을 완성 합 니 다.
연결 을 닫 아야 할 상황 을 처리 합 니 다. 분기 resyncstream_interface
처리 요청, 분기 resyncrequest (read event)
s - > req - > analysers 의 태그 위치 에 따라 서로 다른 analyser 를 호출 하여 처리 요청 ana_list & AN_REQ_WAIT_HTTP: http_wait_for_request
ana_list & AN_REQ_HTTP_PROCESS_FE: http_process_req_common
ana_list & AN_REQ_SWITCHING_RULES:process_switching_rules

처리 응답, 분기 resyncresponse (write event)
s - > rep - > analysers 의 태그 위치 에 따라 서로 다른 analyser 를 호출 하여 처리 요청 ana_list & AN_RES_WAIT_HTTP: http_wait_for_response
ana_list & AN_RES_HTTP_PROCESS_BE:http_process_res_common

forward buffer 의 동작 처리 req 와 rep 의 buffer 를 닫 고 pool 2 를 호출 합 니 다.읽 기와 쓰기 버퍼 (read 0 bytes) 를 포함 하여 session 및 신청 에 관 한 메모 리 를 무료 로 방출 합 니 다.
pool_free2(pool2_buffer, s->req);
pool_free2(pool2_buffer, s->rep);
pool_free2(pool2_session, s);

task 실행 작업 대기 열 에서 지우 고 pool 2 호출free task 신청 메모리 방출: taskdelete(); task_free();
본 고 는 TCP 연결 의 처리 과정 을 간단하게 분석 하고 세부 적 인 분석 에 중심 을 두 지 않 으 며 백 엔 드 server 의 선택 과 연결 등 이 부족 하여 haproxy 가 TCP 연결 을 처리 하 는 프레임 워 크 를 보 여 주 려 고 합 니 다.

좋은 웹페이지 즐겨찾기