学习nginx,就要先了解什么是nginx,为什么使用nginx,最后才是了解怎么使用nginx —— 哲氏沃硕德
nginx简介
nginx是一个高性能的HTTP和反向代理Web服务器,还支持正向代理、透明代理、负载均衡、HTTP缓存等功能。nginx始于2004年10月4日,使用C语言编写,2013年4月24日,nginx发布了v1.4.0稳定版,建议大家使用的版本高于此版本。
免费开源的nginx能够在众多同类产品中脱颖而出,是因为它具备低内存、高并发的优势,且配置简单,支持URL重写、GZIP,内置健康检查,能自动检测集群服务器状态,跳过宕机服务器。
nginx安装
Linux中安装nginx
安装编译工具和库文件
yum -y install make pcre pcre-devel zlib zlib-devel gcc-c++ libtool openssl openssl-devel
下载nginx并安装
nginx下载地址:http://nginx.org/en/download.html
cd /usr/local/src/ 下载特定版本 nginx 压缩包,这里以v1.18.0为例 wget http://nginx.org/download/nginx-1.18.0.tar.gz 解压 tar -zxvf nginx-1.18.0.tar.gz 进入到 nginx-1.18.0 目录下 cd nginx-1.18.0/ 生成 Makefile ./configure 编译并且安装(默认输出到/usr/local/nginx,可在configure中看到) make && make install
如果想要编译输出到指定目录
设置编译输出目录为 /home/jjj/nginx ./configure –prefix=/home/jjj/nginx 编译并且安装(输出到/home/jjj/nginx) make && make install
防火墙开放端口号
开放端口号外网才可访问
练习期间,推荐将防火墙关闭,避免因其导致无法访问而卡住:
systemctl stop firewalld.service
开启 80 firewall-cmd –zone=public –add-port=80/tcp –permanent 重启防火墙 firewall-cmd –reload 查询端口号80是否开启 firewall-cmd –query-port=80/tcp 查询哪些端口已开启 firewall-cmd –list-port
自己动手测试一下能否访问吧
启动nginx(命令要在nginx安装目录的sbin目录下执行)
在浏览器中输入nginx所在的主机ip
/usr/local/nginx/sbin/nginx 启动nginx /usr/local/nginx/sbin/nginx -s reload 重新加载nginx配置 /usr/local/nginx/sbin/nginx -s stop 快速关闭nginx(先查出nginx进行id,然后使用kill命令强制杀死进程),可能不保存相关信息(不推荐) /usr/local/nginx/sbin/nginx -s quit 平稳关闭nginx,保存相关信息(推荐) /usr/local/nginx/sbin/nginx -s reopen 重新打开日志文件 /usr/local/nginx/sbin/nginx -s
为 nginx 指定一个配置文件 /usr/local/nginx/sbin/nginx -t 不运行,仅测试配置文件正确性 /usr/local/nginx/sbin/nginx -v 显示nginx版本 /usr/local/nginx/sbin/nginx -V 显示 nginx 的版本,编译器版本和配置参数 netstat -anput | grep nginx 检测 nginx 运行状态(如无任何信息显示则是未运行) 配置开机启动
关机重启了你不会想自己动手再启动一遍nginx吧?
新建 nginx.service 文件
vim /usr/lib/systemd/system/nginx.service
然后在文件中添加以下配置
配置详情参考:https://www.cnblogs.com/yyxianren/articles/10677332.html
服务说明项 [Unit] 描述 Description=nginx 在哪些服务启动之后启动该服务,多个服务用空格隔开 After=network.target 在哪些服务启动之前启动该服务 Before=xxx 弱依赖,如果xxx服务启动失败或停止运行,不影响该服务 Wants=xxx 强依赖,如果xxx服务启动失败或停止运行,该服务也必须退出 Requires=xxx
运行参数设置 [Service] 启动类型 simple(默认值):ExecStart字段启动的进程为主进程 forking:ExecStart字段将以fork()方式启动,此时父进程将会退出,子进程将成为主进程 oneshot:类似于simple,但只执行一次,Systemd 会等它执行完,才启动其他服务 dbus:类似于simple,但会等待 D-Bus 信号后启动 notify:类似于simple,启动结束后会发出通知信号,然后 Systemd 再启动其他服务 idle:类似于simple,但是要等到其他任务都执行完,才会启动该服务。一种使用场合是为让该服务的输出,不与其他服务的输出相混合 Type=forking Start命令 ExecStart=/usr/local/nginx/sbin/nginx Reload命令 ExecReload=/usr/local/nginx/sbin/nginx -s reload Stop命令 ExecStop=/usr/local/nginx/sbin/nginx -s quit 是否给服务分配独立的临时空间 PrivateTmp=true
配置开机启动方式 [Install] 该服务所在的 Target,Target的含义是服务组,表示一组服务 multi-user.target 默认被配置为开机启动 WantedBy=multi-user.target
纯净版(去除注释)
[Unit] Description=nginx After=network.target
[Service] Type=forking ExecStart=/usr/local/nginx/sbin/nginx ExecReload=/usr/local/nginx/sbin/nginx -s reload ExecStop=/usr/local/nginx/sbin/nginx -s quit PrivateTmp=true
[Install] WantedBy=multi-user.target
最后启动服务并重启机器进行测试
systemctl enable nginx.service 启用 nginx.service 开机启动 reboot 重启电脑
其他命令 systemctl disable nginx.service 禁止 nginx.service 开机启动 systemctl stop nginx.service 停止 nginx.service systemctl start nginx.service 启动 nginx.service systemctl restart nginx.service 重启 nginx.service systemctl list-units –type=service 查看所有已启动的服务
检查 nginx.service 运行状况
systemctl status nginx.service
检查nginx运行状况
netstat -anput | grep nginx
Docker中安装nginx
下载镜像
搜索镜像 docker search nginx 拉取镜像 docker pull nginx
创建并启动容器
-d
:后台运行docker run -d -it -p 8080:80 –name nginx8080 nginx
访问nginx
curl
:8080
微服务分布式部署前期准备
为了方便修改nginx配置,需要将容器内的nginx相关文件拷贝到主机中,并将其映射到容器中去,这样,修改起来就方便多了
拷贝nginx文件到本地
docker cp nginx8080:/etc/nginx ~/nginx
上面步骤创建的nginx8080已经没用了,删除即可
docker stop nginx8080 docker rm nginx8080
创建挂载本地目录的nginx8080容器
挂载:即主机上指定目录与容器内指定目录文件共享
-v ~/nginx:/etc/nginx
:将本地~/nginx文件映射到容器/etc/nginx,方便修改配置-v ~/nginx/log:/var/log/nginx
:将本地~/nginx/log映射到容器/var/log/nginx,方便查看日志的环境:apidemo1、apidemo1、nginx8080都在同一docker中
方法一:使用 link 建立容器间通信
--link=apidemo1:demo1
:实现nginx8080容器到apidemo1容器的单向通信,并为apidemo1起别名为demo1,nginx8080内部可直接使用demo1访问apidemo1--link=apidemo2:demo2
:实现nginx8080容器到apidemo2容器的单向通信,并为apidemo2起别名为demo2,nginx8080内部可直接使用demo2访问apidemo2apidemo1与apidemo2是同一应用的不同分发 docker run -d -it -p 8080:80 –name nginx8080 -v ~/nginx:/etc/nginx -v ~/nginx/log:/var/log/nginx –link=apidemo1:demo1 –link=apidemo2:demo2 nginx
修改nginx.conf
vim ~/nginx/nginx.conf
server {
listen 80; server_name localhost; location / { root /usr/share/nginx/html; index index.html index.htm; } location /api/ { proxy_pass http://apiserver/api/; }
}
upstream apiserver {
server demo1 weight=1; server demo2 weight=1;
}
方法二:使用 docker bridge 建立容器间通信
docker network ls
:查看docker网络信息,其中,们创建的容器默认使用bridge(桥接)docker network inspect bridge
:查看bridge的详细信息以及哪些容器使用了该网络类型,这边的ip地址是apidemo1:172.17.0.2
apidemo2:172.17.0.3
docker run -d -it -p 8080:80 –name nginx8080 -v ~/nginx:/etc/nginx -v ~/nginx/log:/var/log/nginx nginx
修改nginx.conf
vim ~/nginx/nginx.conf
server {
listen 80; server_name localhost; location / { root /usr/share/nginx/html; index index.html index.htm; } location /api/ { proxy_pass http://apiserver/api/; }
}
upstream apiserver {
server 172.17.0.2 weight=1; server 172.17.0.3 weight=1;
}
为了应用新nginx.conf,重启nginx8080
docker restart nginx8080
测试
// 这里的路径按照自己的来 curl
:8080/api/values 可能出现的问题
Http staus code——502:
解决:查看日志可以看到"113: No route to Host”,尝试关闭docker所在linux机器的防火墙,发现可以访问了,可以确定是防火墙的问题。但是把防火墙关闭太不安全了,所以们选择打开防火墙,然后执行以下命令信任 docker0 服务连接 nmcli connection modify docker0 connection.zone trusted 停止 NetworkManager 服务(该服务用语监测网络、自动连接网络) systemctl stop NetworkManager.service 将docker0网络接口设置为内部区域(永久) firewall-cmd –permanent –zone=trusted –change-interface=docker0 启动 NetworkManager 服务 systemctl start NetworkManager.service 信任 docker0 服务连接 nmcli connection modify docker0 connection.zone trusted 重启 docker systemctl restart docker.service
文件目录
*_temp:共5个temp结尾的目录,用于存放nginx运行时产生的临时文件
conf:存放配置文件的目录,包含主配置文件nginx.conf
html:存放了nginx的错误页面和欢迎页面
logs:存放了访问日志和错误日志
sbin:存放了nginx的二进制命令,常用于nginx服务的启动、停止等管理工作
nginx常用功能和配置
限流
三种方式
limit_conn_zone(限制连接数,针对客户端,即单一ip限流)
limit_req_zone(限制请求数,针对客户端,即单一ip限流)
ngx_http_unpstream_module(推荐,针对后台,如:有两台服务器,服务器A最大可并发处理10W条请求,服务器B最大可并发处理5W条请求,这样当12W请求按照负载均衡规则应当被分配给服务器A时,nginx为了防止A挂掉,所以将另外的2W分配给B)
压力测试工具——Ab
安装
yum install httpd-tools -y
测试
// 10个用户,向 http://www.test.com/ 并发发送1000条请求(总请求数=1000) ab -c 10 -n 1000 http://www.test.com/
返回值
Document Path:测试的页面路径
Document Length:页面大小(byte)
Concurrency Level:并发数量,即并发用户数
Time taken for tests:测试耗费时长
Complete requests:成功的请求数量
Failed requests:请求失败的数量
Write errors:错误数量
Requests per second:每秒钟的请求数量、吞吐率
Timer per request:每次请求所需时间、响应时间
limit_conn_zone {limit_conn_zone}
http {
将请求客户端的IP($binary_remote_addr)存放到perip区域,区域大小为10M,一个IP占用32Byte(32位系统)或64Byte(64位系统)左右 perip是区域的名字,可自定义 limit_conn_zone $binary_remote_addr zone=perip:10m; server { 每个IP最大并发1条连接 该语句还可直接放置到http模块下,这样下属的server都应用该配置 该语句还可放置到server中的location模块中,这样仅指定的location应用该配置 limit_conn perip 1; 每个连接限速300 k/s limit_rate 300k; }
}
limit_req_zone {limit_req_zone}
http {
将请求客户端的IP存放到perip区域,区域大小为10M,并限制同一IP地址的请求每秒钟只处理一次 limit_req_zone $binary_remote_addr zone=perip:10m rate=1r/s; server { 当有大量请求爆发时,可以缓存2条请求 设置了nodelay,缓存队列的请求会立即处理,若请求数 > rate+burst 时,立即返回503;如果没设置,则会按照rate排队等待处理 该语句还可直接放置到http模块下,这样下属的server都应用该配置 该语句还可放置到server中的location模块中,这样仅指定的location应用该配置 limit_req zone=perip burst=2 nodelay; }
}
测试:
ab -c 1 -n 3 http://localhost/
3个请求全部成功,因为正在处理的请求数1加上缓存数2,没超过限制
Server Software: nginx/1.18.0 Server Hostname: 192.168.159.128 Server Port: 80
Document Path: / Document Length: 612 bytes
Concurrency Level: 1 Time taken for tests: 0.001 seconds Complete requests: 3 Failed requests: 0 Total transferred: 2535 bytes HTML transferred: 1836 bytes Requests per second: 2439.02 /sec Time per request: 0.410 ms Time per request: 0.410 [ms] (mean, across all concurrent requests) Transfer rate: 2012.67 [Kbytes/sec] received
测试:
ab -c 3 -n 4 http://localhost/
3个请求成功,1个请求失败,因为正在处理的请求数1加上缓存数2,另外1条请求失败
erver Software: nginx/1.18.0 Server Hostname: 192.168.159.128 Server Port: 80
Document Path: / Document Length: 612 bytes
Concurrency Level: 1 Time taken for tests: 0.002 seconds Complete requests: 4 Failed requests: 1 (Connect: 0, Receive: 0, Length: 1, Exceptions: 0) Non-2xx responses: 1 Total transferred: 3223 bytes HTML transferred: 2330 bytes Requests per second: 2504.70 /sec Time per request: 0.399 ms Time per request: 0.399 [ms] (mean, across all concurrent requests) Transfer rate: 1970.86 [Kbytes/sec] received
ngx_http_upstream_module {ngx_http_upstream_module}
upstream MyName {
server 192.168.0.1:8080 weight=1 max_conns=10; server 192.168.0.2:8080 weight=1 max_conns=10;
}
安全配置
版本安全
隐藏HTTP Response消息头Server中的版本号
隐藏前:Server: nginx/1.18.0
隐藏后:Server: nginx
http {
server_tokens off;
}
IP安全
白名单配置(适用于授权IP较少的情况),可配置在http、server、location中
location / {
allow 192.168.1.1; deny all;
}
黑名单配置(适用于授权IP较多的情况),可配置在http、server、location中
location / {
deny 192.168.1.1; allow all;
}
文件安全
location /logs {
autoindex on; root/opt/nginx/;
}
location ^logs~*.(log|txt)$ {
add_header Content-Type text/plain; root/opt/nginx/;
}
连接安全
https(就不多介绍了)
进程数、并发数、系统优化
配置nginx.conf,增加并发量
与CPU逻辑核心数一致 worker_processes 12; events {
单个worker最大并发连接数 worker_connection 65535;
}
调整内核参数
查看所有的属性值
ulimit -a
临时设置硬限制(重启后失效)
ulimit -Hn 100000
临时设置软限制(重启后失效)
ulimit -Sn 100000
持久化设置(重启后仍生效)
vim /etc/security/limits.conf 接下来是文件中需要配置的内容
* soft nofile 100000 * hard nofile 100000
用户/组 软/硬限制 需要限制的项目 限制的值
GZIP
作用:启用gzip后,服务器将响应报文进行压缩,有效地节约了带宽,提高了响应至客户端的速度。当然,压缩会消耗nginx所在电脑的cpu
配置范围:http、server、location
http {
启用gzip gzip on; 允许压缩的最小字节数(即如果response header中的content-length小于该值,就不压缩) gzip_min_length 2k; 按照原数据大小以16k为单位的4倍申请内存用作压缩缓存 gzip_buffers 4 16k; 压缩级别,级别越大,压缩率越高,占用CPU时间更长 gzip_comp_level 5; 需要被压缩的响应类型,默认值是text/html gzip_types text/plain application/x-javascript text/css application/xml; 配置最低版本的http压缩协议(即1.0时,1.0和1.1都会启用压缩;1.1时,仅1.1时才会启用压缩) gzip_http_version 1.0; IE6及以下禁用压缩 gzip_disable "MSIE [1-6]\.";
}
状态监控
配置访问地址
location /nginxstatus {
stub_status on; // 禁止将监控信息写入访问日志 access_log off;
}
安装插件并重启
cd /usr/local/src/nginx-1.18.0 如果不是使用的默认路径,使用 –prefix 指定 ./configure –with-http_stub_status_module make && make install /usr/local/nginx/sbin/nginx -s quit /usr/local/nginx/sbin/nginx
访问地址,状态参数如下
Active connections:活跃的连接数量
server accepts handled requests:处理的总连接数 创建的握手数 处理的总请求数
reading:读取客户端的Header信息的次数。这个操作仅读取头部信息,完成后立即进入writing状态
writing:响应数据传到客户端的Header信息次数。这个操作不仅读取头部,还要等待服务响应
waiting:开启keep-alive后等候下一次请求指令的驻留连接
负载均衡
轮询
upstream myserver {
默认所有服务器权重为 1
server 192.168.250.220:8080;
server 192.168.250.221:8080;
server 192.168.250.222:8080;
}
加权轮询
- 性能更好的服务器权重应更高
upstream myserver {
server 192.168.250.220:8080 weight=3;
server 192.168.250.221:8080; default weight=1
server 192.168.250.222:8080; default weight=1
}
最少连接
upstream myserver {
least_conn;
with default weight for all (weight=1)
server 192.168.250.220:8080;
server 192.168.250.221:8080;
server 192.168.250.222:8080;
}
加权最少连接
- 性能更好的服务器权重应更高
upstream myserver {
least_conn;
server 192.168.250.220:8080 weight=3;
server 192.168.250.221:8080; default weight=1
server 192.168.250.222:8080; default weight=1
}
IP Hash
- 算法:根据客户端ip进行Hash得到一个数值,然后使用该数值对服务器个数取模,得到的结果就是映射的服务器序号
- (在服务器个数不变的情况下)可保证同一ip地址的请求始终映射到同一台服务器,解决了session共享问题
upstream myserver {
ip_hash;
with default weight for all (weight=1)
server 192.168.250.220:8080;
server 192.168.250.221:8080;
server 192.168.250.222:8080;
}
uri Hash
- (在服务器个数不变的情况下)可保证同一uri始终映射到同一台服务器
- nginx在1.7.2之后支持uri_hash
upstream myserver {
hash $request_uri;
with default weight for all (weight=1)
server 192.168.250.220:8080;
server 192.168.250.221:8080;
server 192.168.250.222:8080;
}
access日志切割
新建Shell脚本
脚本文件路径随意 vim /usr/local/nginx/nginx_log.sh
将以下内容添加到脚本中
! /bin/bash 设置日志文件存放目录(nginx安装目录为/usr/local/nginx) LOG_HOME=“/usr/local/nginx/logs”
备份Log名称 LOG_PATH_BAK=“$(date -d yesterday +%Y%m%d%H%M)“.access.log
重命名日志文件 mv $/access.log $/${LOG_PATH_BAK}.log
向nginx主进程发信号重新打开日志 kill -USR1
cat /usr/local/nginx/logs/nginx.pid
创建crontab定时作业
crontab -e
将以下内容添加到作业中去(任取一个)
corn表达式生成器:http://cron.qqe2.com/
以每分钟切割一次为例 */1 * * * * sh /usr/local/nginx/nginx_log.sh
以每天切割一次为例 0 0 0 1/1 * ? sh /usr/local/nginx/nginx_log.sh
动静分离
概念:将动态请求和静态请求分开
实现方式:
(推荐)将静态文件存放在专门的服务器上,使用单独的域名
另一种是将动态和静态文件放在一起,使用nginx区分
以实现方式1为例
前提:将静态文件存放在代理服务器中
在ngnix中创建文件目录(如/usr/local/nginx/static),将所有静态文件发布到该目录中
在nginx.conf http server 中配置动静分离
server {
location ~ .*\.(html|htm|gif|jpg|jpeg|bmp|png|ico|txt|js|css)$ { root /usr/local/nginx/static; 缓存30天 expires 30d; }
}
在实际的后台服务器中发布的程序中,使用静态文件时,路径指向设置为静态文件服务器(这里是代理服务器)
nginx.conf基础配置项
指定运行nginx的用户名 user nobody; 工作线程数,通常同cpu逻辑核心数一致 worker_processes 1;
错误日志路径 最小级别 [ debug | info | notice | warn | error | crit ] error_log logs/error.log; error_log logs/error.log notice; error_log logs/error.log info;
指定进程的pid记录文件,记录当前运行的nginx的pid pid logs/nginx.pid;
网络连接模块 events {
一个工作线程支持的最大并发连接数 worker_connections 1024; keepalive超时时间,单位:秒 keepalive_timeout 60;
}
设定http服务器,利用它的反向代理功能提供负载均衡支持 http {
设定支持的 mime 类型 include mime.types; 默认 mime 类型 default_type application/octet-stream; 设定日志格式,格式名为main $remote_addr:客户端的ip地址(若使用代理服务器,则是代理服务器的ip) $remote_user:客户端的用户名(一般为"-") $time_local:访问时间和时区 $request:请求的url和请求方法 $status:响应HTTP状态码 $body_bytes_sent:响应body中的字节数 $http_referer:客户端是从哪个url来请求的 $http_user_agent:客户端用户使用的代理(一般为浏览器) $http_x_forwarded_for:客户端的ip地址(通过代理服务器记录客户端的ip地址) 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; 指定 nginx 是否调用 sendfile 函数(zero copy 方式)来输出文件,对于普通应用,必须设为 on, 如果用来进行下载等应用磁盘IO重负载应用,可设置为 off,以平衡磁盘与网络I/O处理速度,降低系统的uptime sendfile on; tcp_nopush on; keepalive 超时时长,单位:秒 keepalive_timeout 0; keepalive_timeout 65; 打开 gzip gzip on; 以上为 nginx 的全局设置,应用于所有 Web 应用 一个Web应用对应一个 server,内部配置仅针对该应用,优先级比全局的高 server { // 端口号 listen 80; // 域名,比如 www.test.com server_name localhost; 编码格式 charset koi8-r; 访问日志文件路径 access_log logs/host.access.log main; 一般路由导航到: location / { 根目录为html root html; 默认页为 index.html,如果没有则是 index.htm index index.html index.htm; } 404时的展示页面 error_page 404 /404.html; 50X时的展示页面 redirect server error pages to the static page /50x.html error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } proxy the PHP scripts to Apache listening on 127.0.0.1:80 location ~ \.php$ { proxy_pass http://127.0.0.1; } pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 location ~ \.php$ { root html; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; include fastcgi_params; } 禁止访问 .htxxx 的文件 deny access to .htaccess files, if Apache's document root concurs with nginx's one location ~ /\.ht { deny all; } } another virtual host using mix of IP-, name-, and port-based configuration server { listen 8000; listen somename:8080; server_name somename alias another.alias; location / { root html; index index.html index.htm; } } HTTPS demo beign HTTPS server server { listen 443 ssl; server_name localhost; ssl 证书文件位置 ssl_certificate cert.pem; ssl 证书key的位置 ssl_certificate_key cert.key; ssl_session_cache shared:SSL:1m; ssl_session_timeout 5m; 数字签名 MD5 ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; location / { root html; index index.html index.htm; } } HTTPS demo end 反向代理 demo begin 设定实际的服务器列表(权重默认都是1) upstream myserver{ server 192.168.0.1:8089 weight=7; server 192.168.0.2:8089 weight=3; } server { listen 80; server_name localhost; 反向代理的路径(和upstream绑定),location 后面设置映射的路径 location / { proxy_pass http://myserver; } } 反向代理 demo end
}