Nginx的原理、常用配置和生产案例应用(一)

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
云原生内存数据库 Tair,内存型 2GB
日志服务 SLS,月写入数据量 50GB 1个月
简介: Nginx的原理、常用配置和生产案例应用

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/

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"

访问http://hadoop.senior02:8081/ipblacklist


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
3天前
|
负载均衡 网络协议 关系型数据库
一口把LVS、Nginx及HAProxy工作原理讲清楚了。(附图)
一口把LVS、Nginx及HAProxy工作原理讲清楚了。(附图)
|
1天前
|
应用服务中间件 nginx Docker
本地通过域名访问虚拟机上nginx的服务、搭建域名访问环境一(反向代理配置)
这篇文章介绍了如何通过域名在本地访问虚拟机上的nginx服务,包括创建nginx容器、修改配置文件、修改本地host文件以及进行访问测试的详细步骤。文章提供了具体的Docker命令来创建并配置nginx容器,展示了配置文件的修改示例,说明了如何在本地系统的hosts文件中添加虚拟机IP和自定义域名,以及如何通过浏览器进行测试访问。
本地通过域名访问虚拟机上nginx的服务、搭建域名访问环境一(反向代理配置)
|
4天前
|
负载均衡 应用服务中间件 网络安全
NGINX配置详解
NGINX配置详解
|
4天前
|
应用服务中间件 Linux nginx
高并发下Nginx配置限流
【8月更文挑战第16天】
14 1
|
5天前
|
负载均衡 前端开发 应用服务中间件
使用Nginx配置SSL以及部署前端项目
本文介绍了如何使用Nginx配置SSL证书以启用HTTPS,并展示了如何通过Nginx部署前端项目,包括配置SSL证书、设置代理和负载均衡的示例。
22 2
|
5天前
|
关系型数据库 应用服务中间件 数据库
如何安装和配置 Django 与 Postgres、Nginx 和 Gunicorn
如何安装和配置 Django 与 Postgres、Nginx 和 Gunicorn
8 0
|
8天前
|
负载均衡 应用服务中间件 API
Nginx:location配置模块的用法(一)
Nginx:location配置模块的用法(一)
53 2
|
5天前
|
Web App开发 应用服务中间件 网络安全
如何在 Apache 和 Nginx 上配置 OCSP Stapling
如何在 Apache 和 Nginx 上配置 OCSP Stapling
24 8
|
5天前
|
jenkins 应用服务中间件 持续交付
如何配置 Nginx 作为 Jenkins 的反向代理并启用 SSL 加密
如何配置 Nginx 作为 Jenkins 的反向代理并启用 SSL 加密
25 8