Nginx的概念
正向代理代理的是客户端
反向代理代理的是服务端
Nginx是一个高性能的HTTP和反向代理服务器,单台Nginx服务器最多能够支持高达50000的并发请求,所以一般情况下,会将Nginx作为静态资源的访问服务器或者作为访问流量分流的服务器
主要特点:占用内存少,并发能力强,扩展容易
Nginx的系统架构
nginx配置use epoll后,以异步非阻塞方式工作,能够轻松处理百万级的并发连接
nginx在启动后,会有一个master进程和多个worker进程。master进程主要用来管理worker进程
Nginx的服务过程
从功能上来分有三种:
handlers 处理器模块
filter
proxies
Nginx.conf配置讲解
# 指定nginx 用户及用户组 user xx xx #user nobody; # 指定nginx 工作进程 根据硬件调整 通常等于cpu 核数 worker_processes 1; # 全局错误信息(warn) #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; # PID(进程标识符) 存储目录 #pid logs/nginx.pid; gzip on; gzip_disable "msie6";#为指定的客户端禁用gzip功能 gzip_proxied any;#压缩所有的请求 gzip_min_length 1000;#数据启用压缩的最少字节数 gzip_comp_level 4;#设置数据的压缩等级 #设置需要压缩的数据格式 gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss tex #负载均衡 upstream demo { server 127.0.0.1:8080 weight=1;#权重,值越高,分配到的几率越高 server 127.0.0.2:8081 down;#down表示这台机器不参与 server 127.0.0.2:8081 backup; } upstream moblie { server 192.168.80.123:8080; server 192.168.80.124:8080; } upstream img { server 192.168.80.123:8080; server 192.168.80.124:8080; } events { #连接上限 worker_connections 1024; } 设定http服务器 http { # 文件扩展名与文件类型映射 include mime.types; # 默认文件类型 default_type application/octet-stream; # 设定日志格式 #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' # '$status $body_bytes_sent "$http_referer" ' # '"$http_user_agent" "$http_x_forwarded_for"'; # 设置access log #access_log logs/access.log main; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65; #gzip on; # 设定虚拟主机 server { listen 80; # 监听端口号 server_name localhost; 域名 可以有多个 用空格隔开 #charset koi8-r; # 设定虚拟主机访问的日志 #access_log logs/host.access.log main; #手机站点与PC站点分离 set $mobile_rewrite 1; if ($http_user_agent ~* "(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino") { set $mobile_rewrite 0; } if ($http_user_agent ~* "^(1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-)") { set $mobile_rewrite 0; } location / { #proxy_pass http://demo; if ($mobile_rewrite = 0) { proxy_pass http://moblie; } proxy_pass http://demo; index index.html index.htm; } #动静分离 **.do **.aciton js css jpg gif html location ~ .*\.(jpg|gif)$ { root http://img; } } server { listen 80; server_name www.demo.com; access_log logs/dome.access.log; location / { proxy_pass http://demo; index index.html; root html; } } }
自定义日志格式
使用系统默认处理起来非常的复杂,而且生成的日志格式字段可能我并不全需要或者不满足我现在要求。怎么解决?自定义日志格式
# 1、去掉下面2部分注释
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log logs/access.log main;
# 2、添加自定义日志格式
log_format bf_log '$remote_addr^A$http_host^A$msec^A$request_uri';(分号必不可少)
# 3、 开启日志目录
location =/bf.gif{
default_type image;(分号必不可少)
access_log logs/bf.log bf_log;(分号必不可少)
}
# 4、生成的日志格式
172.16.100.35^Abigdata-spark04.ibeifeng.com^A1479985996.537^A/bf.gif
Location语法
配置语法
location [= | ~* | ^~ ] /uri/ {...}
配置规则
location = /uri 精准匹配
location ^~ /uri 前缀匹配
location ~ /uri
location / 通用匹配
规则的优先级
1 location = /
2 location = /index
3 location ^~ /article/
4 location ^~ /article/files/
5 location ~ \.(gif|png|js|css)$
6 location /
http://192.168.11.154/index ->2
http://192.168.11.154/article/files/1.txt ->4
http://192.168.11.154/mic.png ->5
1. 精准匹配是优先级最高
2. 普通匹配(最长的匹配)
3. 正则匹配
实际使用建议
location =/ {
}
location / {
}
location ~* \.(gif|....)${
}
Nginx的具体应用
一、Nginx+Lua实现动态黑名单
1.安装Redis
wget http://download.redis.io/redis-stable.tar.gz
进入redis根目录执行 make PREFIX=/usr/local/redis install
mv redis.conf /usr/local/redis/etc
vi /usr/local/redis/etc/redis.conf //将daemonize no 改成daemonize yes
设置开机启动:/usr/local/redis/bin/redis-server /usr/local/redis/etc/redis.conf
2.安装LuaJIT(可不安装)
LuaJIT 和 Lua 的一个区别是,LuaJIT 的运行速度比标准 Lua 快数十倍,可以说是一个 Lua 的高效率版本。
cd /usr/local/src
wget http://luajit.org/download/LuaJIT-2.1.0-beta2.tar.gz
tar zxf LuaJIT-2.1.0-beta2.tar.gz
cd LuaJIT-2.1.0-beta2
make PREFIX=/usr/local/luajit
make install PREFIX=/usr/local/luajit
配置lua的环境变量
export LUAJIT_LIB=/usr/local/luajit/lib
export LUAJIT_INC=/usr/local/luajit/include/luajit-2.1
3.下载lua-nginx-module 模块
yum -y update nss #nss版本过于陈旧,升级即可
cd /usr/local
git clone https://github.com/chaoslawful/lua-nginx-module.git
4.下载ngx_devel_kit(NDK)
cd /usr/local
wget https://github.com/simpl/ngx_devel_kit/archive/v0.2.19.tar.gz
tar -xzvf v0.2.19
5.安装lua-redis-parser,lua-resty-redis是openresty(1.9.15.1)的一个组件,简单来说,它提供一个lua语言版的redis API,使用socket(lua sock)和redis通信
git clone https://github.com/openresty/lua-resty-redis.git
mv lua-resty-redis /usr/local/nginx/lua/lua-resty-redis
6.进入之前安装nginx的解压目录,重新编译安装(引入LuaJIT并加入ngx_devel_kit-0.2.19和lua-nginx-module的目录)
sudo ./configure --with-ld-opt="-Wl,-rpath,/usr/local/luajit/lib" --add-module=/usr/local/ngx_devel_kit-0.2.19 --add-module=/usr/local/lua-nginx-module-0.10.2
编译安装
sudo make -j2
make install
7.nginx.conf的配置
http { lua_package_path "/usr/local/nginx/lua/lua-resty-redis/lib/?.lua;;"; #由 Nginx 进程分配一块 1M 大小的共享内存空间,用来缓存 IP 黑名单 lua_shared_dict ip_blacklist 1m; server { listen 8081; server_name hadoop.senior02; location ~ .*(BfImg)\.(gif)$ { default_type image/gif; access_log /home/hadoop/access.log log_format; root /usr/local/nginx/conf/www/source; } location = /ipblacklist { access_by_lua_file conf/lua/ip_blacklist.lua; default_type text/html; content_by_lua 'ngx.say("<p>hello, lua</p>")'; } } }
ip_blacklist.lua文件
local redis = require("resty.redis")
local ngx_log = ngx.log
local ngx_ERR = ngx.ERR
local ngx_INFO = ngx.INFO
local ngx_exit = ngx.exit
local ngx_var = ngx.var
-- 黑名单缓存60秒
local cache_idle = 60
local forbidden_list = ngx.shared.forbidden_list
local function close_redis(red)
if not red then
return
end
-- 释放连接(连接池实现)
local pool_max_idle_time = 100000 -- 毫秒
local pool_size = 100 -- 连接池大小
local ok, err = red:set_keepalive(pool_max_idle_time, pool_size)
if not ok then
ngx_log(ngx_ERR, "set redis keepalive error : ", err)
end
end
-- 从redis获取ip黑名单列表
local function get_forbidden_list()
local red = redis:new()
red:set_timeout(10000)
local ip = "192.168.226.4"
local port = 6379
--local password = ""
local ok, err = red:connect(ip, port)
if not ok then
ngx_log(ngx_ERR, "connect to redis error : ", err)
close_redis(red)
return
end
--local res, err = red:auth(password)
--if not res then
-- ngx_log(ngx_ERR, "failed to authenticate: ", err)
-- close_redis(red)
-- return
--end
local resp, err = red:smembers("forbidden_list")
if not resp then
ngx_log(ngx_ERR, "get redis connect error : ", err)
close_redis(red)
return
end
-- 得到的数据为空处理
if resp == ngx.null then
resp = nil
end
close_redis(red)
return resp
end
-- 刷新黑名单
local function reflush_forbidden_list()
local current_time = ngx.now()
local last_update_time = forbidden_list:get("last_update_time");
if last_update_time == nil or last_update_time < (current_time - cache_idle) then
local new_forbidden_list = get_forbidden_list();
if not new_forbidden_list then
return
end
forbidden_list:flush_all()
for i, forbidden_ip in ipairs(new_forbidden_list) do
forbidden_list:set(forbidden_ip, true);
end
forbidden_list:set("last_update_time", current_time);
end
end
reflush_forbidden_list()
local ip = ngx_var.remote_addr
if forbidden_list:get(ip) then
ngx_log(ngx_INFO, "forbidden ip refused access : ", ip)
return ngx_exit(ngx.HTTP_FORBIDDEN)
end
8.效果演示
redis-cli
#添加黑名单
SADD forbidden_list "127.0.0.1"
#移除黑名单
SREM forbidden_list "127.0.0.1"