论Nginx作为Web服务器的应用在Linux上的实现 ( Blog 18)

Nginx…

博客十八:论Nginx作为Web服务器的应用在Linux上的实现;

Alphabetical index of variables
Core functionality
ngx_http_core_module
ngx_http_access_module
ngx_http_auth_basic_module
ngx_http_fastcgi_module
ngx_http_gzip_module
ngx_http_headers_module
ngx_http_log_module
ngx_http_proxy_module
ngx_http_referer_module
ngx_http_rewrite_module
ngx_http_ssl_module
ngx_http_status_module
ngx_http_stub_status_module
ngx_http_upstream_module
ngx_stream_core_module

获取模块相关指令的帮助: http://nginx.org/en/docs/

主配置文件结构:
main block:主配置段,也即全局配置段;进程配置
event {

}:事件驱动相关的配置;

http {

}:http/https 协议相关的配置段;

mail {

}: 7层负载均衡

stream {

}: 4层负载均衡

http协议相关的配置结构
http {

…:各server的公共配置
server {

}:每个server用于定义一个虚拟主机;
server {

listen defult_server: 主机名虚拟主机时,通过IP访问此主机响应;
server_name _ 匹配所有主机名
root 相当于DocumentRoot
alias 相当于alias
location [OPERATOR] URL {

if CONDITION {

}:相当于IfModule,为真则运行;

error_page 错误页
}:仅能基于URL定义。http可以基于文件系统、URL定义
}
}

配置文件修改后:
1)语法检测:nginx -t
2)重载配置:nginx -s reload

Main配置段指令:
1)正常运行必备
user, pid, include, load_module
(1)、user nginx;
workder进程的身份;
(2)、pid /run/nginx.pid;
pid文件
(3)、include /usr/share/nginx/modules/*.conf;
片段化配置
(4)、load_module “/usr/lib64/nginx/modules/ngx_http_geoip_module.so”;
装载支持动态装载的模块

2)性能优化相关
worker_processes, worker_cpu_affinity, worker_priority, worker_rlimit_nofile
(1)、worker_processes auto;
worker进程启用个数,auto表示当前物理核心数,建议比当前物理核心数小,以避免worker进程间切换;
(2)、worker_cpu_affinity auto [cpumask];
worker_processes 4;
worker_cpu_affinity 0001 0010 0100 1000;
绑定worker进程在哪个CPU上;提高缓存命中率;查看进程位置哪个CPU:ps axo pid,comm,psr
(3)、worker_priority number;
worker_priority -10;
worker进程启动后的优先级,默认是0;查看进程的优先级:ps axo pid,comm,ni
(4)、worker_rlimit_nofile number;
限制打开文件最大数量,应该大于”所有worker进程并发数”;

3)调度定位问题
daemon, master_process, error_log file [level]
(1)、daemon on | off;
nginx是否工作于前台;off:表示工作于前台;注意需要重启进程;
(2)、master_process on | off;
nginx是否仅以master进程工作;off:表示只能master进程;注意需要重启进程;
(3)、error_log file [level];
Log levels:debug, info, notice, warn, error, crit, alert, or emerg.
错误日志记录级别,从左而右依次递增,级别越高记录的越少;

4)事件驱动:event { … }
worker_connections number, use method, accept_mutex
(1)、worker_connections number;
一个worker进程最大并发数;
所有worker进程最大并发数 = worker_connections number X worker_processes
(2)、 use method;
select: 1024
epoll: C10K
(3)、accept_mutex on | off;
on意味着由各worker轮流处理新请求; 必须轮流;
Off意味着每个新请求的到达都会通知所有的worker进程;抢着请求;

http配置段
http {
… …
server {
listen
server_name
root
location [OPERATOR] /uri/ {

}
}
server {

}
}
与套接字相关的配置:

(1)、server { … }
表示定义一个虚拟主机;
server {
listen
server_name
root
}

(2)、listen PORT|address[:port] [ssl]
定义当前虚拟主机监听的地址加端口,省略时表示所有:例如:listen 800; 监听在当前主机所有的接口的地址;
listen 127.0.0.1:8000;
listen 127.0.0.1;
listen 8000;
listen *:8000;
listen localhost:8000;
listen 44322 ssl;
ssl: 表示仅能ssl通信;
ssl_certificate “/etc/pki/nginx/server.crt”;
ssl_certificate_key “/etc/pki/nginx/private/server.key”;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 10m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;

(3)、server_name name …;
定义虚拟主机的主机名称
server {
server_name example.com *.example.com www.example.* ~^www\d+\.example\.com$;
}
优先级:
(1) 首先是字符串精确匹配;
(2) 左侧*通配符;
(3) 右侧*通配符;
(4) 正则表达式;

例如:
server {
listen 172.16.0.99:80;
server_name www.a.com;
root /data/nginx/v3;
}
server {
listen 172.16.0.99:80;
server_name *.a.com;
root /data/nginx/v1;
}
server {
listen 172.16.0.99:80;
server_name www.a.*;
root /data/nginx/v2;
}
server {
listen 172.16.0.99:80;
server_name ^www\d+\.a\.com$;
root /data/nginx/v4;
}
浏览器中访问:
www.a.com —> v3:前三个都满足,精确匹配者为先;
www1.a.com –> v1:二四满足,正则表达式优先级最低;
www.a.io —> v2:仅3匹配;

(4)、tcp_nodelay on | off; <适用于keepalive启用时>
on: 在keepalived模式下的连接时, 每个报文单独发送,提升用户体验;
off: 在keepalived模式下的连接时, 将多个报文打包为一个发送,用户看到有延迟;

(5)、tcp_nopush on | off;
on: 在sendfile模式下,等待应用层首部;
off: 在sendfile模式下,不等待应用层首部,首部随后到达;

(6)、sendfile on | off;
on: 启用sendfile时,worker进程被请求一个资源时,其向内核发起系统调用,内核将其加载至”内核内存”中,直接构建响应报文发送;
off: 将加载到内核内存中的数据再复制到进程内存中,由应用程序响应,消耗不必要的时间;

面向客户端连接的相关配置
(1)、keepalive_timeout timeout [header_timeout];
设定保持连接的超时时长,0表示禁止长连接;默认为75s;
禁用:keepalive_timeout 0;

(2)、keepalive_requests number;
在一次长连接上所允许请求的资源的最大数量,默认为100;

保持连接:多个资源一直请求,第一次建立连接,传输完成后再拆除连接;
缺点:建立后不会释放连接;
折中的方案: 设置长连接,但有限制: 时间, 资源
注意:在高并发场景应该关闭长连接,给每个用户维持一个连接,可能会阻止新的用户连接;
建议配置:
keepalive_timeout 15;

(3)、send_timeout time; 发送响应超时时长!
服务端向客户端发送响应报文时,客户端突然断开,超时会重试响应。

(4)、client_body_buffer_size size;
缓冲(读写)请求报文的body的buffer大小,默认为16K,超出此大小时,其将被暂存到磁盘上的由client_body_temp_path指令所定义的位置;
1个汉字2个Bytes,1KBytes=1024Bytes /2 –> 512汉字; 16K –> 16*1024/2=接近1万个汉字;
如果并发1万:单个buffer 16K ,所有请求:16 X 10^-3 M X 10^4 =16M
client_body_temp_path path [level1 [level2 [level3]]]; 将buffer未能缓存的body部分(>16K),缓存于磁盘上;以便将来快速查找;
path: 缓存的路径:
level1: 一级子目录
level2: 两级子目录
level3: 三级子目录
目录名是URL的hash值(十六进制数字),从右而左截取的字串,如果目录名为一个字符:则缩小16倍。2个字符:则缩小16X16倍。3个字符:则16^3倍。

对客户端进行限制的相关配置:
(1)、limit_except method … { … }
限制除了哪些方法(GET, HEAD, PUT, POST, DELETE, TRACE, OPTIONS)之外的方法:
建议配置:GET HEAD POST方法外不允许使用;
limit_except GET HEAD POST {
deny all;
}
GET:不需要ENTITY-BODY;
HEAD:测试测试能否GET;
POST: 提交表单;密码、提交回复;
PUT: 上传一个资源至服务器端(服务器要提供DAV)
DELETE:删除
TRACE: 追踪web服务器需要经过多少个代理;
traceroute
OPTIONS: 探测资源支持的方法的方法

文件操作优化相关的配置:
(1)aio on | off ; 启用AIO功能,极大优化访问时被阻塞在IO上的时间;
(2)open_file_cache max=N [inactive=time];
max=N 缓存多少个信息;(文件描述符、目录结构、没有访问权限的相关信息); 达到MAX值时,以LRU算法找出最近最少使用,删除缓存;
inactive=time 非活动时长。如果此时间内不命中缓存,就会删除缓存;

定义路径相关的配置:
(1)、root path;
URL的根映射到文件系统哪个目录;用于:http, server, location, if in location;范围小越最终生效;
http {
server {
location {
if () {

}
}
}
}

(2)、location [ = | ^~ | ~* | ~ ] uri { … }
根据请求报文的的URI来匹配检查;URI: 在访问日志中有记录:http://www.a.com/123 –> “GET /123 HTTP/1.1”
根据匹配优先级递减列出:
= 精确匹配
^~ 半部分匹配
~* 正则表达式匹配,ignore case;
~ 正则表达式匹配,区分字母大小写;
直接给出

多个location可以匹配到相同的内容时,则根据此优先级判断应该运用于哪个location:
例如:
server {
listen 172.16.0.67:80;
server_name www.ilinux.io;
root /data/nginx/vhost1;

location ~* \.(jpg|png)$ {
deny 172.16.0.68;
allow all;
}

location / {
root /web
all all;
}
}

此时,在172.16.0.68主机上访问一个 http://www.ilinux.io/1920×1080.jpg,的权限匹配法则:
其URI:/1920×1080.jpg ~* 可以匹配;/也可以匹配;优先级 ~* > /,所以匹配 ~* 所在的location;

(3)、alias path;
路径别名
root: 目录下存在URI
location /images/ {
root /path/to/somedir;
}
www.ilinux.io/images/ –> server –> location /images/ –> /path/to/somedir/images/

alias:目录下不存在URI;
location /images/ {
alias /path/to/somedir;
}
www.ilinux.io/images/ –> server –> location /images/ –> /path/to/somedir/
例如:
server {
listen 172.16.0.67:80;
server_name www.ilinux.io;
root /data/nginx/vhost1;

location ~* \.(jpg|png)$ {
deny 172.16.0.68;
allow all;
}
location / {
}

location ^~ /images/ {
alias /data/pictures/;
}
}

访问:www.ilinux.io/images/1920×1080.jpg –> location (^~ > ~* > 直接给出) –> alias指定的路径下不存在匹配的URI(/data/pictures/1920×1080.jpg)

(4)、error_page code … uri;
自定义错误页;响应状态码为code时,返回URI并重新检查整个配置文件;
例如:
server {
listen 172.16.0.67:80;
server_name www.ilinux.io;
root /data/nginx/vhost1;
location ~* \.(jpg|png)$ {
deny 172.16.0.68;
allow all;
}
location / {
root /web;
}
location ^~ /images/ {
alias /data/pictures/;
}
error_page 404 /notfound.html;
}
客户端访问一个不存在的页面时,返回/notfound.html,并重新匹配整个配置文件,多个location 只能第二个匹配,是root:表示/notfound.html则为/web目录下的一个文件;

server {
listen 172.16.0.67:80;
server_name www.ilinux.io;
root /data/nginx/vhost1;

location ~* \.(jpg|png)$ {
deny 172.16.0.68;
allow all;
}

location / {
}

location ^~ /images/ {
alias /data/pictures/;
}

error_page 404 /notfound.html;
location = /notfound.html {
root /data/nginx/error_pages;
}
}
客户端访问一个不存在的页面时,返回/notfound.html,并重新匹配整个配置文件,location优先级最高的是 = ,文件为: /data/nginx/error_pages/notfound.html

(5)、error_page code … [=[response]] uri;
响应状态码为指定的code时,返回URI;且修改状态码:查看方法:浏览器中打开F12 后 F5刷新;

访问控制:
(1)、ngx_http_access_module
白名单:
allow addr;
deny all;
黑名单:
allow all;
deny addr;

(2)、ngx_http_auth_basic_module
程序包:httpd-tools
location ~* /(admin|login)/ {
auth_basic “admin area”
auth_basic_user_file /etc/nginx/.ngxpasswd
}
不定义root相当于承继全局root;

状态:
(1)、ngx_http_stub_status_module
location /NAME {
stub_status;
}
AME必须要与网页不冲突,惟一;
location /ngxstatus {
stub_status;
}
Active connections: 2
当前的活动连接数;
accepts handled requests
总请求requests中:
accepts:接受进来的请求数;
handled: 处于完成的请求数;
requests > accepts > handled

Reading: 0 Writing: 1 Waiting: 1
处于正在 读请求报文首部状态的请求
处于正在 发送响应状态的请求:
处于正在 等待请求的请求;空闲 <– 长连接,客户端发送一个请求后,不再请求时,就空闲了;

awk取出:处理过的请求:
# curl –silent http://www.ilinux.io/ngxstatus | awk ‘/^[[:space:]]/{print $2}’

日志:
(1)、ngx_http_log_module
log_format name string …;
access_log path [format [buffer=size] [gzip[=level]];
buffer:定义{缓冲}数据内容的缓冲区大小,元数据由下面的指令字义{缓存},大量的访问日志先在内存中,一会儿在写入磁盘。性能提升;默认即可;
access_log off; 表示关闭访问日志

应用上下文: http, server, location
http: 全局配置
server: 单虚拟主机日志
location: URI匹配到此location时,记录

combined格式:
log_format main ‘$proxy_add_x_forwarded_for – $remote_user [$time_local] “$request” ‘
‘$status $body_bytes_sent “$http_referer” ‘
‘”$http_user_agent”‘;

示例:记录自己定义的虚拟主机日志,且admin单独记录,status不记录:
server {
listen 172.16.0.67:80;
server_name www.ilinux.io;
root /data/nginx/vhost1;
access_log /var/log/vhost1_access.log main;

location ~* \.(jpg|png)$ {
deny 172.16.0.68;
allow all;
}

location / {
root /web;
}

location ~* /(admin|login)/ {
auth_basic “admin area”;
auth_basic_user_file /etc/nginx/.ngxpasswd;
access_log /var/log/admin_access.log main;
}

location ^~ /images/ {
alias /data/pictures/;
}

error_page 404 =200 /notfound.html;
location = /notfound.html {
root /data/nginx/error_pages;
}

location /ngxstatus {
stub_status;
access_log off;
}
}

open_log_file_cache max=N [inactive=time] [min_uses=N] [valid=time];
open_log_file_cache off;
缓存各日志文件相关的元数据信息;

max:缓存的最大文件描述符数量;
min_uses:在inactive指定的时长内访问大于等于此值方可被当作活动项;
inactive:非活动时长;
valid:验正缓存中各缓存项是否为活动项的时间间隔;

传输压缩:
(1)、ngx_http_gzip_module
http, server, location, if in location
对所有站点压缩:http中
对指定站点压缩:server中;
对匹配的URI压缩:location

gzip on;
gzip_comp_level 6;
gzip_min_length 64; 启用压缩最小大小
gzip_proxied any;
gzip_types text/xml text/css application/javascript; 对哪些mime(mime.types)压缩;
测试:cp nginx.conf /data/nginx/vhost1/nginx.html
注意:后缀为Html才能压缩;此项为默认!

SSL:
(1)、ngx_http_ssl_module (单个IP只能做一次SSL)
server {
listen 443 ssl;
server_name www.magedu.com;
root /vhosts/ssl/htdocs;
ssl on;
ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2
ssl_certificate /etc/nginx/ssl/nginx.crt;
ssl_certificate_key /etc/nginx/ssl/nginx.key;
ssl_session_cache shared:sslcache:20m;
}
shared:sslcache:20m
1M=4000个会话; 20M –> 160万个会话;
shared: worker进程间的ssl session是共享的;

URL重写:
(1)、ngx_http_rewrite_module
rewrite pcre扩展正则表达式 替换的内容 (类似于查找替换)
pcre扩展正则表达式: 与扩展正则表达式相同写法;
替换的内容: 只能是纯文本字符,可以使用$1, $2 …后向引用
注意:
替换的内容是相对路径: 浏览器中键入的URL不会改变;
替换的内容是绝对路径: 浏览器中键入的URL会改变,相当于 301, permanent

例如:
1)找出URI中jpg替换为png:
rewrite /(.*)\.jpg@ /$1.png
2)全栈SSL
rewrite /(.*)$ https://www.ilinux.io/$1

重写优先级:
last: 重写后重复检查;
break: 重写后不再检查;
redirect: 临时重定向;302;
rewrite /(.*)\.jpg /$1.jpg
rewrite /(.*)\.jpg /$1.jpg redirect 即使相对路径客户端也会重新请求;
permanent, 永久重定向,301,相当于给出绝对路径;
rewrite /(.*)\.jpg /$1.jpg permanent;
服务器自己处理:
last,break, 相对路径;
返回给客户端:
redirect, permanent, 绝对路径;
防火链:
(1)、ngx_http_referer_module
1)valid_referers none block server_names *.magedu.com *.mageedu.com magedu.* mageedu.* ~\.magedu\.;
none: referer没有首部: 自己直接键入的主页; –> 合法;
block: 有referer,但没有值,只要自己委屈的认为合法。可能代理服务器删除了;
server_names 服务器名 正则表达式:自己定义哪些服务器;
\google\:爬虫,应该允许,否则表示拒绝了搜索引擎收录了;
2)if($invalid_referer) {
return http://www.magedu.com/invalid.jpg; 当为真时生效; 返回一个劣图,假图;引起用户注意作用;
}

变量为真:
数字:0假;非0真;
字串:空假,非空真;

3)rewrite_log on | off; 重写发生是否记录于日志;
4)set $var :自己定义变量;

例如:
server {
listen 80;
server_name www.iunix.io;
location ~* \.(jpg|png|jpeg|gif)$ {
valid_referers none blocked server_names *.unix.io unix.* ~\.google\.;
if ($invalid_referer) {
return http://web.iunix.io/default.jpg ;
}
}

}
如果返回当前虚拟主机(www.iunix.io)中定义的图片时,又会匹配到此不可以引用:
解决方法:
1、 valid_referers server_names 后添加可引用的站点;
2、 返回另一个基于名称或端口或IP的虚拟主机路径下的一个图片;
3、 返回另一个站点上的图片;

总结:与优先级相关:
多个server_name:精确 > *.magedu.com > www.magedu.* > ~ REGEXP;
多个location:精确(=) > ^~(行首) > ~* 不区分大小写 > ~ 区分大小写 > 直接给出;
root: 路径下存在URI;
alias: 路径下不存在URI;

Nginx 七层代理:
Nginx是应用层的代理:Client与服务端是两个完全不同的连接;(抓包可分析;)
源地址和源端口会变化;
目标地址和目标端口会变化;Nginx是监听在一个固定端口;

注意:
同一个主机只能LNMP: Nginx + php-fpm + mariadb

跨主机: 建议使用同一个网段的三个主机,不同网段,反正我是没有实现出来;
LNMP: Nginx + php-fpm + mariadb
LANMP: Nginx + httpd(php) + mariadb

ngx_http_proxy_module <– 代理http协议,自定义请求首部;(LNAMP)
proxy_pass http://IP:PORT;

proxy_set_header X-Real-IP $remote_addr; 向服务端设定请求首部;
proxy_cache_path 定义缓存空间、大小、磁盘路径、最大大小、级别;
proxy_cache 调用缓存;
proxy_cache_key 缓存的键
proxy_cache_methods 哪些方法缓存
proxy_cache_min_uses 非活动期内最小使用次数;
proxy_cache_valid 哪些状态码返回的内容缓存的时间
proxy_cache_use_stale 后端服务器哪些状态可以以缓存响应;
proxy_connect_timeout 与后端建立连接超时
proxy_read_timeout 读后端服务器的超时
proxy_send_timeout 向后端服务器发送响应超时

ngx_http_headers_module <– 自定义响应首部
add_header X-Via $server_addr; 代理修改响应给客户端的报文

ngx_http_fastcgi_module <– 代理fastcgi协议,保持连接;(LNMP)
fastcgi_pass IP:PORT;
fastcgi_cache_path
fastcgi_cache
fastcgi_cache_key
fastcgi_cache_methods
fastcgi_cache_valid
fastcgi_keep_conn nginx要求保持连接;

注意:多个主机协作时,必须要同步时间;
Nginx后是fpm时,fpm的并发连接支撑能力不如httpd;并发管理能力不如httpd

1)将用户所有请求代理至后端主机;
server {
listen 80;
server_name www.ilinux.io;

location / {
#root /data/nginx/html;
proxy_pass http://192.168.10.11:80;
proxy_set_header X-Real-IP $remote_addr;
add_header X-Via $server_addr;
}
}
注意:需要在后端httpd主机上添加 %h –> %{X-Real-IP}i

2)将用户对不同的资源请求代理至不同主机;
server {
listen 80;
server_name www.ilinux.io;

proxy_set_header X-Real-IP $remote_addr;
add_header X-Via $server_addr;

location / {
#root /data/nginx/html;
proxy_pass http://192.168.10.11:80;
}

location ~* \.(jpg|gif|png|jpeg)$ {
proxy_pass http://192.168.10.12:80;
}
}

LNAMP:
server {
listen 80;
server_name www.ilinux.io;

proxy_set_header X-Real-IP $remote_addr;
add_header X-Via $server_addr;

location / {
#root /data/nginx/html;
proxy_pass http://192.168.10.11:80;
}

location ~* \.php$ {
proxy_pass http://192.168.10.12:80;
}
}
192.168.10.12
~]# yum -y install php php-mysql mariadb-server php-mbstring php-mcrypt
~]# scp phpMyAdmin-4.0.10.20-all-languages.zip 192.168.10.12:/var/www/html
# unzip phpMyAdmin-4.0.10.20-all-languages.zip
# ln -sv phpMyAdmin-4.0.10.20-all-languages pma
# cp pma/config.sample.inc.php pma/config.inc.php
# vim /etc/my.cnf.d/server.cnf
[mysqld]
skip_name_resolve=ON
innodb_file_per_table=ON
# systemctl start mariadb.service
# mysql_secure_installation
# mysql -uroot -hlocalhost -pmagedu
~]# systemctl restart httpd.service

http://www.ilinux.io/pma/
http://www.ilinux.io/pma/index.php

192.168.10.11
~]# scp phpMyAdmin-4.0.10.20-all-languages.zip 192.168.10.11:/var/www/html
# unzip phpMyAdmin-4.0.10.20-all-languages.zip
# ln -sv phpMyAdmin-4.0.10.20-all-languages pma

# tail /var/log/httpd/access_log
172.16.0.179 – – [17/Dec/2017:07:39:32 +0800] “GET /pma/themes/pmahomme/img/sprites.png HTTP/1.0” 200 61899 “http://www.ilinux.io/pma/phpmyadmin.css.php?server=1&token=d7a0893b2b2b56261eff189d123a25d9&nocache=6008347360ltr” “Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36”

3)静态内容在本地,动态在后端:
server {
listen 80;
server_name www.ilinux.io;

proxy_set_header X-Real-IP $remote_addr;
add_header X-Via $server_addr;

location / {
root /data/nginx/html;
#proxy_pass http://192.168.10.11:80;
}

location ~* \.php$ {
proxy_pass http://192.168.10.12:80;
}
}
http://www.ilinux.io/pma/index.php

172.16.0.6
~]# cp phpMyAdmin-4.0.10.20-all-languages.zip /data/nginx/html/
~]# cd /data/nginx/html/
# unzip phpMyAdmin-4.0.10.20-all-languages.zip
# ln -sv phpMyAdmin-4.0.10.20-all-languages pma
http://www.ilinux.io/pma/index.php
172.16.0.179 – – [17/Dec/2017:07:44:49 +0800] “GET /pma/themes/pmahomme/img/sprites.png HTTP/1.1” 200 61899 “http://www.ilinux.io/pma/phpmyadmin.css.php?server=1&token=6f042529e089b420daaa96176e8fcbda&nocache=4494879789ltr” “Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36” “-”

4)静态在后端:动态在后端(amp/p):
~]# yum -y install php php-mysql mariadb-server php-mbstring php-mcrypt
~]# vim /etc/my.cnf.d/server.cnf
~]# systemctl start mariadb.service
~]# mysql_secure_installation
~]# mysql -uroot -pmagedu

server {
listen
server_name

location / {
proxy_pass http://192.168.10.11:80;

}
location ~* \.php$ {
fastcgi_pass 192.168.10.11:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /data/apps$fastcgi_script_name;
include fastcgi_params;

proxy_pass http://192.168.10.11:80;
}

}

注意:LNMP可行,LNAMP跨网段搭建不出来;

压力测试:

注释fastcgi_cache fcache;
ab -c 100 -n 2000 http://www.ilinux.io/pma/index.php

配置缓存; 后先用curl请求几次;
Requests per second: 640.58 [#/sec] (mean)

启用缓存
Requests per second: 2828.87 [#/sec] (mean)

启用保持连接

http {
fastcgi_cache_path /data/nginx/fcgicache levels=2:2:2 keys_zone=fcache:10m max_size=20g;
}
server {
listen 80;
server_name www.ilinux.io;

location / {
root /data/nginx/html;
#proxy_pass http://192.168.10.12:80;
}

location ~* \.php$ {
fastcgi_pass 192.168.10.11:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /var/www/html$fastcgi_script_name/wp/;
include fastcgi_params;
}
[root@localhost nginx]# ls /data/nginx/fcgicache/
[root@localhost nginx]# <–缓存目录为空
~]# ab -c 100 -n 20000 www.ilinux.io/phpinfo.php
Requests per second: 3315.66 [#/sec] (mean)

打开缓存:
http {
fastcgi_cache_path /data/nginx/fcgicache levels=2:2:2 keys_zone=fcache:10m max_size=20g;
}
server {
listen 80;
server_name www.ilinux.io;

location / {
root /data/nginx/html;
#proxy_pass http://192.168.10.12:80;
}

location ~* \.php$ {
fastcgi_pass 192.168.10.11:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /var/www/html$fastcgi_script_name;
include fastcgi_params;

fastcgi_cache fcache;
fastcgi_cache_key $request_uri;
fastcgi_cache_valid 200 302 10m;
fastcgi_cache_valid 301 1h;
fastcgi_cache_valid any 1m;
}
~]# ab -c 100 -n 20000 www.ilinux.io/phpinfo.php
Requests per second: 8747.94 [#/sec] (mean)
# ls /data/nginx/fcgicache/
de
打开保持连接:
http {
fastcgi_cache_path /data/nginx/fcgicache levels=2:2:2 keys_zone=fcache:10m max_size=20g;
}
server {
listen 80;
server_name www.ilinux.io;

location / {
root /data/nginx/html;
#proxy_pass http://192.168.10.12:80;
}

location ~* \.php$ {
fastcgi_pass 192.168.10.11:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /var/www/html$fastcgi_script_name;
include fastcgi_params;

fastcgi_cache fcache;
fastcgi_cache_key $request_uri;
fastcgi_cache_valid 200 302 10m;
fastcgi_cache_valid 301 1h;
fastcgi_cache_valid any 1m;
fastcgi_keep_conn on
}

~]# ab -c 100 -n 20000 www.ilinux.io/phpinfo.php
Requests per second: 8503.63 [#/sec] (mean)

5) php-fpm状态页:
location ~* ^/(status|ping)$ {
fastcgi_pass 192.168.10.11:9000;
fastcgi_param SCRIPT_FILENAME /data/apps$fastcgi_script_name;
include fastcgi_params;
}

Nginx 负载均衡功能
四层调度
七层调度 ngx_http_upstream_module
支持健康状态检测;

调度:就会有session丢失的问题:
1) session绑定
SH + FWM
-p + FWM
cookie
2) session 集群
3) session server(memcached, redis)

七层调度: 仅能代理http协议!
http {
upstream {
server
server
}

server {

}
}

拓扑:
外网: 172.16.0.0/16
内网: 192.168.10.0/24
192.168.10.11
192.168.10.12

Nginx

1) 定义组: http { .. } 确保有include指令;
upstream websrvs {
server 192.168.10.11:80;
server 192.168.10.12:80;
}
2) 调用组:
server {
listen 80;
server_name www.ilinux.io;

location / {
root /data/nginx/html;
proxy_pass http://websrvs;
}
}
默认是轮循的
[root@localhost nginx]# curl www.ilinux.io
<h1>Upstream Server 2</h1>
[root@localhost nginx]# curl www.ilinux.io
<h1>1Upstream Server 1</h1>
[root@localhost nginx]# curl www.ilinux.io
<h1>Upstream Server 2</h1>
[root@localhost nginx]# curl www.ilinux.io
<h1>1Upstream Server 1</h1>
[root@localhost nginx]# curl www.ilinux.io
<h1>Upstream Server 2</h1>
[root@localhost nginx]#

(1)upstream servername
upstream websrvs {
server 192.168.10.11:80 weight=2;
server 192.168.10.12:80;
}

server {
listen 80;
server_name www.ilinux.io;

location / {
root /data/nginx/html;
proxy_pass http://websrvs;
}
}
(2) server address [parameters];

1) weight= 默认为1;rr,有权重时表示wrr;
upstream websrvs {
server 192.168.10.11:80 weight=2;
server 192.168.10.12:80;
}
WRR算法:首轮是WRR的;
~]# for i in {1..100}; do curl www.ilinux.io; done
<h1>Upstream Server 1</h1>
<h1>Upstream Server 1</h1>
<h1>Upstream Server 2</h1>
<h1>Upstream Server 1</h1>
<h1>Upstream Server 1</h1>

2) max_conns=number 定义server指定的服务器最大并发连接数;

3)max_fails=number
禁用健康状态检测:max_fails=0;
4)fail_timeout=time
每隔多久检测一次?默认有一个时间间隔
检测一次fail_timeout时间内没有响应;就认为失败;
一共失败max_fails次就标记此服务器不可用;
例如:
默认情况下:在11主机上使用iptables规则禁止;
~]# iptables -A INPUT -d 192.168.10.11 -p tcp –dport 80 -j REJECT
请求:
# for i in {1..10}; do curl www.ilinux.io; done
<h1>Upstream Server 2</h1> <–
<h1>Upstream Server 2</h1> <-
<h1>Upstream Server 2</h1> <–
<h1>Upstream Server 2</h1> <–
<h1>Upstream Server 2</h1> <-
启动此服务:~]# iptables -F
请求:
# for i in {1..10}; do curl www.ilinux.io; done
<h1>Upstream Server 1</h1> <–
<h1>Upstream Server 2</h1> <-
<h1>Upstream Server 1</h1> <–
<h1>Upstream Server 1</h1> <–
<h1>Upstream Server 2</h1> <-

自定义:检测失败超时1s, 允许失败3次;
upstream websrvs {
server 192.168.10.11:80 weight=2;
server 192.168.10.12:80 fail_timeout=1 max_fails=3;
}

server {
listen 80;
server_name www.ilinux.io;

location / {
root /data/nginx/html;
proxy_pass http://websrvs;
}
}

在运行过程中宕掉:Upstream Server 2;
<h1>Upstream Server 1</h1>
<h1>Upstream Server 1</h1>
<h1>Upstream Server 2</h1>
<h1>Upstream Server 1</h1>
<h1>Upstream Server 1</h1>
<h1>Upstream Server 1</h1>
<h1>Upstream Server 1</h1>
<h1>Upstream Server 1</h1>
<h1>Upstream Server 1</h1>

5)backup 定义备用主机:所以主机都挂了,才会响应;任何一个主机在线都不会启用此主机;
upstream websrvs {
server 192.168.10.11:80 weight=2;
server 192.168.10.12:80 fail_timeout=1 max_fails=3;
server 127.0.0.1:80 backup;
}

没有backup时:
<h1>Maintanance Time</h1>
<h1>Upstream Server 1</h1>
<h1>Upstream Server 2</h1>
<h1>Upstream Server 1</h1>
<h1>Maintanance Time</h1>
<h1>Upstream Server 1</h1>
/usr/share/nginx/html/index.html
让全部挂掉:
~]# killall httpd
<h1>Maintanance Time</h1>
<h1>Maintanance Time</h1>
任何一个主机上线:
~]# systemctl start httpd
<h1>Upstream Server 1</h1>
<h1>Upstream Server 1</h1>
<h1>Upstream Server 1</h1>

6)灰度发布时,人为将主机宕机;
upstream websrvs {
server 192.168.10.11:80 weight=2;
server 192.168.10.12:80 fail_timeout=1 max_fails=3 down;
server 127.0.0.1:80 backup;
}
默认:
<h1>Upstream Server 1</h1>
<h1>Upstream Server 1</h1>
<h1>Upstream Server 2</h1>
<h1>Upstream Server 1</h1>
<h1>Upstream Server 1</h1>
人为宕机
<h1>Upstream Server 1</h1>
<h1>Upstream Server 1</h1>
<h1>Upstream Server 1</h1>
<h1>Upstream Server 1</h1>
上线时,去掉down 参数:

7)slow_start=time 慢启动;避免大量请求一下子涌进来; 付费;

3)ip_hash 将来自同一个IP的请求 始终定向到同一个upstream server,粒度很粗糙,因为基于来源IP调度;
upstream websrvs {
ip_hash;
server 192.168.10.11:80 weight=2;
server 192.168.10.12:80 fail_timeout=1 max_fails=3;
#server 127.0.0.1:80 backup; ip hash绑定向,挂了看到的是挂了;
}
for i in {1..100}; do curl www.ilinux.io; done
<h1>Upstream Server 2</h1>
<h1>Upstream Server 2</h1>
<h1>Upstream Server 2</h1>
<h1>Upstream Server 2</h1>
宕机server 2
<h1>Upstream Server 2</h1>
<h1>Upstream Server 1</h1>
宕机server 1
<html>
<head><title>502 Bad Gateway</title></head>
<body bgcolor=”white”>
<center><h1>502 Bad Gateway</h1></center>
<hr><center>nginx/1.12.2</center>
</body>
</html>

4)hash key; 基于cookie调度;hash什么变量 就把 变量中的值 当作键;商业版才能使用cookie指令完成基于cookie高效调度;
获取保存cookie的变量名;Alphabetical index of variables
$cookie_name
1)ip_hash; ip哈希:把源IP绑定,把同一个源IP请求绑定在一个Upstream server.
hash $remote_addr;

upstream websrvs {
hash $remote_addr;
server 192.168.10.11:80 weight=2;
server 192.168.10.12:80 fail_timeout=1 max_fails=3;
#server 127.0.0.1:80 backup;
}
<h1>Upstream Server 2</h1>
<h1>Upstream Server 2</h1>
<h1>Upstream Server 2</h1>
<h1>Upstream Server 2</h1>

2)把URI绑定,把对同一个URI请求绑定在一个Upstream server. 后端为缓存服务器非常好用
hash $request_uri;
http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request
$request_uri 完整的URI: /en/docs/http/ngx_http_core_module.html#var_request
$request 不完整的URI:/en/docs/http/ngx_http_core_module.html

3)consistent: 一致性哈希:不使用时是取模法。后端为缓存服务器非常好用
如何将同一个(源IP|URI)绑定至upstream server。
首次对URI请求记录于内存中的hash表中;键是URI;值是后端主机的IP;
以后对URI请求查表,在发到指定主机;速度不快;

换一方式,提高速度:分布式系统均会用到;
1)取模法:URI哈希计算后,对权重取模,根据结果调度;
缺点:一台服务器离线,算法失效,权重没了;缓存失效;整个系统不可用;

2)一致性哈希算法:Berkeley大学教授;
将2^32取模结果:[0,2^32-1 ]组成一个环;将后端主机的IP地址做hash计算对2^32取模,因此主机位于环上的某处;
请求来时,hash计算对2^32取模,位于环上的某处;顺时针遇到的主机则处理;
缺点:所有ip的hash结果对2^32取模,都位于环上的某处的附近;
避免缺点:对hash值加salt后取模,将一个主机分散为50个节点,因此就分布开了;

示例:
upstream websrvs {
hash $remote_addr consistent;
server 192.168.10.11:80 weight=1;
server 192.168.10.12:80 fail_timeout=1 max_fails=3;
#server 127.0.0.1:80 backup;
}

同一个URI始终调度至同一个服务器;
# for i in {1..20}; do echo “Test Page $i On US1” > /var/www/html/test$i.html; done
# for i in {1..20}; do echo “Test Page $i On US2” > /var/www/html/test$i.html; done

# for i in {1..10}; do curl www.ilinux.io/test1.html; done
Test Page 1 On US2
Test Page 1 On US2
Test Page 1 On US2
Test Page 1 On US2
Test Page 1 On US2
Test Page 1 On US2

对每个页面请求3次,把每个页面请求一遍;
for i in {1..20}; do for i in {1..3}; do curl www.ilinux.io/test1.html; done; done

5)keepalive connections; 提高反代服务器的并发能力;每个worker维持长连接个数,每个长连接可承载多个用户请求,用户请求被绑定至同一个主机;
upstream memcached_backend {
keepalive 32;
}

6)least_conn; LC算法,weight相同时lc; weight不同时,wlc;

Nginx的4层代理 及 负载均衡:
ngx_stream_core_module
1)验证此模块是否可以使用:rpm -qa | grep nginx-mod-stream
stream {
server {
listen 22922;
proxy_pass sshsrvs;
}

server {
listen 80;
proxy_pass websrvs;
}
server {
listen 3306;
proxy_pass mydb;
}
upstream sshsrvs {
server 192.168.10.11:22;
server 192.168.10.12:22;
}
upstream websrvs {
server 192.168.10.11:80;
server 192.168.10.12:80;
}
upstream mydb {
server 192.168.10.11:3306;
server 192.168.10.12:3306;
}
}

结构:
stream {
upstream sshsrvs {
server 192.168.10.130:22;
server 192.168.10.131:22;
hash $remote_addr consistent;
}

server {
listen 172.16.100.6:22202;
proxy_pass sshsrvs;
proxy_timeout 60s;
proxy_connect_timeout 10s;
}
}

listen address:port [ssl] [udp]
监听的端口;
默认为tcp协议;
udp: 监听udp协议的端口;

反代的是dns服务,就需要添加udp;

将用户的请求反代至2个后端主机
1)配置在http { … } 之外;
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

# Load dynamic modules. See /usr/share/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;

events {
worker_connections 1024;
}
2)不是在本地提供任何服务,不需要server_name和Root;
stream {
server {
listen 10080;
proxy_pass 192.168.10.11:22;
}
}
# nginx -t
# killall nginx
# nginx
# ss -tnlp
~]# ssh -p 10080 root@172.16.0.6
ssh 172.16.0.6 10080

代理80端口:
stream {
server {
listen 10080;
proxy_pass 192.168.10.11:22;
}

server {
listen 80;
proxy_pass 192.168.10.12:80;
}
}
# curl 172.16.0.6
<h1>Upstream Server 2</h1>

轮循22:
stream {
server {
listen 10080;
proxy_pass ssh;
}
upstream ssh {
server 192.168.10.11:22;
server 192.168.10.12:22;
}
}
# for i in {1..10}; do ssh -p 22022 root@172.16.0.6 ‘hostname’; done
ns1
ns2
ns1
ns2
ns1
轮循80:
server {
listen 80;
proxy_pass web;
}

upstream web {
server 192.168.10.12:80;
server 192.168.10.11:80;
}
# for i in {1..10}; do curl 172.16.0.6/test1.html; done
Test Page 1 On US2
Test Page 1 On US1
Test Page 1 On US2
Test Page 1 On US1
Test Page 1 On US2
Test Page 1 On US1

代理3306服务:
server {
listen 3306;
proxy_pass mariadb;
}

upstream mariadb {
server 192.168.10.12:3306;
server 192.168.10.11:3306;
}
*:3306 users:((“nginx”,32605,7),(“nginx”,32231,7))
并在后端主机生成可连接的远程账号;
# systemctl start mariadb.service
MariaDB [(none)]> GRANT ALL ON mydb.* TO ‘myuser’@’%’ IDENTIFIED BY ‘mypass’;
MariaDB [(none)]> FLUSH PRIVILEGES;
在第二个主机创建一个库;
MariaDB [(none)]> CREATE DATABASE mydb;

注意:先在代理服务器手动连接主机,通过再测试;
# mysql -umyuser -h192.168.10.11 -pmypass -e ‘SHOW DATABASES’
# mysql -umyuser -h192.168.10.12 -pmypass -e ‘SHOW DATABASES’

轮循:
# for i in {1..10}; do mysql -umyuser -h172.16.0.6 -pmypass -e ‘SHOW DATABASES’; done

默认支持健康状态检测:停止mysql
~]# systemctl stop mariadb.service
# for i in {1..10}; do mysql -umyuser -h172.16.0.6 -pmypass -e ‘SHOW DATABASES’; done
~]# systemctl start mariadb.service
# for i in {1..10}; do mysql -umyuser -h172.16.0.6 -pmypass -e ‘SHOW DATABASES’; done

可以将来自同一IP发自同一个主机:hash 命令

nginx编译安装:
默认安装功能适合,不要编译安装;不利于运维、分发
必须得编译时:
开发环境
仿照官方参数即可;

EPEL:获取编译参数:
# nginx -V

开发环境 Development Tools Server Platform Development (仅依赖gcc)
开发组件:pcre-devel(rewrite) openssl-devel 编译需要头文件或库文件;

添加用户:useradd -r nginx

编译第三方的模块:https://www.nginx.com/resources/wiki/modules/
Cache purge:修剪缓存的模块;自带的功能需要商业版;
Mogilefs:nginx作为modfilefs的客户端

注意不需要打补丁,–with指定nginx自动收录;
–add-module=PATH enable external module 编译进核心
–add-dynamic-module=PATH enable dynamic external module 支持动态装载或卸载;
–with 默认没有启用;指定时启用
–without 默认启用; 指定时禁用

第三方模块:在编译参数后添加 –add-module= , 指明module解压出的路径即可 ;
unzip ngx_cache_purge-master.zip
–add-module=/root/ngx_cache_purge-master

yum -y install pcre pcre-devel
yum -y install openssl openssl-devel
yum -y install gcc-c++ autoconf automake
yum install -y zlib-devel
yum -y install libxml2 libxml2-dev
yum -y install libxslt-devel
yum -y install gd-devel
yum -y install perl-devel perl-ExtUtils-Embed
yum -y install GeoIP GeoIP-devel GeoIP-data
去掉此选项:
–with-google_perftools_module

make && make install
默认网页:/etc/nginx/html

提供unit file文件:
vim /usr/lib/systemd/system/nginx.service
基于官方编译,用官方的Unit; 基于EPEL用EPEL
[Unit]
Description=The nginx HTTP and reverse proxy server
After=network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
PIDFile=/run/nginx.pid
# Nginx will fail to start if /run/nginx.pid already exists but has the wrong
# SELinux context. This might happen when running nginx -t from the cmdline.
# https://bugzilla.redhat.com/show_bug.cgi?id=1268621
ExecStartPre=/usr/bin/rm -f /run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
KillSignal=SIGQUIT
TimeoutStopSec=5
KillMode=process
PrivateTmp=true

[Install]
WantedBy=multi-user.target

systemctl daemon-reload

启用nginx(可能需要创建目录,nginx用户,nginx组)

nginx 官方仓库
只能必要时才编译安装;
http://nginx.org/packages
http://nginx.org/packages/centos/7/

SRPMS/ 源码格式的rpm:安装–制作;编译时,应该这样弄;
# wget http://nginx.org/packages/centos/7/SRPMS/nginx-1.12.0-1.el7.ngx.src.rpm
# rpm -vih nginx-1.12.0-1.el7.ngx.src.rpm
# tree rpmbuild/
rpmbuild/
├── SOURCES
│   ├── COPYRIGHT
│   ├── logrotate
│   ├── nginx-1.12.0.tar.gz
│   ├── nginx.check-reload.sh
│   ├── nginx.conf
│   ├── nginx-debug.service
│   ├── nginx-debug.sysconf
│   ├── nginx.init.in
│   ├── nginx.service
│   ├── nginx.suse.logrotate
│   ├── nginx.sysconf
│   ├── nginx.upgrade.sh
│   └── nginx.vh.default.conf
└── SPECS
└── nginx.spec <–如何制作 rpm包

~]# vim rpmbuild/SPECS/nginx.spec
%define BASE_CONFIGURE_ARGS $(echo “–prefix=
在其中添加第三方模块即可;

制作rpm包:
~]# rpmbuild -bb rpmbuild/SPECS/nginx.spec

 

 

本文来自投稿,不代表Linux运维部落立场,如若转载,请注明出处:http://www.178linux.com/90448

评论列表(0条)

  • 马哥教育
    马哥教育 2018-01-07 17:50

    总结的比较全面~~能注意下排版技巧会更好~

联系我们

400-080-6560

在线咨询

工作时间:周一至周五,9:30-18:30,节假日同时也值班

QR code