NGINX动态反向代理

Posted iTutor技术

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NGINX动态反向代理相关的知识,希望对你有一定的参考价值。

 

动态反向代理典型的一个应用场景是:

公司内网中有相当多的Uri资源,包含不同的IP、端口等,对终端用户来说,记录每个资源的Uri相当容易出错。所以这些资源需要统一的反向代理服务器包装成统一访问入口。

在对Uri资源进行可编程式的分类后,动态反向代理则可使用可编程脚本进行Uri资源路由,避免人为介入配置,完成动态反向代理。

正向代理(Proxy)

正向代理也就是我们平时常说的代理服务器。是位于客户端和远端服务器之间的服务器,为了从远端服务器取得内容。

客户端向正向代理发送一个请求并指定目标(远端服务器),然后正向代理向远端服务器转交请求并将获得的内容返回给客户端。

正向代理就像客户端和远端服务器之间的跳板。

 


反向代理(Reverse Proxy)

反向代理是代理服务器的一种,根据客户端的请求,从后端的服务器(如Web服务器)上获取资源,然后再将这些资源返回给客户端。

客户端都通过反向代理访问不同后端服务器上的资源,而不需要知道这些后端服务器的存在,认为所有资源都来自于这个反向代理服务器。

反向代理的最主要作用如下:

Ø 外网发布

² 将防火墙后面的服务器提供给互联网用户访问,加强安全防护。

² 使用高级 URL策略管理,可使处于不同服务器系统的URL资源于同一个 URL 空间下。(本文所讨论的动态反向代理)

Ø 负载均衡

² 后端的多台服务器提供负载均衡,或为后端较慢的服务器提供缓冲服务

 

正向代理 VS 反向代理

正向代理(代理客户端): 代理(Proxy)与客户端(Client)站一边,负责与远端服务器(Server)通讯。

反向代理(代理服务端): ProxyServer站一边,负责接受外界Client请求,根据策略与内部Server通讯。

 

具体如下图所示:

 

nginx反向代理

Nginx是一款由俄罗斯人创建面向性能设计的HTTP服务器,具备高性能、高并发、低内存的特色。不采用每客户机单一线程的设计模型,而是充分使用异步逻辑,削减了上下文调度开销,所以并发服务能力更强。在一定的高并发优化下,单Nginx服务器已可承受近10万的并发量。

Nginx整体采用模块化设计,有丰富的模块库和第三方模块库,配置灵活。在Linux操作系统下,Nginx使用epoll事件模型,效率相当高。

 

Nginx作为web服务器一个重要的功能就是反向代理,其反向代理的指令不需要新增额外的模块,使用默认自带proxy_pass指令,只需要修改配置文件就可以实现反向代理。

 

Nginx的反向代理配置参考如下案例:

Ø  案例I:用户访问反向代理服务器http://proxy.itutorgroup.com:80的请求将被反向代理至http://www.tutorabc.com.cn/,配置中仅需添加proxy_pass的指令。

#nginx.conf

http {

    server {

        listen 80;

        server_name   proxy.itutorgroup.com;

        location / {

            proxy_pass    http://www.tutorabc.com.cn/;

        }

    } 

}

 

Ø  案例II:用户访问反向代理服务器http://proxy.itutorgroup.com:80的请求被反向代理至http://www1~www3.tutorabc.com.cn/中持有最少活跃连接数的一台服务器。配置中的proxy_pass反向代理指令引用了上游服务器的负载均衡upstream块。

#nginx.conf

http {

     upstream tutorabcWebSrv {

least_conn;
         server
http://www1.tutorabc.com.cn/;

        server http://www2.tutorabc.com.cn/;

        server http://www3.tutorabc.com.cn/;

    }

 

    server {

        listen 80;

        server_name   proxy.itutorgroup.com;

        location / {

            proxy_pass    http://tutorabcWebSrv

        }

    } 

}

 

案例中引用到的nginx.conf有包含几个配置块,主要职能如下:

配置块

简介

http块

处理http请求的主要配置模块,大多数配置都在这里面进行

server块

主机的配置块,可以配置多个虚拟主机

location块

server中对应的目录级别的控制块,可以有多个

upstream块

反向代理和负载均衡的配置块,可以有多个

 

OpenResty

OpenResty是一个基于Nginx与Lua的高性能Web平台,其内部集成了大量精良的Lua库、第三方Nginx模块以及大多数的依赖项。

其充分利用Nginx的非阻塞I/O 模型,不仅仅对 HTTP 客户端请求,甚至于对远程后端诸如 mysql、PostgreSQL、Memcached以及Redis等都进行一致的高性能响应。

 

开发人员可使用Lua脚本语言调动Nginx支持的各种C以及Lua模块,快速构造出足以胜任10K乃至1000K以上单机并发连接的高性能Web应用系统。

 

Lua语言具有如下特性,非常适合快速开发:

Ø  轻量级:它用标准C语言编写并以源代码形式开放,编译后仅仅一百余K,可以很方便的嵌入别的程序里。

Ø  可扩展性: Lua提供了非常易于使用的扩展接口和机制:由宿主语言(通常是C或C++)提供这些功能,Lua可以使用它们,就像是本来就内置的功能一样。

Ø  多编程方式:面向过程(procedure-oriented)编程和函数式编程(functional programming)。

 

Lua同时提供了代码JIT的功能,使运行时速度上升到CPU指令级,非常高效。

OpenResty+Lua Script+Redis完成动态反向代理

在OpenResty中,Nginx模块与Lua库的集成都可在nginx.conf中完成,参考如下配置案例,

Ø  在/proxy的location块中,定义了remoteaddr的变量。

Ø  在请求访问阶段处理使用script文件夹下的routing.lua脚本处理remoteaddr变量并赋值。

 

#nginx.conf

http {

    server {

        listen 80;

        server_name   proxy.itutorgroup.com;

        location /proxy {

set $remoteaddr "";

default_type text/plain;

access_by_lua_file /usr/local/openresty/script/routing.lua;

proxy_pass $remoteaddr;

}

    }

}

 

假设经过routing.lua脚本的动态解析,proxy_pass指令可将用户访问反向代理,

http://proxy.itutorgroup.com/proxy/department/team/project/index.html

http://lp.tutorabc.com.cn/lpgs/XssLdiDUOK/index.html

 

我们来看下脚本包含什么逻辑,可以协助完成动态反向代理。这段Lua脚本会在后面安装配置指南中用到。

--#1. 获取用户访问的Uriargs则赋值为/proxy/department/team/project/index.html

local args= ngx.var.uri

 

--#2. "/",作为分隔符,将Uri分割并保存至lua Table内。split函数声明暂放Lua脚本最后

local uriTable =  split(args,"/")

 

--#3. 获取Tabledepartmentteamproject栏位的值,uriTable下标从1开始

local department = uriTable[2]

local team = uriTable[3]

local project = uriTable[4]

 

--#4. 将三个值拼接后封装成Redis缓存的Key

local cacheKey = department..'_'..  team..'_'.. project

 

--#5. 连接本地监听6379端口的Redis缓存,获取值。

local redis = require  "resty.redis"

local cache = redis.new()

cache.connect(cache, '127.0.0.1',  6379)

local cacheValue =  cache:get(cacheKey)

 

--#6. 如缓存值未发现,则返回HTTP 404

if res==ngx.null then

     return ngx.exit(404)

end

 

local count = 0;

for _,subUri in ipairs(uriTable) do

    if count>3

    then

      cacheValue = cacheValue..'/'..subUri

    end

    count = count + 1

end

 

--#8. 对脚本外部location中定义的remoteaddr赋值

ngx.var.remoteaddr = cacheValue

 

--#附:分割函数

function split(pString, pPattern)

    local Table = {}  -- NOTE: use  {n = 0} in Lua-5.0

    local fpat = "(.-)" .. pPattern

    local last_end = 1

    local s, e, cap = pString:find(fpat, 1)

    while s do

       if s ~= 1 or cap ~= "" then

      table.insert(Table,cap)

       end

       last_end = e+1

       s, e, cap = pString:find(fpat, last_end)

    end

    if last_end <= #pString then

       cap = pString:sub(last_end)

       table.insert(Table, cap)

    end

    return Table

end

 

通过脚本的解释,我们可以了解当确保本地Redis缓存中包含如下kv时,location块则可获得动态反向代理所需参数。

Key

Value

Department_Team_Project

http://lp.tutorabc.com.cn/lpgs/XssLdiDUOK/

 

Nginx Lua模块指令

Ngin+Lua动态反向代理的核心是在location块植入Lua脚本,支持植入满足Lua语法的语句块、或者有访问权限的Lua语句文件,Lua的植入可在Nginx的各个处理阶段。

 

Nginx11个处理阶段,而相应的处理阶段是可以做插入式处理,即可插拔式架构;另外指令可以在httpserverserver iflocationlocation if几个范围进行配置,不仅仅局限于location块。

 

Nginx处理阶段植入Lua脚本的指令表如下:

指令

所处处理阶段

使用范围

解释

init_by_lua

init_by_lua_file

loading-config

http

nginx Master进程加载配置时执行;

通常用于初始化全局配置/预加载Lua模块

init_worker_by_lua

init_worker_by_lua_file

starting-worker

http

每个Nginx Worker进程启动时调用的计时器,如果Master进程不允许则只会在init_by_lua之后调用;

通常用于定时拉取配置/数据,或者后端服务的健康检查

set_by_lua

set_by_lua_file

rewrite

server,server if,location,location if

设置nginx变量,可以实现复杂的赋值逻辑;此处是阻塞的,Lua代码要做到非常快;

rewrite_by_lua

rewrite_by_lua_file

rewrite tail

http,server,location,location if

rrewrite阶段处理,可以实现复杂的转发/重定向逻辑;

access_by_lua

access_by_lua_file

access tail

http,server,location,location if

请求访问阶段处理,用于访问控制

content_by_lua

content_by_lua_file

content

locationlocation if

内容处理器,接收请求处理并输出响应

header_filter_by_lua

header_filter_by_lua_file

output-header-filter

httpserverlocationlocation if

设置headercookie

body_filter_by_lua

body_filter_by_lua_file

output-body-filter

httpserverlocationlocation if

对响应数据进行过滤,比如截断、替换。

log_by_lua

log_by_lua_file

log

httpserverlocationlocation if

log阶段处理,比如记录访问量/统计平均响应时间

 

OpenResty安装配置指南

以分步骤引导的方式,介绍在CentOS上进行OpenResty安装、与动态反向代理配置的方法。主要配置将在/usr目录下完成。

 

  • 1. 下载LuaJIT 2.0.2

http://luajit.org/download/LuaJIT-2.0.2.tar.gz

解压:sudo tar zxvf LuaJIT-2.0.2.tar.gz

 

  • 2. 下载pcre 8.39

https://sourceforge.net/projects/pcre/files/pcre/8.39/pcre-8.39.tar.gz/download

解压:sudo tar zvxf pcre-8.39.tar.gz

 

  • 3. 下载zlib 1.2.8

http://zlib.net/fossils/zlib-1.2.8.tar.gz

解压:sudo tar vxf zlib-1.2.8.tar.gz

 

  • 4. 下载OpenResty 1.11.2.3

https://openresty.org/download/openresty-1.11.2.3.tar.gz

解压:sudo tar zxvf openresty-1.11.2.3.tar.gz

 

  • 5. 安装LuaJIT 2.0.2

安装在/usr/local目录下

cd /usr/LuaJIT-2.0.2/

make

make install

export LUAJIT_LIB=/usr/local/lib

export  LUAJIT_INC=/usr/local/include/luajit-2.0

 

  • 6. 安装OpenResty 1.11.2.3

安装在/usr/local目录下

cd  /usr/openresty-1.11.2.3/

./configure  --with-pcre=/usr/pcre-8.39 --with-zlib=/usr/zlib-1.2.8 --with-http_ssl_module  --with-luajit

make

make  install

 

  • 7. 配置Nginx.conf

vim /usr/local/openresty/nginx/conf/nginx.conf

location块中加入如下shell指令后保存退出

location /proxy {

set $remoteaddr "";

default_type text/plain;

access_by_lua_file /usr/local/openresty/script/myscript.lua;

proxy_pass $remoteaddr;

}

 

  • 7. 配置Lua脚本

将之前章节介绍的Lua脚本保存为/usr/myscript.lua,使用如下shellLua脚本准备好

mkdir   /usr/local/openresty/script/

sudo cp -f/usr/myscript.lua  /usr/local/openresty/script/

 

  • 7. 注册Nginx服务,并设置开机自动启动

保存开机启动脚本为/usr/nginx,然后运行shell进行注册。并启动Nginx服务

sudo cp -f /usr/nginx /etc/rc.d/init.d/

sudo chmod +x /etc/rc.d/init.d/nginx

chkconfig nginx on

systemctl start nginx

 

启动脚本:

#!/bin/bash

# Tengine Startup script# processname:  nginx

# chkconfig: - 85 15

# description: nginx is a World Wide Web  server. It is used to serve

# pidfile: /var/run/nginx.pid

# config:  /usr/local/nginx/conf/nginx.conf

nginxd=/usr/local/openresty/nginx/sbin/nginx

nginx_config=/usr/local/openresty/nginx/conf/nginx.conf

nginx_pid=/usr/local/openresty/nginx/logs/nginx.pid

RETVAL=

prog="nginx"

# Source function library.

. /etc/rc.d/init.d/functions

# Source networking configuration.

. /etc/sysconfig/network

# Check that networking is up.

[ ${NETWORKING} =

[ -x $nginxd ] || exit

# Start nginx daemons functions.

start() {

if [ -e $nginx_pid ];then

echo "tengine already  running...."

exit

fi

echo -n $"Starting $prog: "

daemon $nginxd -c ${nginx_config}

RETVAL=$?

echo

[ $RETVAL =  ] && touch /var/lock/subsys/nginx

return $RETVAL

}

# Stop nginx daemons functions.

stop() {

echo -n $"Stopping $prog: "

killproc $nginxd

RETVAL=$?

echo

[ $RETVAL =  ] && rm -f /var/lock/subsys/nginx  /usr/local/nginx/logs/nginx.pid

}

reload() {

echo -n $"Reloading $prog: "

#kill -HUP `cat ${nginx_pid}`

killproc $nginxd -HUP

RETVAL=$?

echo

}

# See how we were called.

case "$1" in

start)

start

;;

stop)

stop

;;

reload)

reload

;;

restart)

stop

start

;;

 

status)

status $prog

RETVAL=$?

;;

*)

echo $"Usage: $prog  {start|stop|restart|reload|status|help}"

exit

esac

exit $RETVAL

 

  • 8. 安装并配置Redis

Redis的编译安装配置不在本文介绍,仅提供简单的yum源安装脚本。安装后使用redis-cli set命令将动态反向代理需要的Key准备好。

sudo yum install epel-release

sudo yum update

sudo yum install redis

sudo systemctl enable redis

sudo systemctl start redis

 

Redis KV参考值如下

Key

Value

Department_Team_Project

http://lp.tutorabc.com.cn/lpgs/XssLdiDUOK/

 

  • 9. 测试动态反向代理

Nginx安装服务器上访问http://localhost:port/proxy/Department/Team/Project/index.html

则会根据Redis中配置的KV跳转至http://lp.tutorabc.com.cn/lpgs/XssLdiDUOK/index.html

就此Nginx动态反向代理配置成功了,只要通过后端APIRedis缓存进行更新,可以做到运行时的路由切换。

 

参考文献:

https://en.wikipedia.org/wiki/Reverse_proxy

https://www.zhihu.com/question/24723688

http://nginx.org/en/docs/

http://tool.oschina.net/apidocs/apidoc?api=nginx-zh

http://nginx.org/en/docs/http/ngx_http_upstream_module.html

https://openresty.org/cn/

http://jinnianshilongnian.iteye.com/blog/2186448

https://github.com/openresty/lua-nginx-module

https://www.lua.org/start.html


以上是关于NGINX动态反向代理的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法动态配置 nginx(或其他快速反向代理)?

nginx反向代理实现资源的动静分离

Ceryx —— 基于 NGINX OpenResty 的动态反向代理

Nginx反向代理到花生壳动态域名失效问题解决

nginx详解反向代理负载均衡LNMP架构上线动态网站

《nginx》二nginx反向代理