Nginx一个具有高性能的HTTP和反向代理的web服务器。
目前负载均衡技术中的主流方案,是一个轻量级的高性能HTTP反向代理服务器,支持TCP、UDP、SMTP、HTTPS等。基于多路复用模型构建出的产物,理论上单节点
同时支持5W
并发连接。如动静分离、资源压缩、缓存配置、IP黑名单、高可用保障等高级特性
可以作为HTTP代理服务器和反向代理服务器,支持通过缓存加速访问,可以完成简单的负载均衡和容错,支持包过滤功能,支持SSL等。
SSI 是一种类似于 ASP 的基于服务器的网页制作技术。将内容发送到浏览器之前,可以使用“服务器端包含(SSI)”指令将文本、图形或应用程序信息包含到网页中。例如,可以使用 SSI 包含时间/日期戳、版权声明或供客户填写并返回的表单。对于在多个文件中重复出现的文本或图形,使用包含文件是一种简便的方法。将内容存入一个包含文件中即可,而不必将内容输入所有文件。通过一个非常简单的语句即可调用包含文件,此语句指示 Web 服务器将内容插入适当网页。而且,使用包含文件时,对内容的所有更改只需在一个地方就能完成。因为包含 SSI 指令的文件要求特殊处理,所以必须为所有 SSI 文件赋予 SSI 文件扩展名。默认扩展名是 .stm、.shtm 和 .shtml
Nginx的官方下载网站为http://nginx.org/en/download.html,源码地址http://nginx.org/download/
yum install -y gcc pcre pcre-devel zlib zlib-devel openssl openssl-devel进行全部安装
mkdir -p /usr/local/nginx/core
cd /usr/local/nginx/core
wget http://nginx.org/download/nginx-1.20.1.tar.gz
tar -xzf nginx-1.20.1.tar.gz
cd ./configure
make
make install
sudo yum install -y yum-utils ## 安装过忽略
vim /etc/yum.repos.d/nginx.repo
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/ $basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
[nginx-mainline]
name=nginx mainline repo
baseurl=http://nginx.org/packages/mainline/centos/$re leasever/$basearch/
gpgcheck=1
enabled=0
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
yum list | grep nginx ##查看是否安装成功
yun install -y nginx
复杂对于简单区别就是编译可以指定参数 (详情见附录A)。
–prefix=path 安装目录,默认值/usr/local/nginx;
–sbin-path=path执行程序路径,默认值$prefix/sbin/nginx ;
–modules-path=path模块安装目录,默认$prefix/modules;
–conf-path=path配置文件,默认prefix/conf/nginx.conf;
–error-log-path = 指向错误日志目录;
–pid-path= 指向 pid 文件(nginx.pid)
–lock-path= 指向 lock 文件(nginx.lock)(安装文件锁定,防止安装文件被别人利用,或自己误操作。)
–user= 指定程序运行时的非特权用户; –group= 指定程序运行时的非特权用户组
–builddir= 指向编译目录
http-log-path;pid-path=paht默认prefix/logs/nginx.pid;
./configure --prefix=/usr/local/nginx \ --sbin-path=/usr/local/nginx/sbin/nginx \ --modules-path=/usr/local/nginx/modules \ --conf-path=/usr/local/nginx/conf/nginx.conf \ --error-log-path=/usr/local/nginx/logs/error.log \ --http-log-path=/usr/local/nginx/logs/access.log \ --pid-path=/usr/local/nginx/logs/nginx.pid \ --lock-path=/usr/local/nginx/logs/nginx.lock
./configure --with-http_stub_status_module --with-http_ssl_module --with-stream
--with-select_module、--without-select_module、 --with-poll_module、--without-poll_module
./configure --add-module=/path/to/nginx_tcp_proxy_module //代理
./nginx -s stop
rm -rf /usr/local/nginx
make clean
USR2信号给master进程,告诉它进程要平滑升级,会重新开启对应的master和work进程,整个系统有两个master。旧的PID被记录在nginx.pid.oldbin文件中,接着再次发送quit信号给旧的master,让其处理完请求后再进行关闭。
kill -USR2 PID / kill -USR2 cat /usr/local/nginx/logs/nginx.pid
TERM/INT:立即关闭整个服务;QUIT:优雅关闭;HUP:重读配置文件;WINCH:给work进程发送quit指令。
nginx -s stop(term) ; quit(quit);reload(HUP)
例如:版本1.16.1升级到1.20.1
进入1.16.1安装目录;./configure;make && make install编译与安装
进入1.20.1安装目录;./configure;make
cd /usr/local/nginx/sbin
mv nginx nginxold
cd ~/nginx/core/nginx-1.20.1/objs
cp nginx /usr/local/nginx/sbin
more /usr/local/logs/nginx.pid.oldbin
前两步一样;然后进入1.20.1目录(安装目录),执行make upgrade。
http里面中 server块是配置和虚拟主机相关的内容。location块是接收请求字符串与location后面的值进行匹配,对特定请求进行处理。 http->server->location (父含有多个孩子)
debug|info|notice|warn|error|crit|alert|emerg,翻译过来为调试|信 息|通知|警告|错误|临界|警报|紧急,这块建议大家设置的时候不要设置成info以下的等级,因为会带来大量的磁盘I/O消耗,影响Nginx的性能。
events {
accept_mutex on|off; #设置网络连接序列化(防止多个进程对连接的争抢,一个个唤醒接收)
multi_accept off|on; #设置是否允许同时接收多个网络连接
worker_connections 1024; #最大连接数。不仅仅包括和前端用户建立的连接数,而是包括所有可能的连接数
use method; #默认根据操作系统。select/poll/epoll/kqueue等。内核2.6 可以用epoll
}
某些接口的时候需要返回指定的文本字符串或者json字符串,如果逻辑非常简单或者干脆是固定的字符串,那么可以使用nginx快速实现,这样就不用编写程序响应请求了,可以减少服务器资源占用并且响应性能非常快。
location /get_json{
default_type application/json;
return 200 '{"name":"TOM","age":18}';
}
http {
charset utf-8;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
server_tokens off;
log_not_found off;
types_hash_max_size 2048;
types_hash_bucket_size 64;
client_max_body_size 16M;
# 注意如果启用 SSI,那么 Last-Modified 头和 Content-Length 头不会传递
# 建议写道location里面 location ~* \.shtml${ ssi on; ssi_types text/shtml; ssi_value_length 1024}
ssi [ on | off ]
# MIME 默认
include mime.types;
default_type application/octet-stream;
# Logging
#正向代理,服务器收到是代理IP地址
#client send request=>clientIp=192.168.1.1 serverIp=>192.168.1.200
log_format client 'client send request=>clientIp=$remote_addr serverIp=>$host';
log_format server1 '===>server1 access log';
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 /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log warn;
sendfile on; #提高Nginx处理静态资源的性能
keepalive_timeout 65; #用来设置长连接的超时时间,默认75s
keepalive_requests 100; #设置一个keep-alive连接使用次数,默认100
include /XXX/XXX/conf.d/server/*.conf; #如nginx_gzip.conf
}
使用keepalive模式,可以告诉服务器端在处理完 一个请求后保持这个TCP连接的打开状态,若接收到来自这个客户端的其 他请求,服务端就会利用这个未被关闭的连接,而不需要重新创建一个新 连接,提升效率,但是这个连接也不能一直保持,这样的话,连接如果过 多,也会是服务端的性能下降,这个时候就需要我们进行设置其的超时时 间
详细参数说明参考
server1.conf
server{
#配置监听端口和主机名称
listen 8081;
# 虚拟主机的域名,可以写多个域名
server_name localhost;
#配置请求处理日志存放路径
access_log /home/www/myweb/server1/logs/access.log server1;
#配置错误页面
error_page 404 /404.html;
#配置处理/server1/location1请求的location
location /server1/location1{
root /home/www/myweb;
index index_sr1_location1.html;
}
#配置处理/server1/location2请求的location
location /server1/location2{
root /home/www/myweb;
index index_sr1_location2.html;
}
#配置错误页面转向
location = /404.html {
root /home/www/myweb; 22 index 404.html;
}
}
[Unit]
Description=nginx web service
Documentation=http://nginx.org/en/docs/
After=network.target
[Service]
Type=forking
PIDFile=/usr/local/nginx/logs/nginx.pid
ExecStartPre=/usr/local/nginx/sbin/nginx -t -c /usr/local/nginx/conf/nginx.conf
ExecStart=/usr/local/nginx/sbin/nginx
ExecReload=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/usr/local/nginx/sbin/nginx -s stop
PrivateTmp=true
[Install]
WantedBy=default.target
chmod 755 /usr/lib/systemd/system/nginx.service
启动: systemctl start nginx
停止: systemctl stop nginx
重启: systemctl restart nginx
重新加载配置文件: systemctl reload nginx
查看nginx状态: systemctl status nginx
开机启动: systemctl enable nginx
vim /etc/profile
在最后一行添加 export PATH=$PATH:/usr/local/nginx/sbin 12
使之立即生效:source /etc/profile
# vim nginx-log-rotate
/data/weblogs/*.log {
nocompress
daily
copytruncate
create
notifempty
rotate 7
olddir /data/weblogs/old_log
missingok
dateext
postrotate
/bin/kill -HUP `cat /var/run/nginx.pid 2> /dev/null` 2> /dev/null || true
endscript
}
# vim /etc/crontab 设置计划任务
59 23 * * * root ( /usr/sbin/logrotate -f /PATH/TO/nginx-log-rotate)
/data/weblogs/*.log 使用通配符时,/data/weblogs/目录下的所有匹配到的日志文件都将切割。如果要切割特定日志文件,就指定到该文件.
静态资源即指在服务器端真实存在并且能直接拿来展示的一些文件,比如常见的html页面、css文件、js文件、图 片、视频等资源; 动态资源即指在服务器端真实存在但是要想获取需要经过一定的业务逻辑处理,根据不同的条件展示在页面不同这 一部分内容,比如说报表数据展示、根据当前登录用户展示相关具体数据等资源;
listen:127.0.0.1:8000;监听指定IP和端口(不写IP默认是本机)
server{
#default_server属性是标识符,用来将此虚拟主机设置成默认主机。所谓的默认主机指的是如果没有匹配到对应的address:port,则会默认执行的。
listen 8080 default_server;
server_name:设置虚拟主机服务名称。精准匹配、通配符(只能出现在首段或尾段)、正则表达式(~ 作为开始标记。如~^www.(\w+).com$以www开头,com结尾,任意字符匹配)
hosts:是一个没有扩展名的系统文件,可以用记事本等工具打开,其作用 就是将一些常用的网址域名与其对应的IP地址建立一个关联“数据库”,当 用户在浏览器中输入一个需要登录的网址时,系统会首先自动从hosts文 件中寻找对应的IP地址,一旦找到,系统会立即打开对应网页,如果没有 找到,则系统会再将网址提交DNS域名解析服务器进行IP地址的解析。
匹配执行顺序:exact_success -> wildcard_before_success -> wildcard_after_success -> regex_success -> default_server not found server!!
location:[ = | ~ | ~* | ^~ |@ ] uri{…}。/abc是以abc开头的;=/abc是精准匹配;~^/abc\w$ 用于表示当前uri中包含了正则表达式,并且区分大小写;~*^/abc\w$ 用于表示当前uri中包含了正则表达式,并且不区分大小写; ^~
/abc 与/abc功能一致,不同是模式匹配就停止搜索其他模式了。
root:设置请求的根目录(root路径+location路径)。
index:设置网站的默认首页。
error_page:code uri;
#指定具体跳转的地址
error_page 404 http://www.itcast.cn;
#指定重定向地址
error_page 404 /50x.html;
error_page 500 502 503 504 /50x.html;
location =/50x.html{
root html;
}
#使用location的@符合完成错误信息展示
error_page 404 @jump_to_error;
location @jump_to_error {
default_type text/plain;
return 404 'Not Found Page...';
}
#可选项=[response]的作用是用来将相应代码更改为另外一个
error_page 404 =200 /50x.html; #当返回404时候,浏览器看到返回200状态码
sendfile on:用于开启高效的文件传输模式。
tcp_nopush on:在senfile打开的状态下才会生效,主要提升网络包的传输效率。
tcp_nodelay on:该指令必须在keep-alive连接开启的情况下才生效,来提高网络包传输的’实时性’。
sendfile可以开启高效的文件传输模式,tcp_nopush开启可以确保在发送到客户端之前数据包已经充分“填满”, 这大大减少了网络开销,并加快了文件发送的速度。 然后,当它到达最后一个可能因为没有“填满”而暂停的数据包时,Nginx会忽略tcp_nopush参数, 然后,tcp_nodelay强制套接字发送数据。由此可知,TCP_NOPUSH可以与TCP_NODELAY一起设置,它比单独配置TCP_NODELAY具有更强的性能。
可以通过配置gzip来对静态资源进行压缩,相关的指令可以配置在http块、server块和location块中。
ngx_http_gzip_module模块; ngx_http_gzip_static_module模块; ngx_http_gunzip_module模块。
ngx_http_gzip_module模块
gzip on; #开启或关闭
gzip_types application/javascript; #根据响应页的MIME类型选择开启Gzip压缩功能;如是*号代表所有
gzip_comp_level 6; #压缩程度。默认1,程度越高越费时间
gzip_vary off|on; #是告诉接收方,所发送的数据经过了Gzip压缩处理
# gzip_buffers 32 4k|16 8k; #处理请求压缩的缓冲区的数量和大小(建议不设置采用系统默认)
gzip_disable "MSIE [1-6]\."; #针对不同种类客户端发起的请求,选择性开启和关闭Gzip功能(排除一些明显不支持Gzip的浏览器);对IE6以下的版本不进行压缩。
# gzip_http_version:针对不同http协议版本,选择性开启和关闭功能(建议不设置)。
gzip_min_length 5k; #传输数据大小,来选择开启和关闭功能(如果要压缩的数据比较小的化,可能出现越压缩数据量越大的情况)。
gzip_proxied off; #设置是否对服务端返回的结果进行Gzip压缩(expired|no-cache|nostore|private|no_last_modified|no_etag|auth|any)
很多地方用到,可以单独放一个配置文件中,然后通过include指令加载nginx_gzip.conf
ngx_http_gzip_static_module模块
需要安装
cd /root/nginx/core/nginx-1.16.1
make clean ;#清空之前编译的内容
./configure --with-http_gzip_static_module;
make ;#编译
mv objs/nginx /usr/local/nginx/sbin #编译后文件放到安装目录下的sbin
make upgrade #更新命令
【Gzip和sendfile共存问题】:sendfile不经过用户进程,Gzip经过用户进程。
gzip_static on; #检查与访问资源同名的.gz文件,response中以gzip相关的header返回.gz文件的内容。
浏览器缓存:成本最低的一种缓存实现;减少网络带宽消耗;降低服务器压力;减少网络延迟,加快页面打开速度。
header | 说明 |
---|---|
Expires | 缓存过期的日期和时间 |
Cache-Control | 设置和缓存相关的配置信息 |
Last-Modified | 请求资源最后修改时间 |
ETag | 请求变量的实体标签的当前值,比如文件的MD5值 |
# Nginx进行缓存相关设置
expires off; #-1不缓存;0最大值 ; 7d 7天过期
add_header name value [always]; #用来添加指定的响应头和响应值
deny all; #禁止下载
同源策略 :一种约定,是浏览器最核心也是最基本的安全功能(需要协议、域名、端口相同)。
跨域问题 : 不满足同源策略。
#在不同源的 location /{}内加上跨域报头
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE;
实现原理:头信息referer,告诉浏览器该网页是从哪个页面链接过来的。
valid_referrers:通过查看referer自动和valid_referers后面的内容进行匹配,匹配为0,不匹配为1,匹配过程中不区分大小写。
#location /images{ 特定目录images下所有资源
location ~*\.(png|jpg|gif){
#none:如果header中referer为空,允许访问;blocked:不带http等协议头的资源允许访问
#server_names:指定域名或IP;string:需要以~开头表示正则表达式。
valid_referers none blocked www.baidu.com 192.168.200.222 *.example.com example.* www.example.org ~\.google\.;
if ($invalid_referer){
return 403;
}
root /usr/local/nginx/html;
}
晋级方法:第三方模块【ngx_http_accesskey_module】
主要的作用是用来实现URL的重写。Nginx使用的是ngx_http_rewrite_module模块来解析和处理Rewrite功能的相关配置。根据相关变量重定向和选择不同的配置,从一个 location 跳转到另一个 location,不过这样的循环最多可以执行10 次,超过后 nginx 将返回 500 错误。
重写与转发:重写浏览器地址会发生变化而地址转发则不变;一次重写产生2次请求,转发产生1次请求;抽重写到的页面必须是一个完整的路径而转发则不需要;重写是两次请求所以request范围内属性不能传递给新页面而转发可以;转发速度快于重写。
set指令:【set $variable value】变量名要用 $ 开头,且不能与预设全局变量同名( _见附)。
if指令 :【if (condition){…}】根据选择不同的配置。 注意:尽量考虑使用 trp_files 代替。
$flag
0;if ($uri ~ ^/thumb/[0-9]+_160.jpg$){ set $flag “${flag}1” ;} if ($arg_unitid = 42012){set $flag “${flag}1”;} if ($flag = “011”){ echo “www.ttlsa.com”;}break指令 :处于同一作用域的Nginx配置中,位于它前面的指令配置生效,位于后面的指令配置无效。
return指令 :该指令用于完成对请求的处理,直接向客户端返回响应状态代码。
rewrite指令:【rewrite regex replacement [flag];】该指令通过正则表达式的使用来改变URI。可以同时存在一个或者多个指令,按照顺序依次对URL进行匹配和处理。replacement:匹配成功后,用于替换URI中被截取内容的字符串。如果该字符串是以"http://"或者"https://"开头的,则不会继续向下对URI进行其他处理,而是直接返回重写后的URI给客户端。flag:用来设置rewrite对URI的处理行为 last、break、redirect、permanent。
rewrite_log指令:该指令配置是否开启URL重写日志的输出功能。默认off。开启后,URL重写的相关日志将以notice级别输出到error_log指令配置的日志文件汇总。
uninitialized_variable_warn : 控制是否记录未初始化变量的警告信息。默认开启ON
域名跳转
server{
listen 80;
server_name www.360buy.com www.jingdong.com;
#在域名跳转的过程中携带请求的URI $1
rewrite ^(.*) http://www.jd.com$1 permanent;
}
http {
# 定义 image 日志格式
log_format imagelog '[$time_local] ' $image_file ' ' $image_type ' ' $body_bytes_sent ' ' $status;
# 开启重写日志
rewrite_log on;
server {
root /home/www;
location / {
# 重写日志输出规则信息
error_log logs/rewrite.log notice;
# 注意这里要用‘’单引号引起来,避免{}
rewrite '^/images/([a-z]{2})/([a-z0-9]{5})/(.*)\.(png|jpg|gif)$' /data?file=$3.$4;
# 注意不能在上面这条规则后面加上“last”参数,否则下面的 set 指令不会执行
set $image_file $3;
set $image_type $4;
}
location /data {
# 指定针对图片的日志格式,来分析图片类型和大小
access_log logs/images.log mian;
root /data/images;
# 应用前面定义的变量。判断首先文件在不在,不在再判断目录在不在,如果还不在就跳转到最后一个 url 里
try_files /$arg_file /image404.html;
}
location = /image404.html {
# 图片不存在返回特定的信息
return 404 "image not found\n";
}
}
}
# 如果想分别记录各个部分的 URL,可以使用正则表达式来捕获 URI,然后,给变量分配指定位置变量
# 指定$scheme 和$host 变量,因为要做一个永久重定向并希望 nginx 使用相同的参数来构造 URL。
rewrite ^/(home(/index)?|index(\.php)?)/?$ $scheme://$host/ permanent;
server {
rewrite ^(/images)/(.*)\.(png|jpg|gif)$ $1/$3/$2.$3 last;
location /images/ {
rewrite ^(/images)/(.*)\.(png|jpg|gif)$ $1/$3/$2.$3 break;
}
}
rewrite ^/images/(.*)_(\d+)x(\d+)\.(png|jpg|gif)$ /resizer/$1.$4?width=$2&height=$3? last;
nginx 重写规则说起来挺简单的,做起来就难,重点在于正则表达式,同时,还需要考虑到 nginx 执行顺序。
部署在用户先访问到的那几台服务器上,负责定位 IP 然后重定向用户请求的那个软件,我们叫它“调度器”。
将全网 IP 分为若干个 IP 段组,分组的依据通常是运营商或者地域,目的是让相同网络环境中的用户聚集到相同的组内;依据 CDN 服务器们的网络和容量,确定哪些 CDN 服务器适合服务哪些 IP 段组。
智能 DNS 是办法之一,稳定可靠且有效。缺点如下:
解决方案“调度器”:将用户先行引导到某一台或几台统一的服务器上去;让它拿到用户的真实 IP,计算出服务他的服务器;通过 HTTP302 或其它方式把用户定位到最终服务器上。
Nginx 可以在核心模块 HttpGeoModule(http://wiki.nginx.org/HttpGeoModule)的配合下实现调度:
http{
...
geo $useriprang {
ranges;
default a;
0.0.0.1-0.8.255.255 a;
0.9.0.0-0.255.255.255 a;
1.0.0.0-1.0.0.255 a;
1.0.1.0-1.0.1.255 b;
1.0.2.0-1.0.3.255 b;
1.0.4.0-1.0.7.255 a;
...
223.255.252.0-223.255.253.255 c;
223.255.254.0-223.255.254.255 a;
223.255.255.0-223.255.255.255 a;
}
upstream backend {
server 127.0.0.1:81;
}
server {
listen 80;
client_max_body_size 10240m;
location / {
proxy_redirect off;
proxy_pass http://backend$request_uri&useriprang=$useriprang;
proxy_next_upstream http_502 http_504 error timeout invalid_header;
proxy_cache cache_one;
proxy_cache_key $host:$server_port$uri$is_args$args;
expires 5s;
}
}
...
}
域名镜像:部分资源跳转.
镜像网站指定是将一个完全相同的网站分别放置到几台服务器上,并分别使用独立的URL进行访问。其中一台服务器上的网站叫主站,其他的为镜像网站。镜像网站和主站没有太大的区别,可以把镜像网站理解为主站的一个备份节点。可以通过镜像网站提供网站在不同地区的响应速度。镜像网站可以平衡网站的流量负载、可以解决网络宽带限制、封锁等
server {
listen 80;
server_name rewrite.myweb.com;
location ^~ /source1{
#proxy_pass http://zhu.myweb.com/web$1;
rewrite ^/source1(.*)$ http://zhu.myweb.com/web$1 last;
}
location ^~ /source2{
rewrite ^/source2(.*) http://zhu.myweb.com/web$1 last;
}
}
独立域名
server{
listen 80;
server_name search.hm.com;
rewrite ^(.*) http://www.hm.com/search$1 ;
}
server{
listen 81;
server_name item.hm.com;
rewrite ^(.*) http://www.hm.com/item$1 ;
}
目录自定添加”/“【0.8.48之后忽略,默认server_name_in_redirect为off】
server {
listen 80;
server_name localhost;
server_name_in_redirect on;
location /hm {
if (-d $request_filename){
rewrite ^/(.*)([^/])$ http://$host/$1$2/ permanent;
}
}
}
合并目录
包含URL的目录层级一般不要超过三层,否则的话不利于搜索引擎的搜索也给客户端的
输入带来了负担,但是将所有的文件放在一个目录下又会导致文件资源管理混乱并且访问文件的速度也会随着文件增多而慢下来,这两个问题是相互矛盾的,那么使用rewrite来解决上述问题:http://www.web.name/server/11/22/33/44/20.html (5层)
#客户端只需要输入http://www.web.name/server-11-22-33-44-20.html就可以访问到20.html页面了。这里也充分利用了rewrite指令支持正则表达式的特性。
server {
listen 80;
server_name www.web.name;
location /server{
rewrite ^/server-([0-9]+)-([0-9]+)-([0-9]+)- ([0-9]+)\.html$ /server/$1/$2/$3/$4/$5.html last;
}
}
防盗链
通过rewrite可以将防盗链的功能进行完善下,当出现防盗链的情况。
if ($invalid_referer){
#return 403; return 403 没有权限; return http://www.baidu.com;
rewrite ^/ http://www.web.com/images/forbidden.png;
}
locatin ~* ^.+\.(gif|jpg|png|swf|flv|rar|zip)${
valid_referers none blocked server_names *.web.com;
if ($invalid_referer){
rewrite ^/ http://www.web.com/images/forbidden.png;
}
}
location /file/{
root /server/file/;
valid_referers none blocked server_names *.web.com;
if ($invalid_referer){
rewrite ^/ http://www.web.com/images/forbidden.png;
}
}
简而言之就是正向代理代理的对象是客户端,反向代理代理的是服务端。
#服务端设置
http {
log_format main 'client send request=>clientIp=$remote_addr serverIp=>$host';
server{
listen 80;
server_name localhost;
access_log logs/access.log main;
location {
root html;
index index.html index.htm;
}
}
}
#客户端访问服务端,日志
client send request=>clientIp=192.168.1.1 serverIp=>192.168.1.200
#代理服务器设置,代理IP192.168.1.100
server {
listen 82;
resolver 8.8.8.8;
resolver_timeout 30s;
location /{
proxy_pass http://$host$request_uri;
}
access_log /data/httplogs/proxy-$host-aceess.log;
}
#internet选项->连接->局域网设置->代理服务器(代理IP和port)
#客户端设置后访问服务端,日志
client send request=>clientIp=192.168.1.100 serverIp=>192.168.1.200
Nginx反向代理模块的指令是由【nginx_http_proxy_module】模块进行解析。
proxy:该指令用来设置被代理服务器地址,可以是主机名称、IP地址加端口号形式。
#最好非根目录不要加/
server {
listen 80;
server_name localhost;
location /{
#proxy_pass http://192.168.200.146;
proxy_pass http://192.168.200.146/;
}
location /server{
#proxy_pass http://192.168.200.146;
proxy_pass http://192.168.200.146/;
}
}
#当客户端访问 http://localhost/server/index.html
#第二个proxy_pass就变成了http://localhost/index.html效果 就不一样了。
proxy_set_header:Nginx服务器接收到的客户端请求的请求头信息,然后将新的请求头发送给代理的服务器。proxy_set_header field value
proxy_redirect:用来重置头信息中的"Location"和"Refresh"的值。【proxy_redirect redirect replacement】:默认是default。可以off关闭。
#代理服务端192.168.1.100
server {
listen 8081;
server_name localhost;
location / {
proxy_pass http://192.168.1.200:8081/;
#200是目标服务器;100是要替换的值。
#默认值 是用proxy_pass变量做为第一个;location块uri变量为第二个
proxy_redirect http://192.168.1.200 http://192.168.1.100;
}
}
# 如果服务器1、服务器2的内容不一样,那我们可以根据用户请求来分发到不同的服务器
#代理服务器
server {
listen 8082;
server_name localhost;
location /server1 {
proxy_pass http://192.168.200.146:9001/;
}
location /server2 {
proxy_pass http://192.168.200.146:9002/;
}
}
#服务端
#server1
server {
listen 9001;
server_name localhost;
default_type text/html;
return 200 '192.168.200.146:9001
'
}
#server2
server {
listen 9002;
server_name localhost;
default_type text/html;
return 200 '192.168.200.146:9002
'
}
通过代理分开了客户端到应用程序服务器端的连接,实现了安全措施。在反向代理之前设置防火墙,仅留一个入口供代理服务器访问。
HTTPS是一种通过计算机网络进行安全通信的传输协议。它经由HTTP进行通信,利用 SSL / TLS 建立全通信,加密数据包,确保数据的安全性。TLS和SSL在传输层和应用层对网络连接进行加密。
参考ngx_http_gzip模块安装
将原有/usr/local/nginx/sbin/nginx进行备份
拷贝nginx之前的配置信息
在nginx的安装源码进行配置指定对应模块 ./configure – with-http_ssl_module
通过make模板进行编译
将objs下面的nginx移动到/usr/local/nginx/sbin下
在源码目录下执行 make upgrade进行升级,这个可以实现不停机添 加新模块的功能
server {
listen 443 ssl;
server_name localhost;
ssl_certificate server.cert;
ssl_certificate_key server.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;
}
}
ssl_certificate:为当前这个虚拟主机指定一个带有PEM格式证书的证书。
ssl_certificate_key:该指令用来指定PEM secret key文件的路径
ssl_session_cache:该指令用来配置用于SSL会话的缓存。ssl_sesion_cache off|none|[builtin[:size]][shared:name:size]
参数 | 说明 |
---|---|
off | 禁用会话缓存,客户端不得重复使用会话 |
none | 禁止使用会话缓存,客户端可以重复使用,但是并没有在缓存中存储会话参数 |
builtin | 内置OpenSSL缓存,仅在一个工作进程中使用 |
shared | 所有工作进程之间共享缓存,缓存的相关信息用name和size来指定 |
ssl_session_timeout:开启SSL会话功能后,设置客户端能够反复使用储存在缓存中的会话参数时间。
ssl_ciphers:指出允许的密码,密码指定为OpenSSL支持的格式。
ssl_prefer_server_ciphers:该指令指定是否服务器密码优先客户端密码.
openssl生成证书:openssl version
mkdir /root/cert
cd /root/cert
openssl genrsa -des3 -out server.key 1024
openssl req -new -key server.key -out server.csr
cp server.key server.key.org
openssl rsa -in server.key.org -out server.key
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
提高IO吞吐效率。
proxy_buffering on;
proxy_buffer_size 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
proxy_buffering :该指令用来开启或者关闭代理服务器的缓冲区。
proxy_buffers:该指令用来指定单个连接从代理服务器读取响应的缓冲区的个数和大小。
proxy_buffer_size:该指令用来设置从被代理服务器获取的第一部分响应数据的大小。保持与proxy_buffers中的size一致即可,当然也可以更小。
proxy_busy_buffers_size:该指令用来限制同时处于BUSY状态的缓冲总大小。
proxy_temp_path:当缓冲区存满后,仍未被Nginx服务器完全接受,响应数据就会被临时存放在磁盘文件上,该指令设置文件路径(注意path最多设置三层)
proxy_temp_file_write_size:该指令用来设置磁盘上缓冲文件的大小。
应用集群:将同一应用部署到多台机器上,组成处理集群,接收负载均衡设备分发的请求,进行处理并返回响应的数据。
负载均衡器:将用户访问的请求根据对应的负载均衡算法,分发到集群中的一台服务器进行处理。
1、解决服务器的高并发压力,提高应用程序的处理性能。
2、提供故障转移,实现高可用。
3、通过添加或减少服务器数量,增强网站的可扩展性。
4、在负载均衡器上进行过滤,可以提高系统的安全性
域名系统(服务)协议(DNS)是一种分布式网络目录服务,主要用于域 名与 IP 地址的相互转换。
大多域名注册商都支持对同一个主机名添加多条A记录(一个域名对应多个IP),这就是DNS轮询,DNS服务器将解析请求按照A记录的顺序,随机分配到不同的IP上,这样就能完成简单的负载均衡。DNS轮询的成本非常低,在一些不重要的服务器,被经常使用。
缺点:
1.可靠性低
假设一个域名DNS轮询多台服务器,如果其中的一台服务器发生故障,那么所有的访问该服务器的请求将不会有所回应,即使你将该服务器的IP从DNS中去掉,但是由于各大宽带接入商将众多的DNS存放在缓存中,以节省访问时间,导致DNS不会实时更新。所以DNS轮流上一定程度上解决了负载均衡问题,但是却存在可靠性不高的缺点。
2.负载均衡不均衡
DNS负载均衡采用的是简单的轮询负载算法,不能区分服务器的差异,不能反映服务器的当前运行状态,不能做到为性能好的服务器多分配请求,另外本地计算机也会缓存已经解析的域名到IP地址的映射,这也会导致使用该DNS服务器的用户在一定时间内访问的是同一台Web服务器,从而引发Web服务器减的负载不均衡。
负载不均衡则会导致某几台服务器负荷很低,而另外几台服务器负荷确很高,处理请求的速度慢,配置高的服务器分配到的请求少,而配置低的服务器分配到的请求多。
OSI(open systeminterconnection),叫开放式系统互联模型。
所谓四层负载均衡指的是OSI七层模型中的传输层,主要是基于IP+PORT的负载均衡
实现四层负载均衡的方式:
硬件:F5 BIG-IP、Radware等
软件:LVS、Nginx、Hayproxy等
所谓的七层负载均衡指的是在应用层,主要是基于虚拟的URL或主机IP的负载均衡
实现七层负载均衡的方式:
软件:Nginx、Hayproxy等
四/七的区别:
- 四层负载均衡数据包是在底层就进行了分发,而七层负载均衡数据包则在 最顶端进行分发,所以四层负载均衡的效率比七层负载均衡的要高。
- 四层负载均衡不识别域名,而七层负载均衡识别域名。
Nginx实现用到proxy_pass代理模块配置。Nginx的负载均衡是在Nginx的反向代理基础上把用户的请求根据指定的算法分发到一组【upstream虚拟服务池】。
upstream指令:【upstream name {…}】该指令是用来定义一组服务器,它们可以是监听不同端口的服务器,并且也可以是同时监听TCP和Unix socket的服务器。服务器可以指定不同的权重,默认为1。
server指令:【server name [paramerters]】该指令用来指定后端服务器的名称和一些参数,可以使用域名、IP、端口或者unix socket
#服务器端
server {
listen 9001;
server_name localhost;
default_type text/html;
location /{
return 200 '192.168.200.146:9001
';
}
}
server {
listen 9002;
server_name localhost;
default_type text/html;
location /{
return 200 '192.168.200.146:9002
';
}
}
#代理服务器
upstream backend{
server 192.168.200.146:9091;
server 192.168.200.146:9092;
}
server {
listen 8083;
server_name localhost;
location /{
proxy_pass http://backend;
}
}
#tcp代理
#1.安装代理插件
./configure --add-module=/path/to/nginx_tcp_proxy_module make make install
# 配置
http {
listen 80;
location /status {
check_status;
}
}
tcp {
# 这会出现一个问题,就是 tcp 连接会掉线。原因在于当服务端关闭连接的时候,客户端不可能立刻发觉连接已经被关闭,需要等到当 Nginx 在执行 check 规则时认为服务端链接关闭,此时 nginx 会关闭与客户端的连接
## --start
timeout 1d;
proxy_read_timeout 10d;
proxy_send_timeout 10d;
proxy_connect_timeout 30
## --end
upstream cluster_www_ttlsa_com {
# simple round-robin
server 127.0.0.1:1234;
check interval=3000 rise=2 fall=5 timeout=1000;
#check interval=3000 rise=2 fall=5 timeout=1000 type=ssl_hello;
#check interval=3000 rise=2 fall=5 timeout=1000 type=http;
#check_http_send "GET / HTTP/1.0\r\n\r\n";
#check_http_expect_alive http_2xx http_3xx;
}
server {
listen 8888;
proxy_pass cluster_www_ttlsa_com;
## --start
so_keepalive on;
tcp_nodelay on;
## --end
}
}
Nginx在1.9之后,增加了一个stream模块,用来实现四层协议的转发、代理、负载均衡等。stream模块的用法跟http的用法类似,允许我们配置一组TCP或者UDP等协议的监听,然后通过proxy_pass来转发我们的请求,通过upstream添加多个后端服务,实现负载均衡。
添加stream模块的支持
需要在编译的时候加上–with-stream
将原有/usr/local/nginx/sbin/nginx进行备份
拷贝nginx之前的配置信息
在nginx的安装源码进行配置指定对应模块 ./configure – with-stream
通过make模板进行编译
将objs下面的nginx移动到/usr/local/nginx/sbin下
在源码目录下执行 make upgrade进行升级,这个可以实现不停机添 加新模块的功能
stream指令:该指令提供在其中指定流服务器指令的配置文件上下文。和http指令同级。
upstream指令:该指令和http的upstream指令是类似的。
stream {
upstream redisbackend {
server 192.168.200.146:6379;
server 192.168.200.146:6378;
}
upstream tomcatbackend {
server 192.168.200.146:8080;
}
server {
listen 81;
proxy_pass redisbackend;
}
server {
listen 82;
proxy_pass tomcatbackend;
}
}
down:将该服务器标记为永久不可用,那么该代理服务器将不参与负载均衡。
backup:将该服务器标记为备份服务器,当主服务器不可用时,将用来传递请求.
max_conns:用来设置代理服务器同时活动链接的最大数量,默认为0,表示不限制,使用该配置可以根据后端服务器处理请求的并发量来进行设置,防止后端服务器被压垮。
max_fails:设置允许请求代理服务器失败的次数,默认为1。
fail_timeout:设置经过max_fails失败后,服务暂停的时间,默认是10秒。
upstream backend{
server 192.168.200.146:9001 down;
server 192.168.200.146:9002 backup;
server 192.168.200.146:9003 max_fails=3 fail_timeout=15;
}
Nginx的upstream支持如下六种方式的分配算法,分别是:
轮询:是upstream模块负载均衡默认的策略。每个请求会按时间顺序逐个分配到不同的后端服务器。轮询不需要额外的配置。
weight加权:用来设置服务器的权重,默认为1,权重数据越大,被分配到请求的几率越大。
upstream backend{
server 192.168.200.146:9001 weight=10;
server 192.168.200.146:9002 weight=5;
}
ip_hash:ip_hash指令能够将某个客户端IP的请求通过哈希算法定位到同一台后端服务器上。这样,当来自某一个IP的用户在后端Web服务器A上登录后,在访问该站点的其他URL,能保证其访问的还是后端web服务器A。
#设置后端服务器权重等方法将不起作用
upstream backend{
ip_hash;
#least_conn;
#hash &request_uri;
#fair;
server 192.168.200.146:9001;
server 192.168.200.146:9002;
}
least_conn:最少连接,把请求转发给连接数较少的后端服务器。轮询算法是把请求平均的转发给各个后端,使它们的负载大致相同;但是,有些请求占用的时间很长,会导致其所在的后端负载较高。这种情况下,least_conn这种方式就可以达到更好的负载均衡效果。
url_hash: 按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,要配合缓存命中来使用。同一个资源多次请求,可能会到达不同的服务器上,导致不必要的多次下载,缓存命中率不高,以及一些资源时间的浪费。而使用url_hash,可以使得同一个url(也就是同一个资源请求)会到达同一台服务器,一旦缓存住了资源,再此收到请求,就可以从缓存中读取。
fair:fair采用的不是内建负载均衡使用的轮换的均衡算法,而是可以根据页面大小、加载时间长短智能的进行负载均衡。。需要添加[nginx-upstream-fair]
- 下载地址为: https://github.com/gnosek/nginx-upstream-fair
- unzip nginx-upstream-fair-master.zip
- mv nginx-upstream-fair-master fair
- ./configure --add-module=/root/fair
- make
如果报错,在Nginx的源码中 src/http/ngx_http_upstream.h,找到
ngx_http_upstream_srv_conf_s,在模块中添加添加default_port属性:
in_port_t default_port- 更新nginx 参考上面nginx更新步骤
服务器
upstream videobackend{
server 192.168.200.146:9001;
server 192.168.200.146:9002;
}
upstream filebackend{
server 192.168.200.146:9003;
server 192.168.200.146:9004;
}
server {
listen 8084;
server_name localhost;
location /video/ {
proxy_pass http://videobackend;
}
location /file/ {
proxy_pass http://filebackend;
}
}
upstream backend{
server 192.168.200.146:9001;
server 192.168.200.146:9002;
}
server {
listen 80;
server_name localhost;
location /file/ {
rewrite ^(/file/.*) /server/$1 last;
}
location / {
proxy_pass http://backend;
}
}
场景 | 作用 |
---|---|
操作系统磁盘缓存 | 减少磁盘机械操作 |
数据库缓存 | 减少文件系统的IO操作 |
应用程序缓存 | 减少对数据库的查询 |
web服务器缓存(nginx) | 减少对应用服务器请求次数 |
浏览器缓存 | 减少与后台的交互次数 |
优点:
1.减少数据传输,节省网络流量,加快响应速度,提升用户体验;
2.减轻服务器压力;
3.提供服务端的高可用性;
缓存的缺点
1.数据的不一致
2.增加成本
Nginx是基于Proxy Store来实现的,其原理是把URL及相关组合当做Key,在使用MD5算法对Key进行哈希,得到硬盘上对应的哈希目录路径,从而将缓存内容保存在该目录
中。它可以支持任意URL连接,同时也支持404/301/302这样的非200状态码。Nginx即可以支持对指定URL或者状态码设置过期时间,也可以使用purge命令来手动清除指定URL的缓存。
Nginx的web缓存服务主要是使用ngx_http_proxy_module模块相关指令集来完成
该指定用于设置缓存文件的存放路径。proxy_cache_path path [levels=number] keys_zone=zone_name:zone_size [inactive=time][max_size=size];
path:缓存路径地址,如:/usr/local/proxy_cache
levels:缓存空间对应的目录,最多设置3层,每层取值为1|2
levels=1:2 缓存空间有两层目录,第一次是1个字母,第二次是2个 字母
举例说明:
itheima[key]通过MD5加密以后的值为 43c8233266edce38c2c9af0694e2107d
levels=1:2 最终的存储路径为/usr/local/proxy_cache/d/07
levels=2:1:2 最终的存储路径 为/usr/local/proxy_cache/7d/0/21
levels=2:2:2 最终的存储路径 为/usr/local/proxy_cache/7d/10/e2
注解:md5码队尾截取长度为2或长度为1。如:7d 10 e2
keys_zone:用来为这个缓存区设置名称和指定大小
keys_zone=itcast:200m 缓存区的名称是itcast,大小为200M,1M 大概能存储8000个keys
inactive:指定缓存的数据多次时间未被访问就将被删除。
max_size:设置最大缓存空间,如果缓存空间存满,默认会覆盖缓存时间最长的资源
http{
proxy_cache_path /usr/local/proxy_cache keys_zone=itcast:200m levels=2:2:2 inactive=1d max_size=20g;
}
该指令用来开启或关闭代理缓存,如果是开启则自定使用哪个缓存区来进行缓存。
proxy_cache zone_name|off;
该指令用来设置web缓存的key值,Nginx会根据key值MD5哈希存缓存
默认值:proxy_cache_key $scheme$proxy_host$request_uri;
该指令用来对不同返回状态码的URL设置不同的缓存时间
#为200和302的响应URL设置10分钟缓存
proxy_cache_valid 200 302 10m;
#为404的响应URL设置1分钟缓存
proxy_cache_valid 404 1m;
#对所有响应状态码的URL都设置1分钟缓存
proxy_cache_valid any 1m;
该指令用来设置资源被访问多少次后被缓存。默认值1
该指令用户设置缓存哪些HTTP方法。默认值GET HEAD
#完成反向代理配置
http{
upstream backend{
server 192.168.200.146:8080;
}
server {
listen 8080;
server_name localhost;
location / {
proxy_pass http://backend/js/;
}
}
}
#缓存配置
http{
proxy_cache_path /usr/local/proxy_cache levels=2:1 keys_zone=itcast:200m inactive=1d max_size=20g;
upstream backend{
server 192.168.200.146:8080;
}
server {
listen 8080;
server_name localhost;
location / {
proxy_cache itcast;
proxy_cache_key itheima;
proxy_cache_min_uses 5;
proxy_cache_valid 200 5d;
proxy_cache_valid 404 30s;
proxy_cache_valid any 1m;
add_header nginx-cache "$upstream_cache_status";
proxy_pass http://backend/js/;
}
}
}
rm -rf /usr/local/proxy_cache/…
ngx_cache_purge-2.3.tar.gz
tar -zxf ngx_cache_purge-2.3.tar.gz
mv ngx_cache_purge-2.3 purge
# 进入Nginx安装目录
./configure --add-module=/root/nginx/module/purge
make
mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginxold
cp objs/nginx /usr/local/nginx/sbin
make upgrade
## 联网安装
yum -y install zlib-devel pcre-devel openssl-devel # 安装依赖
tar –xvf ngx_cache_purge-1.4.tar.gz
tar –xvf nginx-1.0.11.tar.gz
cd nginx-1.0.11/
./configure – prefix=/usr/local/nginx – add-module=../ngx_cache_purge-1.4 – withhttp_stub_status_module – with-http_ssl_module – with-http_flv_module – withhttp_gzip_static_module
Make && make install
# 在nginx配置文件中进行如下配置
server{
location ~/purge(/.*) {
proxy_cache_purge itcast itheima;
}
}
对于一些经常发生变化的数据,对于这些资源我们在缓存的过程中就需要进行过滤,不进行缓存。
该指令是用来定义不将数据进行缓存的条件:proxy_no_cache string … ;
proxy_no_cache $cookie_nocache $arg_nocache $arg_comment;
该指令是用来设置不从缓存中获取数据的条件:proxy_cache_bypass string …;
proxy_cache_bypass $cookie_nocache $arg_nocache $arg_comment;
$cookie_nocache 指的是当前请求的cookie中键的名称为nocache对应的值
$ arg_nocache和$arg_comment 指的是当前请求的参数中属性名为nocache和comment对应的属性值
server{
listen 8080;
server_name localhost;
location / {
if ($request_uri ~ /.*\.js$){
#设置变量
set $nocache 1;
}
#至少有一个不为空且不等于"0",则条件满足成立
proxy_no_cache $nocache $cookie_nocache $arg_nocache $arg_comment;
proxy_cache_bypass $nocache $cookie_nocache $arg_nocache $arg_comment;
}
}
(1)在Centos上准备一个Tomcat
1.Tomcat官网地址:https://tomcat.apache.org/
2.下载tomcat,本次课程使用的是apache-tomcat-8.5.59.tar.gz
3.将tomcat进行解压缩
mkdir web_tomcat
tar -zxf apache-tomcat-8.5.59.tar.gz -C /web_tomcat
4.启动tomcat
./bin/startup.sh
http://192.168.200.146:8080/demo/getAddress
upstream webservice {
server 192.168.200.146:8080;
}
server{
listen 80;
server_name localhost;
location /demo {
proxy_pass http://webservice;
}
}
静态资源交给Nginx来部署,非静态内容则交给Tomcat的服务器。
优点:
upstream webservice {
server 192.168.200.146:8080;
}
server{
listen 80;
server_name localhost;
#动态资源
location /demo {
proxy_pass http://webservice;
}
#静态资源
location ~/.*\.(png|jpg|gif|js){
root html/web;
gzip on;
}
location ~ .*\.(html|htm|gif|jpg|jpeg|bmp|png|ico|txt|js|css){
root /soft/nginx/static_resources;
expires 7d;
}
location / {
root html/web;
index index.html index.htm;
}
}
#访问http://192.168.200.133/index.html
upstream webservice {
server 192.168.200.146:8080;
server 192.168.200.146:8180;
}
两台以上Nginx服务器对外提供服务。
使用Keepalived来解决,Keepalived 软件由 C 编写的,最初是专为 LVS负载均衡软件设计的,Keepalived 软件主要是通过 VRRP 协议实现高可用功能。
VRRP 协议将两台或多台路由器设备虚拟成一个设备,对外提供虚拟路由器IP,而在路由器组内部,如果实际拥有这个对外IP的路由器如果工作正常的话就是ASTER,MASTER实现针对虚拟路由器IP的各种网络功能。其他设备不拥有该虚拟IP,状态为BACKUP,处了接收MASTER的VRRP状态通告信息以外,不执行对外的网络功能。当主机失效时,BACKUP将接管原先MASTER的网络功能。
1.选择协议
VRRP可以把一个虚拟路由器的责任动态分配到局域网上的 VRRP 路由器 中的一台。其中的虚拟路由即Virtual路由是由VRRP路由群组创建的一个 不真实存在的路由,这个虚拟路由也是有对应的IP地址。而且VRRP路由1 和VRRP路由2之间会有竞争选择,通过选择会产生一个Master路由和一个 Backup路由。
2.路由容错协议
Master路由和Backup路由之间会有一个心跳检测,Master会定时告知 Backup自己的状态,如果在指定的时间内,Backup没有接收到这个通知 内容,Backup就会替代Master成为新的Master。Master路由有一个特 权就是虚拟路由和后端服务器都是通过Master进行数据传递交互的,而备 份节点则会直接丢弃这些请求和数据,不做处理,只是去监听Master的状 态
VIP | IP | 主机名 | 主/从 |
---|---|---|---|
192.168.1.133 | keepalived1 | 主 | |
192.168.1.222 | |||
192.168.1.122 | keepalived2 | 从 |
步骤1:从官方网站下载keepalived,官网地址 https://keepalived.org/
步骤2:将下载的资源上传到服务器 keepalived-2.0.20.tar.gz
步骤3:创建keepalived目录,方便管理资源
mkdir keepalived
步骤4:将压缩文件进行解压缩,解压缩到指定的目录
tar -zxf keepalived-2.0.20.tar.gz -C keepalived/
步骤5:对keepalived进行配置,编译和安装
cd keepalived/keepalived-2.0.20
./configure --sysconf=/etc --prefix=/usr/local
make && make install
## 例如:
wget http://www.keepalived.org/software/keepalived-1.1.19.tar.gz
tar zxvf keepalived-1.1.19.tar.gz
cd keepalived-1.1.19
./configure –prefix=/usr/local/keepalived
make
make install
cp /usr/local/keepalived/sbin/keepalived /usr/sbin/
cp /usr/local/keepalived/etc/sysconfig/keepalived /etc/sysconfig/
cp /usr/local/keepalived/etc/rc.d/init.d/keepalived /etc/init.d/
mkdir /etc/keepalived
/etc/keepalived/keepalived.conf (keepalived的系统配置文件,我们主要操作的就是该文件),
/usr/local/sbin目录下的keepalived ,是系统配置脚本,用来启动和关闭keepalived
这里面会分三部,第一部分是global全局配置、第二部分是vrrp相关配置、第三部分是LVS相关配置。
#global全局部分:
global_defs {
#通知邮件,当keepalived发送切换时需要发email给具体的邮箱 地址
notification_email {
leo_pic@163.com
leorainbow@163.com
}
#设置发件人的邮箱信息
notification_email_from zhaomin@itcast.cn
#指定smpt服务地址
smtp_server 192.168.200.1
#指定smpt服务连接超时时间
smtp_connect_timeout 30
#运行keepalived服务器的一个标识,可以用作发送邮件的主题信息
router_id LVS_DEVEL
#默认是不跳过检查。检查收到的VRRP通告中的所有地址可能会比较 耗时,设置此命令的意思是,如果通告与接收的上一个通告来自相同的 master路由器,则不执行检查(跳过检查)
vrrp_skip_check_adv_addr
#严格遵守VRRP协议。
vrrp_strict
#在一个接口发送的两个免费ARP之间的延迟。可以精确到毫秒级。 默认是0
vrrp_garp_interval 0
#在一个网卡上每组na消息之间的延迟时间,默认为0
vrrp_gna_interval 0
}
VRRP部分,该部分可以包含以下四个子模块 1. vrrp_script 2. vrrp_sync_group
3. garp_group 4. vrrp_instance。会用到1,4
#设置keepalived实例的相关信息,VI_1为VRRP实例名称
vrrp_instance VI_1 {
state MASTER #有两个值可选MASTER主 BACKUP备
interface eth0 #vrrp实例绑定的接口,用于发送VRRP 包[当前服务器使用的网卡名称]
virtual_router_id 51#指定VRRP实例ID,范围是0-255
priority 100 #指定优先级,优先级高的将成为 MASTER
advert_int 1 #指定发送VRRP通告的间隔,单位是秒
authentication { #vrrp之间通信的认证信息
auth_type PASS #指定认证方式。PASS简单密码认证(推 荐)
auth_pass 1111 #指定认证使用的密码,最多8位
}
virtual_ipaddress { #虚拟IP地址设置虚拟IP地址,供用户 访问使用,可设置多个,一行一个
192.168.10.104/24
}
}
virtual_server 192.168.10.104 80 {
delay_loop 6
lb_algo rr
lb_kind NAT
nat_mask 255.255.255.0
persistence_timeout 50
protocol TCP
real_server 192.168.10.251 80 {
weight 3
TCP_CHECK {
connect_timeout 10
nb_get_retry 3
delay_before_retry 3
connect_port 80
}
}
real_server 192.168.200.148 80 {
weight 3
TCP_CHECK {
connect_timeout 10
nb_get_retry 3
delay_before_retry 3
connect_port 80
}
}
}
配置备用调度器的 keepalived,只需要将 state MASTER 改为 state BACKUP,降低 priority 100 的值:
state MASTER —> state BACKUP
priority 100 —> priority 99 (此值必须低于主的)
主备启动
/etc/init.d/keepalived start
服务器1配置
global_defs {
notification_email {
tom@itcast.cn
jerry@itcast.cn
}
notification_email_from zhaomin@itcast.cn
smtp_server 192.168.200.1
smtp_connect_timeout 30
router_id keepalived1
vrrp_skip_check_adv_addr
vrrp_strict
vrrp_garp_interval 0
vrrp_gna_interval 0
}
vrrp_instance VI_1 {
state MASTER
interface ens33
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.200.222
}
}
服务器2配置
! Configuration File for keepalived
global_defs {
notification_email {
tom@itcast.cn
jerry@itcast.cn
}
notification_email_from zhaomin@itcast.cn
smtp_server 192.168.200.1
smtp_connect_timeout 30
router_id keepalived2
vrrp_skip_check_adv_addr
vrrp_strict
vrrp_garp_interval 0
vrrp_gna_interval 0
}
vrrp_instance VI_1 {
state BACKUP
interface ens33
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.200.222
}
}
cd /usr/local/sbin
./keepalived
通过上述的测试,我们会发现,虚拟IP(VIP)会在MASTER节点上,当MASTER节点上的keepalived出问题以后,因为BACKUP无法收到MASTER发出的VRRP状态通过信息,就会直接升为MASTER。VIP也 会"漂移"到新的MASTER
keepalived只能做到对网络故障和keepalived本身的监控,即当出现网络故障或者keepalived本身出现问题时,进行切换。但是这些还不够,我们还需要监控keepalived所在服务器上的其他业务,比如Nginx,如果Nginx出现异常了,仅仅keepalived保持正常,是无法完成系统的正常工作的,因此需要根据业务进程的运行状态决定是否需要进行主备切换,这个时候,我们可以通过编写脚本对业务进程进行检测监控
。
vrrp_script 脚本名称 {
script "脚本位置"
interval 3 #执行时间间隔
weight -20 #动态调整vrrp_instance的优先级
}
#!/bin/bash
num=`ps -C nginx --no-header | wc -l`
if [ $num -eq 0 ];then
/usr/local/nginx/sbin/nginx
sleep 2
if [ `ps -C nginx --no-header | wc -l` -eq 0 ]; then
killall keepalived
fi
fi
# -C(command):指定命令的所有进程。 --no-header:排除标题
vrrp_script ck_nginx {
script "/etc/keepalived/ck_nginx.sh" #执行脚本的位置
interval 2 #执行脚本的周期,秒为单位
weight -20 #权重的计算方式
}
vrrp_instance VI_1 {
state MASTER
interface ens33
virtual_router_id 10
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.200.111
}
track_script {
ck_nginx
}
}
通常如果master服务死掉后backup会变成master,但是当master服务又好了的时候 master此时会抢占VIP,这样就会发生两次切换对业务繁忙的网站来说是不好的。所以我们要在配置文件加入 nopreempt 非抢占,但是这个参数只能用于state 为backup,故我们在用HA的时候最好master 和backup的state都设置成backup 让其通过priority来竞争.
location /download{
root /usr/local;
#启用或禁用目录列表输出 默认off
autoindex on;
#对应HTLM格式,指定是否在目录列表展示文件的详细大小,最好off。on是按bytes
autoindex_exact_size on;
#设置目录列表的格式html|xml|json|jsonp
autoindex_format html;
#对应HTML格式,是否在目录列表上显示时间,默认off
autoindex_localtime on;
}
认证需要做的就是根据用户输入的用户名和密码来判定用户是否为合法用户,如果是则放行访问,如果不是则拒绝访问。
Nginx对应用户认证这块是通过【ngx_http_auth_basic_module】模块来实现的
auth_basic:使用“ HTTP基本认证”协议启用用户名和密码的验证。开启后,服务端会返回401,指定的字符串会返回到客户端,给用户以提示信息。
auth_basic_user_file:指定用户名和密码所在文件,该文件中的用户名和密码的设置,密码需要进行加密。
location /download{
root /usr/local;
autoindex on;
autoindex_exact_size on;
autoindex_format html;
autoindex_localtime on;
auth_basic 'please input your auth';
auth_basic_user_file htpasswd;
}
我们需要使用htpasswd工具生成
yum install -y httpd-tools
htpasswd -c /usr/local/nginx/conf/htpasswd username // 创建一个新文件记录用户名和密码
htpasswd -b /usr/local/nginx/conf/htpasswd username password //在指定文件新增一个用户名和密码
htpasswd -D /usr/local/nginx/conf/htpasswd username // 从指定文件删除一个用户信息
htpasswd -v /usr/local/nginx/conf/htpasswd username // 验证用户名和密码是否正确
上述方式虽然能实现用户名和密码的验证,但是大家也看到了,所有的用户名和密码信息都记录在文件里面,如果用户量过大的话,这种方式就显得有点麻烦了,这时候我们就得**通过后台业务代码来进行用户权限的校验
**了。
Lua是一种轻量、小巧的脚本语言,用标准C语言编写并以源代码形式开发。设计的目的是为了嵌入到其他应用程序中,从而为应用程序提供灵活的扩展和定制功能。
Lua有其自身的特点:
(1)轻量级:用标准C语言编写并以源代码形式开发,编译后仅仅一百余千字节,可 以很方便的嵌入到其他程序中。
(2)可扩展:提供非常丰富易于使用的扩展接口和机制,由宿主语言(通常是C或 C++)提供功能,Lua可以使用它们,就像内置的功能一样。
(3)支持面向过程编程和函数式编程。
游戏开发、独立应用脚本、web应用脚本、扩展和数据库插件、系统安全等应用场景。
服务器
#Lua的官网地址为: https://www.lua.org
wget https://www.lua.org/ftp/lua-5.4.1.tar.gz
cd lua-5.4.1
# 如果test失败: yum install -y readline-devel
make linux test
make install
lua -v
Lua有两种交互方式,分别是:交互式和脚本式。
交互式:lua -i ; print(“hello world”);
脚本式:是将代码保存到一个以lua为扩展名的文件中并执行的方式。
#方式一 类似java源文件形式
#hello.lua文件内容
print("Hello World")
-----
#命令执行文件
lua hello.lua
#方式二 类似脚本文件形式
#hello.lua文件内容。
#第一句指定lua解释器所在位置。一般情况下#!就是用来指定用哪个程序来运行本文件。
#!/usr/local/bin/lua
print("Hello World!!!")
-----
#命令执行文件
chmod 755 hello.lua
./hello.lua
补充一点,如果想在交互式中运行脚本式的hello.lua中的内容,我们可以使用一个dofile函数,如:dofile(“lua_demo/hello.lua”)
单行注释:–注释内容。
多行注释:- -[[ 注释内容 --]] 。取消多行前面再加-就可以。- - -
这块建议大家最好不要使用下划线加大写字母的标识符,因为Lua的保留字也是这样定义的,容易发生冲突。注意Lua是区分大小写字母的。
需要注意的:local、repeat、until、nil。其他类似if、for等
Lua中支持的运算符有算术运算符、关系运算符、逻辑运算符、其他运算符。
算术运算符:+、-、*、/、%、^乘幂
关系运算符:==、~=、>、<、>=、<=
逻辑运算符:and &&、 or || 、 not !
其他运算符:. .连接两个字符串 ;# 一元预算法,返回字符串或表的长度(#“rain” -->4)。
在Lua语言中,全局变量无须声明即可使用。在默认情况下,变量总是认为是全局的,如果未提前赋值,默认为nil。要想声明一个局部变量,需要使用local来声明。
nil是一种只有一个nil值的类型,它的作用可以用来与其他所有值进行区分,也可以当想要移除一个变量时,只需要将该变量名赋值为nil,垃圾回收就会会释放该变量所占用的内存。
在Lua语言中,只会将false和nil视为假,其他的都视为真,特别是在条件检测中0和空字符串都会认为是真,这个和我们熟悉的大多数语言不太一样。
在Lua5.3版本开始,Lua语言为数值格式提供了两种选择:integer(整型) 和float(双精度浮点型)。
不管是整型还是双精度浮点型,使用type()函数来取其类型,都会返回的是number,所以它们之间是可以相互转换的,同时,具有相同算术值的整型值和浮点型值在Lua语言中是相等的。
Lua语言中的字符串即可以表示单个字符,也可以表示一整本书籍。在Lua语言中,操作100K或者1M个字母组成的字符串的程序很常见。
可以使用单引号或双引号来声明字符串。如果声明的字符串比较长或者有多行,则可以使用如下方式进行声明:
#短字符串
a = "hello"
b = 'world'
a .. b -->hello world
#长字符串
html = [[
Lua-string</title> </head>
"http://www.lua.org">Lua</a> </body>
</html>
]]
在 Lua语言中,函数( Function )是对语句和表达式进行抽象的主要方式。
#定义函数的语法为:
function functionName(params)
....
end
#例子
function f(a,b)
print(a,b)
end
f() --> nil nil
f(2) --> 2 nil
f(2,6) --> 2 6
f(2.6.8) --> 2 6 (8被丢弃)
#可变长参数函数
function add(...)
a,b,c=...
print(a)
print(b)
print(c)
end
add(1,2,3) --> 1 2 3
#函数返回值可以有多个
function f(a,b)
return a,b
end
x,y=f(11,22) --> x=11,y=22
table是Lua语言中最主要和强大的数据结构。使用表, Lua 语言可以以一种简单、统一且高效的方式表示数组、集合、记录和其他很多数据结构。 Lua语言中的表本质上是一种辅助数组。这种数组比Java中的数组更加灵活,可以使用数值做索引,也可以使用字符串或其他任意类型的值作索引(除nil外)。
#arr[0]值nil;arr[1]值TOM;数组默认从1开始
arr = {"TOM","JERRY","ROSE"}
#下面与上面效果一样
arr ={}; arr[1]="TOM"
#用字符串表示索引
arr = {}; arr["X"]=10 ; arr["Y"]=20
#取值
print(arr["X"]); print(arr.Y)
#混合
arr = {"TOM",X=10,"JERRY",Y=20,"ROSE",Z=30}#弱类型
TOM:arr[1] ; 10:arr["X"] ; JERRY:arr[2] ; 20:arr.Y
在Lua中,thread用来表示执行的独立线路,用来执行协同程序。
userdata是一种用户自定义数据,用于表示一种由应用程序或C/C++语言库所创建的类型。
用于循环的 while、 repeat 和 for。 所有的控制结构语法上都有一个显式的终结符: end 用于终结 if、 for 及 while 结构, until 用于终结repeat 结构。
function show(age)
if age<=18 then
return "青少年"
elseif age>18 and age<=45 then
return "青年"
elseif age>45 and age<=60 then
return "中年人"
elseif age>60 then
return "老年人"
end
end
function testWhile()
local i = 1
while i<=10 do
print(i)
i=i+1
end
end
repeat-until语句会重复执行其循环体直到条件为真时结束(while循环相反
)。 由于条件测试在循环体之后执行,所以循环体至少会执行一次。
function testRepeat()
local i = 10
repeat
print(i) i=i-1
until i < 1
end
#10是步长,for(int i=1;i+10;i<100)
for i = 1,100,10 do
print(i)
end
#类似foreach
arr = {"TOME","JERRY","ROWS","LUCY"}
for i,v in ipairs(arr) do
print(i,v)
end
#ipairs 与pairs 区别,前面是整数索引,不会显示x坐标值;后面pairs会显示
arr = {"TOME","JERRY","ROWS",x="JACK","LUCY"}
for i,v in pairs(arr) do
print(i,v) #1 TOM 2 JERRY 3 ROWS 4 LUCY x JACK
end
淘宝开发的ngx_lua模块通过将lua解释器集成进Nginx,可以采用lua脚本实现业务逻辑,由于lua的紧凑、快速以及内建协程,所以在保证高并发服务能力的同时极大地降低了业务逻辑实现成本。
(1)LuaJIT是采用C语言编写的Lua代表的解释器.
官网上对应的下载地址:http://luajit.org/download/LuaJIT-2.0.5.tar.gz
wget http://luajit.org/download/LuaJIT-2.0.5.tar.gz
tar -zxf LuaJIT-2.0.5.tar.gz
cd LuaJIT-2.0.5
make && make install
(2)下载lua-nginx-module
wget https://github.com/openresty/lua-nginx-module/archive/v0.10.16rc4.tar.gz
tar -zxf lua-nginx-module-0.10.16rc4.tar.gz
mv lua-nginx-module-0.10.16rc4 lua-nginx-module
#导入环境变量,告诉Nginx去哪里找luajit
export LUAJIT_LIB=/usr/local/lib
export LUAJIT_INC=/usr/local/include/luajit-2.0
#进入Nginx的目录执行如下命令:
./configure --prefix=/usr/local/nginx --add- module=../lua-nginx-module
make && make install
#如果启动提示libluajit-5.1.so.2错误。设置软链接。
ln -s /usr/local/lib/libluajit-5.1.so.2 /lib64/libluajit-5.1.so.2
#如果提示resty.core没有找到。一种安装,另一种禁用restry模块。
http{
lua_load_resty_core off;
}
#安装成功测试
location /lua{
default_type 'text/html';
content_by_lua 'ngx.say("HELLO,LUA
")';
}
OpenResty是由淘宝工程师开发的,其官方网站(http://openresty.org/)。OpenResty内部就已经集成了Nginx和Lua,所以我们使用起来会更加方便。
#安装
wget https://openresty.org/download/openresty- 1.15.8.2.tar.gz
tar -zxf openresty-1.15.8.2.tar.gz
cd openresty-1.15.8.2
./configure
make && make install
cd /usr/local/openresty/nginx/
vim nginx.conf
location /lua{ default_type 'text/html'; content_by_lua 'ngx.say(" HELLO,OpenRestry
")'; }
在sbin目录下启动nginx
xxx_by_lua ,指令后面跟的是 lua指令;xxx_by_lua_file 指令后面跟的是 lua文件。
该指令在每次Nginx重新加载配置时执行,可以用来完成一些耗时模块的 加载,或者初始化一些全局配置。
该指令用于启动一些定时任务,如心跳检查、定时拉取服务器配置等。
该指令只要用来做变量赋值,这个指令一次只能返回一个值,并将结果赋 值给Nginx中指定的变量。
该指令用于执行内部URL重写或者外部重定向,典型的如伪静态化URL重 写,本阶段在rewrite处理阶段的最后默认执行。
该指令用于访问控制。例如,如果只允许内网IP访问。
该指令是应用最多的指令,大部分任务是在这个阶段完成的,其他的过程 往往为这个阶段准备数据,正式处理基本都在本阶段
该指令用于设置应答消息的头部信息。
该指令是对响应数据进行过滤,如截断、替换。
该指令用于在log请求处理阶段,用Lua代码处理日志,但并不替换原有 log处理。
该指令主要的作用是用来实现上游服务器的负载均衡器算法
该指令作用在Nginx和下游服务开始一个SSL握手操作时将允许本配置项 的Lua代码。
http://192.168.200.133?name=张三&gender=1
Nginx接收到请求后,根据gender传入的值,如果gender传入的是1, 则在页面上展示
张三先生,如果gender传入的是0,则在页面上展示张三女士,如果未传或 者传入的不是1和2则在页面上展示张三。
## 实现代码
location /getByGender {
default_type 'text/html';
set_by_lua $name "
local uri_args = ngx.req.get_uri_args()
gender = uri_args['gender']
name = uri_args['name']
if gender=='1' then
return name..'先生'
elseif gender=='0' then
return name..'女士'
else
return name
end
";
header_filter_by_lua "
ngx.header.aaa='bbb'
";
return 200 $name;
}
Nginx支 持3种方法访问Redis,分别是HttpRedis模块、HttpRedis2Module、lua-resty-redis库。
准备一个redis环境,然后准备对应的API;
lua-resty-redis提供了访问Redis的详细API,包括创建对接、连 接、操作、数据处理等。这些API基本上与Redis的操作一一对应。
(1)redis = require “resty.redis”
(2)new 语法: redis,err = redis:new(),创建一个Redis对象。
(3)connect 语 法:ok,err=redis:connect(host,port[,options_table]),设 置连接Redis的连接信息。 ok:连接成功返回 1,连接失败返回nil err:返回对应的错误信息
(4)set_timeout 语法: redis:set_timeout(time) ,设置请求操作Redis的超 时时间。
(5)close 语法: ok,err = redis:close(),关闭当前连接,成功返回1, 失败返回nil和错误信息
(6)redis命令对应的方法 在lua-resty-redis中,所有的Redis命令都有自己的方法,方 法名字和命令名字相同,只是全部为小写。
效果实现
location / {
default_type "text/html";
content_by_lua_block{
local redis = require "resty.redis" -- 引入 Redis
local redisObj = redis:new() --创建Redis对象
redisObj:set_timeout(1000) --设置超时数据为1s
local ok,err = redisObj:connect("192.168.200.1",6379) --设置redis连接 信息
if not ok then --判断是否连接成功
ngx.say("failed to connection redis",err)
return
end
ok,err = redisObj:set("username","TOM")--存入 数据
if not ok then --判断是否存入成功
ngx.say("failed to set username",err)
return
end
local res,err = redisObj:get("username") --从 redis中获取数据
ngx.say(res) --将数据写会消息体中
redisObj:close()
}
}
MySQL是一个使用广泛的关系型数据库。在ngx_lua中,MySQL有两种访问模式,分别是使
(1)用ngx_lua模块和lua-resty-mysql模块:这两个模块是安装OpenResty时默认安装的。
(2)使用drizzle_nginx_module(HttpDrizzleModule)模块:需要单独安装,这个库现不在OpenResty中。
lua-resty-mysql是OpenResty开发的模块,使用灵活、功能强大,适合复杂的业务场景,同时支持存储过程的访问。
准备一个mysql环境,然后准备对应的API;
(1)引入"resty.mysql"模块 local mysql = require “resty.mysql”
(2)new 创建一个MySQL连接对象,遇到错误时,db为nil,err为错误描 述信息语法: db,err = mysql:new()
(3)connect 尝试连接到一个MySQL服务器语法:ok,err=db:connect(options),options是一个参数的 Lua表结构,里面包含数据库连接的相关信息 host:服务器主机名或IP地址 port:服务器监听端口,默认为3306 user:登录的用户名 password:登录密码 database:使用的数据库名
(4)set_timeout 设置子请求的超时时间(ms),包括connect方法 语法:db:set_timeout(time)
(5)close 关闭当前MySQL连接并返回状态。如果成功,则返回1;如果出现任 何错误,则将返回nil和错误描述。 语法:db:close()
(6)send_query 异步向远程MySQL发送一个查询。如果成功则返回成功发送的字节 数;如果错误,则返回nil和错误描述 语法:bytes,err=db:send_query(sql)
(7)read_result 从MySQL服务器返回结果中读取一行数据。res返回一个描述OK包 或结果集包的Lua表,语法:
res, err, errcode, sqlstate = db:read_result()
res, err, errcode, sqlstate = db:read_result(rows) :rows指定返回结果集的最大值,默认为4 如果是查询,则返回一个容纳多行的数组。每行是一个数据列的 key-value对,如
{ {id=1,username=“TOM”,birthday=“1988-11- 11”,salary=10000.0}, {id=2,username=“JERRY”,birthday=“1989-11- 11”,salary=20000.0} }
如果是增删改,则返回类上如下数据
{ insert_id = 0, server_status=2, warning_count=1, affected_rows=2, message=nil }
返回值:
res:操作的结果集
err:错误信息
errcode:MySQL的错误码,比如1064
sqlstate:返回由5个字符组成的标准SQL错误码,比如 42000
create database nginx_db;
use nginx_db;
create table users(
id int primary key auto_increment,
username varchar(30),
birthday date,
salary double
);
insert into users(id,username,birthday,salary) values(null,"TOM","1988-11-11",10000.0);
insert into users(id,username,birthday,salary) values(null,"JERRY","1989-11-11",20000.0);
insert into users(id,username,birthday,salary) values(null,"ROWS","1990-11-11",30000.0);
insert into users(id,username,birthday,salary) values(null,"LUCY","1991-11-11",40000.0);
insert into users(id,username,birthday,salary) values(null,"JACK","1992-11-11",50000.0);
实现代码
location /{
content_by_lua_block{
local mysql = require "resty.mysql"
local db = mysql:new()
local ok,err = db:connect{
host="192.168.200.111",
port=3306,
user="root",
password="123",
database="nginx_db"
}
db:set_timeout(1000)
db:send_query("select * from users where id =1")
local res,err,errcode,sqlstate = db:read_result()
ngx.say(res[1].id..","..res[1].username..","..res[1]. birthday..","..res[1].salary)
db:close()
}
}
read_result()得到的结果res都是table类型,要想在页面上展示,就必须知道table的具体数据结构才能进行遍历获取。处理起来比较麻烦,接下来我们介绍一种简单方式cjson,使用它就可以将table类型的数据转换成json字符串,把json字符串展示在页面上即可。
步骤一:引入cjson
步骤二:调用cjson的encode方法进行类型转换
步骤三:使用
location /{
content_by_lua_block{
local mysql = require "resty.mysql"
local cjson = require "cjson"
local db = mysql:new()
local ok,err = db:connect{
host="192.168.200.111", port=3306, user="root", password="123456", database="nginx_db"
}
db:set_timeout(1000)
--db:send_query("select * from users where id = 2")
db:send_query("select * from users")
local res,err,errcode,sqlstate = db:read_result()
ngx.say(cjson.encode(res))
for i,v in ipairs(res) do
ngx.say(v.id..","..v.username..","..v.birthday..",".. v.salary)
end
db:close()
}
}
优化send_query和read_result。
本方法是send_query和read_result组合的快捷方法。
res, err, errcode, sqlstate = db:query(sql[,rows])
location /{
content_by_lua_block{
local mysql = require "resty.mysql"
local db = mysql:new()
local ok,err = db:connect{
host="192.168.200.1",
port=3306,
user="root",
password="123456",
database="nginx_db",
max_packet_size=1024,
compact_arrays=false
}
db:set_timeout(1000)
local res,err,errcode,sqlstate = db:query("select * from users")
--local res,err,errcode,sqlstate = db:query("insert into users(id,username,birthday,salary) values(null,'zhangsan','2020-11-11',32222.0)")
--local res,err,errcode,sqlstate = db:query("update users set username='lisi' where id = 6")
--local res,err,errcode,sqlstate = db:query("delete from users where id = 6") db:close()
}
}
使用ngx_lua模块完成Redis缓存预热。
分析:
(1)先得有一张表(users)
(2)浏览器输入如下地址
http://191.168.200.133?username=TOM
(3)从表中查询出符合条件的记录,此时获取的结果为table类型
(4)使用cjson将table数据转换成json字符串
(5)将查询的结果数据存入Redis中
init_by_lua_block{
redis = require "resty.redis"
mysql = require "resty.mysql"
cjson = require "cjson"
}
location /{
default_type "text/html";
content_by_lua_block{
--获取请求的参数username
local param = ngx.req.get_uri_args() ["username"]
--建立mysql数据库的连接
local db = mysql:new()
local ok,err = db:connect{
host="192.168.200.111", port=3306, user="root", password="123456", database="nginx_db"
}
if not ok then
ngx.say("failed connect to mysql:",err)
return
end
--设置连接超时时间
db:set_timeout(1000)
--查询数据
local sql = "";
if not param then
sql="select * from users"
else
sql="select * from users where username=".."'"..param.."'"
end
local res,err,errcode,sqlstate=db:query(sql)
if not res then
ngx.say("failed to query from mysql:",err)
return
end
--连接redis
local rd = redis:new()
ok,err = rd:connect("192.168.200.111",6379)
if not ok then
ngx.say("failed to connect to redis:",err)
return
end
rd:set_timeout(1000)
--循环遍历数据
for i,v in ipairs(res) do
rd:set("user_"..v.username,cjson.encode(v))
end
ngx.say("success")
rd:close()
db:close()
}
}
参数 | 说明 |
---|---|
–prefix= | 指向安装目录 |
–sbin-path | 指向(执行)程序文件(nginx) |
–conf-path= | 指向配置文件(nginx.conf) |
–error-log-path= | 指向错误日志目录 |
–pid-path= | 指向 pid 文件(nginx.pid) |
–lock-path= | 指向 lock 文件(nginx.lock)(安装文件锁定,防止安装文件被别人利用,或自己误操作。) |
–user= | 指定程序运行时的非特权用户 |
–group= | 指定程序运行时的非特权用户组 |
–builddir= | 指向编译目录 |
–with-rtsig_module | 启用 rtsig 模块支持(实时信号) |
–with-select_module | 启用 select 模块支持(一种轮询模式,不推荐在高载环境下使用)禁用:–withoutselect_module |
–with-poll_module | 启用 poll 模块支持(功能与 select 相同,与 select 特性相同,为一种轮询模式,不推荐在高载环境下使用) |
–with-file-aio | 启用 file aio 支持(一种 APL 文件传输格式) |
–with-ipv6 | 启用 ipv6 支持 |
–with-http_ssl_module | 启用 ngx_http_ssl_module 支持(使支持 https 请求,需已安装 openssl) |
–with-http_realip_module | 启用 ngx_http_realip_module 支持(这个模块允许从请求标头更改客户端的 IP 地址值,默认为关) |
–with-http_addition_module | 启用 ngx_http_addition_module 支持(作为一个输出过滤器,支持不完全缓冲,分部分响应请求) |
–with-http_xslt_module | 启用 ngx_http_xslt_module 支持(过滤转换 XML 请求) |
–with-http_image_filter_module | 启用 ngx_http_image_filter_module 支持(传输 JPEG/GIF/PNG 图片的一个过滤器)(默认为不启用。gd 库要用到) |
–with-http_geoip_module | 启用 ngx_http_geoip_module 支持(该模块创建基于与 MaxMind GeoIP 二进制文件相配的客户端 IP 地址的 ngx_http_geoip_module 变量) |
–with-http_sub_module | 启用 ngx_http_sub_module 支持(允许用一些其他文本替换 nginx 响应中的一些文本) |
–with-http_dav_module | 启用 ngx_http_dav_module 支持(增加 PUT,DELETE,MKCOL:创建集合,COPY 和 MOVE 方法)默认情况下为关闭,需编译开启 |
–with-http_flv_module | 启用 ngx_http_flv_module 支持(提供寻求内存使用基于时间的偏移量文件) |
–with-http_gzip_static_module | 启用 ngx_http_gzip_static_module 支持(在线实时压缩输出数据流) |
–with-http_random_index_module | 启用 ngx_http_random_index_module 支持(从目录中随机挑选一个目录索引) |
–with-http_secure_link_module | 启用 ngx_http_secure_link_module 支持(计算和检查要求所需的安全链接网址) |
–with-http_degradation_module | 启用 ngx_http_degradation_module 支持(允许在内存不足的情况下返回204 或 444 码) |
–with-http_stub_status_module | 启用 ngx_http_stub_status_module 支持(获取 nginx 自上次启动以来的工作状态) |
–without-http_charset_module | 禁用 ngx_http_charset_module 支持(重新编码 web 页面,但只能是一个方向–服务器端到客户端,并且只有一个字节的编码可以被重新编码) |
–without-http_gzip_module | 禁用 ngx_http_gzip_module 支持(该模块同-with-http_gzip_static_module 功能一样) |
–without-http_ssi_module | 禁用 ngx_http_ssi_module 支持(该模块提供了一个在输入端处理处理服务器包含文件(SSI)的过滤器,目前支持 SSI 命令的列表是不完整的) |
–without-http_userid_module | 禁用 ngx_http_userid_module 支持(该模块用来处理用来确定客户端后续请求的 cookies) |
–without-http_access_module | 禁用 ngx_http_access_module 支持(该模块提供了一个简单的基于主机的访问控制。允许/拒绝基于 ip 地址) |
–without-http_auth_basic_module | 禁用 ngx_http_auth_basic_module(该模块是可以使用用户名和密码基于http 基本认证方法来保护你的站点或其部分内容) |
–without-http_autoindex_module | 禁用 disable ngx_http_autoindex_module 支持(该模块用于自动生成目录列表,只在 ngx_http_index_module 模块未找到索引文件时发出请求。) |
–without-http_geo_module | 禁用 ngx_http_geo_module 支持(创建一些变量,其值依赖于客户端的 IP 地址) |
–without-http_map_module | 禁用 ngx_http_map_module 支持(使用任意的键/值对设置配置变量) |
–without-http_split_clients_module | 禁用 ngx_http_split_clients_module 支持(该模块用来基于某些条件划分用户。条件如:ip 地址、报头、cookies 等等) |
–without-http_referer_module | 禁用 disable ngx_http_referer_module 支持(该模块用来过滤请求,拒绝报头中 Referer 值不正确的请求) |
–without-http_rewrite_module | 禁用 ngx_http_rewrite_module 支持(该模块允许使用正则表达式改变 URI,并且根据变量来转向以及选择配置。如果在 server 级别设置该选项,那么他们将在 location 之前生效。如果在location 还有更进一步的重写规则,location 部分的规则依然会被执行。如果这个 URI 重写是因为 location 部分的规则造成的,那么 location 部分会再次被执行作为新的 URI。 这个循环会执行 10 次,然后 Nginx 会返回一个 500 错误。) |
–without-http_proxy_module | 禁用 ngx_http_proxy_module 支持(有关代理服务器) |
–without-http_fastcgi_module | 禁用 ngx_http_fastcgi_module 支持(该模块允许 Nginx 与 FastCGI 进程交互,并通过传递参数来控制 FastCGI 进程工作。 )FastCGI 一个常驻型的公共网关接口。 |
–without-http_uwsgi_module | 禁用 ngx_http_uwsgi_module 支持(该模块用来医用 uwsgi 协议,uWSGI 服务器相关) |
–without-http_scgi_module | 禁用 ngx_http_scgi_module 支持(该模块用来启用 SCGI 协议支持,SCGI 协议是CGI 协议的替代。它是一种应用程序与 HTTP 服务接口标准。它有些像 FastCGI 但他的设计 更容易实现。) |
–without-http_memcached_module | 禁用 ngx_http_memcached_module 支持(该模块用来提供简单的缓存,以提高系统效率) |
-without-http_limit_zone_module | 禁用 ngx_http_limit_zone_module 支持(该模块可以针对条件,进行会话的并发连接数控制) |
–without-http_limit_req_module | 禁用 ngx_http_limit_req_module 支持(该模块允许你对于一个地址进行请求数量的限制用一个给定的 session 或一个特定的事件) |
–without-http_empty_gif_module | 禁用 ngx_http_empty_gif_module 支持(该模块在内存中常驻了一个 1*1 的透明 GIF 图像,可以被非常快速的调用) |
–without-http_browser_module | 禁用 ngx_http_browser_module 支持(该模块用来创建依赖于请求报头的值。如果浏览器为 modern ,则$modern_browser 等于 modern_browser_value 指令分配的值;如 果浏览器为 old,则$ancient_browser 等于 ancient_browser_value 指令分配的值;如果浏览器为 MSIE 中的任意版本,则 $msie 等于 1) |
–without-http_upstream_ip_hash_module | 禁用 ngx_http_upstream_ip_hash_module 支持(该模块用于简单的负载均衡) |
–with-http_perl_module | 启用 ngx_http_perl_module 支持(该模块使 nginx 可以直接使用 perl 或通过 ssi 调用 perl) |
–with-perl_modules_path= | 设定 perl 模块路径 |
–with-perl= | 设定 perl 库文件路径 |
–http-log-path= | 设定 access log 路径 |
–http-client-body-temp-path= | 设定 http 客户端请求临时文件路径 |
–http-proxy-temp-path= | 设定 http 代理临时文件路径 |
–http-fastcgi-temp-path= | 设定 http fastcgi 临时文件路径 |
–http-uwsgi-temp-path= | 设定 http uwsgi 临时文件路径 |
–http-scgi-temp-path= | 设定 http scgi 临时文件路径 |
-without-http | 禁用 http server 功能 |
–without-http-cache | 禁用 http cache 功能 |
–with-mail | 启用 POP3/IMAP4/SMTP 代理模块支持 |
–with-mail_ssl_module | 启用 ngx_mail_ssl_module 支持 |
–without-mail_pop3_module | 禁用 pop3 协议(POP3 即邮局协议的第 3 个版本,它是规定个人计算机如何连接到互联网上的邮件服务器进行收发邮件的协议。是因特网电子邮件的第一个离线协议标 准,POP3 协议允许用户从服务器上把邮件存储到本地主机上,同时根据客户端的操作删除或保存在邮件服务器上的邮件。POP3 协议是 TCP/IP 协议族中的一员,主要用于 支持使用客户端远程管理在服务器上的电子邮件) |
–without-mail_imap_module | 禁用 imap 协议(一种邮件获取协议。它的主要作用是邮件客户端可以通过这种协议从邮件服务器上获取邮件的信息,下载邮件等。IMAP 协议运行在 TCP/IP 协议之上, 使用的端口是 143。它与POP3 协议的主要区别是用户可以不用把所有的邮件全部下载,可以通过客户端直接对服务器上的邮件进行操作。) |
–without-mail_smtp_module | 禁用 smtp 协议(SMTP 即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式。SMTP 协议属于 TCP/IP 协议族,它帮助每台计算机在发送或中转信件时找到下一个目的地。) |
–with-google_perftools_module | 启用 ngx_google_perftools_module 支持(调试用,剖析程序性能瓶颈) |
–with-cpp_test_module | 启用 ngx_cpp_test_module 支持 |
–add-module= | 启用外部模块支持 |
–with-cc= | 指向 C 编译器路径 |
–with-cpp= | 指向 C 预处理路径 |
–with-cc-opt= | 设置 C 编译器参数(PCRE 库,需要指定–with-cc-opt=”-I /usr/local/include”,如果使用select()函数则需要同时增加文件描述符数量,可以通过–with-cc- opt=”-D FD_SETSIZE=2048”指定。) |
–with-ld-opt= | 设置连接文件参数。(PCRE 库,需要指定–with-ld-opt=”-L /usr/local/lib”。) |
–with-cpu-opt= | 指定编译的 CPU,可用的值为: pentium, pentiumpro, pentium3, pentium4, athlon, opteron, amd64, sparc32, sparc64, ppc64 |
–without-pcre | 禁用 pcre 库 |
–with-pcre | 启用 pcre 库 |
–with-pcre= | 指向 pcre 库文件目录 |
–with-pcre-opt= | 在编译时为 pcre 库设置附加参数 |
–with-md5= | 指向 md5 库文件目录(消息摘要算法第五版,用以提供消息的完整性保护) |
–with-md5-opt= | 在编译时为 md5 库设置附加参数 |
–with-md5-asm | 使用 md5 汇编源 |
–with-sha1= | 指向 sha1 库目录(数字签名算法,主要用于数字签名) |
–with-sha1-opt= | 在编译时为 sha1 库设置附加参数 |
–with-sha1-asm | 使用 sha1 汇编源 |
–with-zlib= | 指向 zlib 库目录 |
–with-zlib-opt= | 在编译时为 zlib 设置附加参数 |
–with-zlib-asm= | 为指定的 CPU 使用 zlib 汇编源进行优化,CPU 类型为 pentium, pentiumpro |
–with-libatomic | 为原子内存的更新操作的实现提供一个架构 |
–with-libatomic= | 指向 libatomic_ops 安装目录 |
–with-openssl= | 指向 openssl 安装目录 |
–with-openssl-opt | 在编译时为 openssl 设置附加参数 |
–with-debug | 启用 debug 日志 |
参数 | 注释 |
---|---|
$arg_PARAMETER | HTTP 请求中某个参数的值,如/index?site=www.ttlsa.com,可以用$arg_site 取得 www.ttlsa.com 这个值 |
$ args: | 变量中存放了请求URL中的请求指令。比如http://192.168.200.133:8080?arg1=value1&args2=value2中 的"arg1=value1&arg2=value2",功能和$query_string一样 |
$http_user_agent: | 变量存储的是用户访问服务的代理信息(如果通过浏览器访问,记录的是浏览器的相关版本信息) |
$host : | 变量存储的是访问服务器的server_name值 |
$hostname | 表示 Nginx 所在机器的名称,与 gethostbyname 调用返回的值相同 |
$uri | 表示当前请求的 URI,不带任何参数 |
$ document_uri : | 变量存储的是当前访问地址的URI。比如http://192.168.200.133/server?id=10&name=zhangsan中的"/server",功能和$uri一样 |
$document_root: | 变量存储的是当前请求对应location的root值,如果未设置,默认指向Nginx自带html目录所在位置 |
$body_bytes_sent | 表示在向客户端发送的 http 响应中,包体部分的字节数 |
$content_length : | 变量存储的是请求头中的Content-Length的 值 |
$content_type : | 变量存储的是请求头中的Content-Type的值 |
$cookie_COOKIE | 表示在客户端请求头部中的 cookie 字段 |
$http_HEADER | 表示当前 HTTP 请求中相应头部的值。HEADER 名称全小写。例如,示请求中 Host 头部对应的值 用 $http_host 表 |
$http_cookie : | 变量存储的是客户端的cookie信息,可以通过add_header Set-Cookie 'cookieName=cookieValue’来添加cookie数 据 |
$sent_http_HEADER | 表示返回客户端的 HTTP 响应中相应头部的值。HEADER 名称全小写。例如,用 $sent_ http_content_type 表示响应中 Content-Type 头部对应的值 |
$is_args | 表示请求中的 URI 是否带参数,如果带参数,$is_args 值为 ?,如果不带参数,则是空字符串 |
$limit_rate : | 变量中存储的是Nginx服务器对网络连接速率的限制,也就是Nginx配置中对limit_rate指令设置的值,默认是0,不限制。 |
$nginx_version | 表示当前 Nginx 的版本号 |
$query_string | 请求 URI 中的参数,与 $args 相同,然而 $query_string 是只读的不会改变 |
$remote_addr : | 变量中存储的是客户端的IP地址 |
$remote_port : | 变量中存储了客户端与服务端建立连接的端口号 |
$remote_user : | 变量中存储了客户端的用户名,需要有认证模块才能获取 |
$scheme | 变量中存储了访问协议 |
$server_addr | 变量中存储了服务端的地址 |
$server_name | 变量中存储了客户端请求到达的服务器的名称 |
$server_port | 变量中存储了客户端请求到达服务器的端口号 |
$server_protocol | 变量中存储了客户端请求协议的版本,比如"HTTP/1.1" |
$request_body | 表示 HTTP 请求中的包体,该参数只在 proxy_pass 或 fastcgi_pass 中有意义 |
$request_body_file | 变量中存储了发给后端服务器的本地文件资源的名称 |
$request_completion | 当请求已经全部完成时,其值为 “ok”。若没有完成,就要返回客户端,则其值为空字符串;或者在断点续传等情况下使用 HTTP range 访问的并不是文件的最后一块,那么其值也是空字符串。 |
$request_method | 变量中存储了客户端的请求方式,比如"GET","POST"等 |
$request_filename | 变量中存储了当前请求的资源文件的路径名 |
$request_uri : | 变量中存储了当前请求的URI,并且携带请求参数,比如http://192.168.200.133/server?id=10&name=zhangsan中的"/server?id=10&name=zhangsan" |