小知识,大挑战!本文正在参与“程序员必备小知识”创作活动
Nginx
基础
nginx 是高性能的Http和反向代理web服务器, 核心特点是占有内存少, 并发能力强。
-
Http服务器(Web服务器)
性能非常高, 非常注重效率, 能够经受高负载的考验, 支持50000个并发数。CPU和内存的占用也非常低, 10000个没有活动的连接才占用2.5M的内存。
-
反向代理服务器
-
负载均衡服务器
-
动静分离
特点:
- 跨平台: 类unix操作系统和windows
- 配置简单
- 高并发 性能好 稳定性好
部署
yum -y install gcc zlib zlib-devel pcre-devel openssl openssl-devel
tar -xvf nginx-1.17.8.tar
cd nginx-1.17.8
./configure --prefix=/usr/local/nginx
make
make install
## 此时在/usr/local/下产生nginx
cd /usr/local/nginx/sbin
./nginx
命令
./nginx
./nginx -s stop ## 强制停止
./nginx -s quit ## 优雅退出
./nginx -s reload
./nginx -t
./nginx -s reopen #重启
配置文件
# 全局块
# 用户配置 worker 进程数量 通常设置为CPU数量
#user nobody;
worker_processes 1;
## 全局错误日志和pid文件位置
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
# events事件块(nginx服务器和用户的网络连接)
events {
# 单个worker进程最大并发连接数
worker_connections 1024;
}
# http 块 虚拟主机的配置 监听端口的配置 请求转发 反向代理 负载均衡`2`
http {
# 引入mime类型定义文件
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 logs/access.log main;
# 一般就开启, 如果IO密集 可以改成off
sendfile on;
#tcp_nopush on;
# 连接的超时时间
#keepalive_timeout 0;
keepalive_timeout 65;
# 是否开启GZip压缩
#gzip on;
server {
# 监听端口
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
# 默认请求
location / {
root html; # 默认的网站根目录
index index.html index.htm; # 索引页
}
#error_page 404 /404.html;
# 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;
#}
# 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 server
#
#server {
# listen 443 ssl;
# server_name localhost;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# location / {
# root html;
# index index.html index.htm;
# }
#}
}
nginx 语法
location [=|~|~*|^~] /uri/ {}
-
正则匹配 location ~ /abc{}
-
不区分大小写的正则匹配 location ~*/abc{}
-
匹配路径的前缀location ^~ /abc{}
-
精确匹配 location =/abc{}
-
普通路径前缀匹配 location /abc{}
优先级: 精确匹配 > 匹配路径前缀 > 不区分大小写正则 > 正则匹配 > 普通路径匹配
反向代理
location / {
#转发请求
proxy_pass http://127.0.0.1:8081
proxy_method: POST
proxy_set_header HOST $host
proxy_set_header X-Real-IP $remote_addr
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for
}
负载均衡
upstream loadBalanceServer{
server 127.0.0.1:8080;
server 127.0.0.1:8002;
}
location / {
proxy_pass http://loadBalanceServer
}
策略
-
默认轮询
-
weight 权重, 默认为1, max_fails默认为1 max_conns默认为0
fail_timeout 默认10s
upstream loadBalanceServer{ server 127.0.0.1:8080 weight=1 max_fails=3 fail_timeout=15 max_conns=0; server 127.0.0.1:8002 weight=2 backup; server 127.0.0.1:8004 weight=2 down; } -
ip_hash
upstream loadBalanceServer{ ip_hash; server 127.0.0.1:8080; server 127.0.0.1:8002; } -
least_conn
选取活跃连接数与权重weight的比值最小者为下一个处理请求的server。当然,上一次已选的server和已达到最大连接数的server照例不在选择的范围。
upstream loadBalanceServer{ least_conn; server 127.0.0.1:8080; server 127.0.0.1:8002; }除此以外还有第三方负载均衡fair等
动静分离
location ~ .*\.(html|htm|gif|jpg|jpeg|bmp|png|ico|js|css)$ {
root staticData;
}
缓存
proxy_cache_path 缓存文件路径,文件名是cache_key的MD5值
levels 缓存目录下的层级目录结构, 根据哈希后的请求地址创建的。名称从哈希后的字符串结尾处开始截取, 如果地址为12345, levels=1:2, 第一层为5,第二层为34
keys_zone 指定缓存区名称及共享内存大小,存放key和metadata。
inactive 主动清空在指定时间内未被访问的缓存。 10m代表10分钟
max_size 最大cache磁盘空间,不指定会使用掉所有的disk space,达到配额后会使用最少使用的cache文件
proxy_cache_path /data/cache levels=1:2 keys_zone=cache:50m inactive=10m max_size=1g
location / {
proxy_pass http://loadBalanceServer;
proxy_cache cache;
proxy_cache_key $host$uri$is_args$args;
proxy_cache_valid 200 304 1m;
add_header X-Proxy-Cache $upstream_cache_status
}
使用ngx_cache_purge 模块 进行缓存清理
location ~ /purge(/.*){
allow all;
proxy_cache_purge cache $host$uri$is_args$args;
}
压缩
GZip压缩
| 配置块 | 作用 |
|---|---|
| gzip on|off; | 是否开启gzip压缩 |
| gzip_comp_level level; | 压缩等级。从1到9,默认1 |
| gzip_disable "MSIE[1-6]\."; | 针对不同客户端发起的请求进行有选择的打开或者关闭gzip命令 后面是浏览器名称 比如禁用IE6的gzip功能 |
| gzip_min_length 1k; | 最小文件 |
| gizp_http_version 1.0| 1.1; | 启动压缩功能时,协议的最小版本,默认HTTP/1.1 |
| gzip_buffers number size; | 使用几个缓存空间, 每个缓存空间的大小。 32 4K | 16 8K |
| gzip_proxied off|any; | off关闭 any压缩所有服务器返回的数据 |
| gzip_types mine-type...; | 除text/html外, 对指定MIME类型启用响应的压缩 |
| gzip_vary on|off | 如果启用压缩 是否在响应报文首部插入"Vary:Accept-Encoding", 建议开启参数 |
gizp on;
gzip_http_version 1.1;
gzip_comp_level 3;
gzip_types text/plain application/json application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png
跨域
location / {
proxy_pass http://loadBalanceServer;
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Headers' 'Content-Type,*';
add_header 'Access-Control-Allow-Methods' 'GET,POST';
}
底层剖析
Nginx 启动后, 以daemon多进程方式在后台运行,包含一个Master进程和多个worker进程
-
Master进程
主要管理worker进程
- 接收外界信号向各worker进程发送信息
- 监控worker进程的运行状态, 当worker进程异常退出时会自动重新启动新的worker进程等
-
Worker进程
具体处理网络请求等,多个worker进程之间是对等的, 同等竞争来自客户端的请求, 各进程之间是相互独立的。一个请求只可能在一个worker进程中处理。worker进程的个数一般与机器CPU核数一致
热加载
./nginx -s reload
- master进程对配置文件进行语法检查
- 尝试配置
- 尝试成功使用新的配置, 新建worker进程
- 新建成功, 给旧的worker进程发送关闭信息
- 旧的worker进程收到信号后会继续服务,知道把当前进程接收到的请求处理完毕后关闭
请求处理机制
- master进程创建后, 会建立好需要监听的socket, 然后从master进程中fork出多个worker进程, 所有worker进程的监听符listenfd在新连接到来时都变得可读
- nginx使用互斥锁保证只有一个worker进程能够处理请求,拿到互斥锁的那个进程注册listenfd读事件, 在读事件里调用accept接受该连接,解析,处理,返回客户端。
多进程好处
- 每个worker进程独立,不需要加锁,节省开销
- 每个worker进程独立,互不影响, 一个异常结束,其他的也能提供服务