1. 程式人生 > >nginx四層反向代理分析

nginx四層反向代理分析

1 反向代理
反向代理(Reverse Proxy)方式是指以代理伺服器來接受internet上的連線請求,然後將請求轉發給內部網路上的伺服器,並將從伺服器上得到的結果返回給internet上請求連線的客戶端,
此時代理伺服器對外就表現為一個反向代理伺服器。


2 nginx反向代理
首先看配置,nginx反向代理是一個核心模組。基本配置如下。
tcp {
    timeout 10s; //會話超時時間
    proxy_read_timeout 10s;//會話讀超時時間
    proxy_send_timeout 10s; //會話寫超時時間
    upstream proxy_name {
#       # simple round-robin
        server localhost:1935;#需要代理的埠//代理服務配置,最終落地的伺服器
#check interval=3000 rise=2 fall=5 timeout=3000;
#check interval=3000 rise=2 fall=5timeout=1000
#check interval=3000 rise=2 fall=5timeout=1000
#check_http_send "GET /HTTP/1.0\r\n\r\n";
#check_http_expect_alive http_2xxhttp_3xx;
    }
    server {
        listen 8085; #代理8888埠   
        proxy_pass proxy_name;//對應上面的 upstream
    }
}


3 nginx反向代理編譯執行
https://github.com/yaoweibin/nginx_tcp_proxy_module
解壓後,到nginx目錄下打補丁。
執行命令
patch -p1 < ./nginx_tcp_proxy_module-master/tcp.patch


配置編譯
 ./configure --prefix=/home/nginx/   --with-openssl=/data/nginx/openssl-1.0.1t --with-stream  --add-module=/data/nginx/nginx_tcp_proxy_module-master
make && make install


4 程式碼分析
 (1)反向代理初始化
主要是解析到監聽的埠,將監聽埠新增到nginx網路框架中,並設定對應的回撥函式
入口函式:ngx_tcp.c ngx_tcp_block()
ngx_tcp_optimize_servers()監聽配置的埠
ls->handler = ngx_tcp_init_connection; 設定事件回撥
ngx_tcp_upstream_init() tcp反向代理初始化,連線到對端,也就是配置中的server
這裡可以配置域名,nginx啟動的時候會解析域名,並得到ip列表。
ngx_tcp_upstream_get_round_robin_peer() 連線對端的時候,通過round robin演算法獲取一個連線ip。
連線成功後為對端的連線設定讀寫事件回撥:
c->write->handler = ngx_tcp_upstream_handler;
        c->read->handler = ngx_tcp_upstream_handler;


ngx_tcp_upstream_check_broken_connection()每次會話上有新的請求的時候,判斷連線的狀態。

  (2) 反向代理資料透傳
ngx_tcp_proxy_handler()回撥函式
    if (c == s->connection)
{
        if (ev->write) {
            recv_action = "client write: proxying and reading from upstream";
            send_action = "client write: proxying and sending to client";
            src = pctx->upstream->connection;
            dst = c;
            b = pctx->buffer;
            write_bytes = &s->bytes_write;
        } else {
            recv_action = "client read: proxying and reading from client";
            send_action = "client read: proxying and sending to upstream";
            src = c;
            dst = pctx->upstream->connection;
            b = s->buffer;
            read_bytes = &s->bytes_read;
        }
    } 
else 
{
        if (ev->write) {
            recv_action = "upstream write: proxying and reading from client";
            send_action = "upstream write: proxying and sending to upstream";
            src = s->connection;
            dst = c;
            b = s->buffer;
            read_bytes = &s->bytes_read;
        } else {
            recv_action = "upstream read: proxying and reading from upstream";
            send_action = "upstream read: proxying and sending to client";
            src = c;
            dst = s->connection;
            b = pctx->buffer;
            write_bytes = &s->bytes_write;
        }
    }


通過時間源和型別,設定本次透傳的源和目標。從而進行資料轉發。