@octopus
2018-05-05T20:40:54.000000Z
字数 14595
阅读 2206
nginx
nginx -tc /etc/nginx/nginx.conf // 查看是否有配置错误
ab -n 50 -c 20 www.xxxx.com // 总共请求50次,同时并发20个请求
- IO多路复用 epoll
红黑树维护申请的事件,当事件被触发,通过回调函数自动把事件 添加到双向链表中,所以最大连接无限制,效率也更高。在 nginx 中 epoll 的应用:https://www.cnblogs.com/yimuren/p/4105124.html
- 轻量级,功能模块少,代码模块化
- CPU 亲和
将nginx的每个worker进程与固定的cpu绑定,减少切换损耗的性能
- sendfile机制
静态文件不走用户空间,直接通过内核空间传递给socket(关于 sendfile:https://my.oschina.net/lemonfight/blog/659133)
user 设置 nginx 的使用用户
worker_processes 工作进程数(最好与核数保持一致)
error_log nginx 的错误日志
pid nginx 服务启动时候的pid
worker_connections 每个进程允许的最大连接数
use 定义内核模型
http{
...
server{
# http 模块下的具体服务器配置,可以配置多个
listen 80;
server_name localhost;
location /{
# 服务器的路径相关配置
root /usr/local/nginx/html;
index index.html index.htm
}
error_page 500 502 503 504 /50.html
# 当页面状态码为这些时,转到 /50.html
location /50.html{
# 定义上面的文件路径
root /usr/local/nginx/html/50.html;
}
}
server{
...
}
}
定义日志格式,要写在 http
模块下
http{
...
access_log /var/log/nginx/access.log main // 类型 位置 格式名
log_format main '$remote_addr [$time_local]'; // log_format 格式名 格式
}
arg_PARAMETER // 参数
http_HEADER // 请求头信息
sent_http_HEADER // 返回头信息
// 注意,要把大写变小写,横杠变下划线,前面加$
// 获取用户浏览器信息
User-Agent => $http_user_agent
nginx -V 查看默认安装的模块
Syntax: stub_status
Default: -
Context: server/location
location /mystatus{
stub_status;
}
浏览器访问 127.0.0.1/mystatus,会看到活跃连接数、握手次数、建立连接数、总请求数、读的个数、写个数、等待个数
Syntax: limit_conn_zone key zone=name:size // 申请一块空间,设置空间名和大小和key
Default: - // 默认没有配置
Context: http // 在http下配置
Syntax: limit_conn zone number // 空间名,并发个数限制
Default: -
Context: http,server,location
Syntax: limit_req_zone key zone=name:size rate=rate // 申请一块空间,设置空间名和大小和key,设置允许请求的速率
Default: -
Context: http
Syntax: limit_req zone=name // 空间名,并发个数限制
Default: -
Context: http,server,location
// 请求限制
// 解释:申请空间,将 ip 地址作为键,空间大小为1m,限制速率为1秒请求一次
http{
limit_req_zone $binary_remote_addr zone=req_zone:1m rate=1r/s;
server{
...
location / {
limit_req zone=req_zone;
}
}
}
// 连接限制
http{
limit_conn_zone $binary_remote_addr zone=conn_zone:1m;
server{
...
location / {
limit_conn conn_zone 1;
}
}
}
缺点:当使用代理等工具就会由 ip1->ip2->nginx ,最终获取到的是 ip2的地址,所以不精确
Syntax: allow/deny address|CIDR|unix:|all // 允许的ip地址、网段、socket、所有
Default: -
Context: http,server,location,limit_except
// ~ 表示匹配模式,匹配到以 /admin.html 开头的
// 不允许本机访问,其他所有ip都可访问
location ~ ^/admin.html {
root /admin/
deny 127.0.0.1
allow all
}
密码加密需要用到 htpasswd ,首先要 yum 安装它:yum -y install httpd-tools
缺点:机械化,不利于管理用户
Syntax: auth_basic string|off // 进行认证的字符串提示,或关闭认证
Default: off // 默认关闭
Context: server,location,limit_except
Syntax: auth_basic_user_file file
Default: -
Context: http,server,location,limit_except
// 1. 第一步,生成存储用户名密码的文件,写用户名和密码
htpasswd -c auto_conf username
// 2. 配置文件
location ~ ^/admin.html {
root /admin/
auth_basic "input your passward!";
auth_basic_user_file auto_conf;
}
Syntax: sendfile on|off
Default: off // 默认关闭
Context: http,server,location
在 sendfile 开启的条件下,提高网络包的传输效率。
发送网络包时,不再一个一个发包,而是整合多个包一次发送
Syntax: tcp_nopush on|off
Default: off // 默认关闭
Context: http,server,location
在 keeplive 长连接的前提下有效
立刻发送数据包,与上面的nopush对立,在实时性要求高的场景使用
Syntax: tcp_nodelay on|off
Default: on // 默认打开
Context: http,server,location
压缩传输
Syntax: gzip on|off // 是否开启压缩传输
Default: off
Context: http,server,location
Syntax: gzip_comp_level level // 压缩比
Default: gzip_comp_level 1 // 默认是1,提高压缩比会对性能有损耗
Context: http,server,location
预读 gzip 功能,返回目录下gzip压缩过的文件
server{
...
sendfile on;
// 所有以图片格式结尾的文件,gzip压缩,压缩比2,
location ~ .*\.(jpg|gif|png)$ {
gzip on;
gzip_http_version 1.1;
gzip_comp_level 2;
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
root /opt/app/code/images;
}
// 所有以txt或xml格式结尾的文件,gzip压缩,压缩比1,
location ~ .*\.(txt|xml)$ {
gzip on;
gzip_http_version 1.1;
gzip_comp_level 1;
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
root /opt/app/code/doc;
}
// 以download开头的文件,预读gzip,开启tcp_nopush
location ~ ^/download {
gzip_static on;
tcp_nopush on;
root /opt/app/code;
}
}
expires 1d;
Access-Control-Allow-Origin
Syntax: add_header name value; // 添加头信息
Default: -
Context: http,server,location
location .*\.(html|htm)$ {
add_header Access-Control-Allow-Origin http://www.xxx.com
add_header Access-Control-Allow-Methods GET,POST;
}
referer 为当前链接的上一页链接,比如在 a 页面打开了 b 的链接,b 的nginx 就可以获取 referer 值为 a 的地址
valid_referers none blocked 116.62.103.228 jeson.imoocc.com ~/baidu\./;
if ($invalid_referer) {
return 403;
}
// none 代表没有上一页,是直接打开的
// blocked 代表有referer但是被防火墙或者是代理给去除了
// 可以指定允许访问当前站点资源的地址或域名
// 支持正则匹配
// 验证通过,$invalid_referer变量值为0,未通过为1
正向代理与反向代理的区别:
- 代理的对象不一样。
- 正向代理代理的对象是客户端,比如翻墙,n个客户端去请求一个代理服务器,让代理服务器去抓我们要的页面。
- 反向代理代理的对象是服务器端,比如集群,访问的是 a.com,实际上 a.com对应很多服务器,反向代理可以把适配的某台服务器信息给用户
Syntax: proxy_pass url; // 设定反向代理的跳转url
Default: -
Context: location
// 当请求根路径时,反向道理到 8080 端口
location / {
proxy_pass http://127.0.0.1:8080;
}
// 通过本机转发请求相应服务器
// 设置浏览器代理为此服务器即可
location / {
proxy_pass http://$http_host$request_uri;
}
location / {
// 当上游服务器返回的响应是重定向或刷新请求(如HTTP响应码是301或者302)时,proxy_redirect可以重设HTTP头部的location或refresh字段。
proxy_redirect default;
// 由于经过代理实际客户端的ip或域名会更改,就可以通过设置头信息返回正确的头信息
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
// 设置一些超时时间
proxy_connect_timeout 30;
proxy_send_timeout 60;
proxy_read_timeout 60;
// 设置缓冲区大小,是否开启缓冲区等 详见:(https://www.cnblogs.com/me115/p/5698787.html)
proxy_buffer_size 32k;
proxy_buffering on;
proxy_buffers 4 128k;
proxy_busy_buffers_size 256k;
proxy_max_temp_file_size 256k;
}
当检测到某一主机无法到达,则自动不会再转发到改主机
Syntax: upstream name{...};
Default: -
Context: http // 注意是配置在 http 层
http{
...
upstream test { // 定义集群名以及包含的主机
server 127.0.0.1:8081;
server 127.0.0.1:8082;
server test.com:8083;
}
server{
...
location / {
proxy_pass http://test // 设置负载均衡的集群名
}
}
}
down 当前 server 暂时不参与负载均衡
backup 预留的备份服务器,即在其他服务器‘存活’时,不参与负载均衡
max_fails 允许请求某服务器失败的次数,即当某一负载服务器挂掉,会再请求max_fails次确认
fail_timeout 设置不再请求连接失败服务器的时间,即fail_timeout后,再次请求某失败服务器
max_conns 限制最大的接收连接数
http{
upstream test {
server 127.0.0.1:8001 down;
server 127.0.0.1:8002 backup;
server 127.0.0.1:8003 max_fails=1 fail_timeout=10s;
}
}
轮询 按照时间顺序逐一分配到不同服务器
加权轮询 按照全权重分配,权重越大被访问的几率越高
ip_hash 每个请求按访问ip的hash结果分配,同一ip访问相同服务器,缺点在于使用代理时无法定位正确的ip
url_hash
hash关键数值
# 设置 weight 权重,如下当有7个连接请求时,5个都会到 8003 端口上去
http{
upstream test {
server 127.0.0.1:8001;
server 127.0.0.1:8002;
server 127.0.0.1:8003 weight=5;
}
}
# 只需要在upstream加上 ip_hash ,再把其他权重设置等删掉即可
http{
upstream test {
ip_hash
server 127.0.0.1:8001;
server 127.0.0.1:8002;
server 127.0.0.1:8003;
}
}
只要用正则提取出想要 hash 的值放到自定义变量中,再在 upstream 加上 hash $xxx 即可
http{
upstream test {
hash $request_uri;
server 127.0.0.1:8001;
server 127.0.0.1:8002;
server 127.0.0.1:8003;
}
}
https://blog.csdn.net/u012081441/article/details/71787164
以及php配置将session写进redis的简单实现:https://www.cnblogs.com/hfdp/p/6671298.html
// proxy_cache配置语法
Syntax: proxy_cache_path path [levels=levels]
Default: -
Context: http
Syntax: proxy_cache zone|off
Default: off
Context: http,server,location
// 缓存过期时间配置
Syntax: proxy_cache_valid [code..] time;
Default: -
Context: http,server,location
// 缓存维度设置
Syntax: proxy_cache_key string;
Default: proxy_cache_key $scheme$proxy_host$request_uri;
Context: http,server,location
http{
// 设置缓存目录;
// levels 设置目录分级 1:2 分两级;
// keys_zone 设置 key 的空间名,以及key的大小;
// max_size 表示缓存大小,超过以后则根据规则删除不常用键值
// inactive 60分钟内没有被用到的缓存被清除
// use_temp_path 是否使用临时路径
proxy_cache_path /opt/app/cache levels=1:2 keys_zone=test_cache:10m max_size=10g inactive=60m use_temp_path=off;
upstream test {
server 127.0.0.1:8081;
server 127.0.0.1:8082;
server test.com:8083;
}
server{
location / {
proxy_cache test_cache; // 使用 zone 为test_cache的配置
proxy_pass http://test; // 基于代理模式缓存
proxy_cache_valid 200 304 12h; // 对响应头为 200 与 304 的设置12小时过期
proxy_cache_valid any 10m; // 除此之外的,设置10分钟后过期
proxy_cache_key $host$uri$is_args$args; // 设置 key 格式
add_header Nginx-Cache "$upstream_cache_status"; // 添加一个头信息,告诉客户端是否命中
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
// 当服务器出现以上错误码或错误信息,则轮询到下一台服务器
include proxy_params;
}
}
}
指定页面不缓存
Syntax: proxy_no_cache [args..]
Default: -
Context: http,server,location
server{
// 匹配到以下页面不缓存
if($request_uri ~ ^/(url3|login|register|password\/rest)) {
set $cookie_nocache 1;
}
location /{
...
proxy_no_cache $cookie_nocache
}
}
php 等需要动态加载的文件与图片等静态文件分别配置
通过反向代理的方式,配合 location 正则匹配实现
http{
upstream php_api{
server 127.0.0.1:8080
}
server{
root /xxx/public
location ~ \.php$ { // 以 php 结尾的文件
proxy_pass http://php_api
index index.html index.htm
}
location ~ \.(jpg|png|gif)$ {
expires 1h;
gzip on;
}
}
}
Syntax: rewrite regex replacement[flag];
Default: -
Context: server,location,if
// 所有的url,都跳到/index.html
rewrite ^(.*)$ /index.html break;
. 匹配除换行符以外的任意字符
? 重复0次或1次
+ 重复1次或更多次
* 重复任意次
\d 匹配数字
^ 匹配以某字符串开头
$ 匹配以某字符串结尾
{n} 重复n次
{n,} 重复n次或更多次
[c] 匹配单个字符c
[a-z] 匹配a-z中任意一个字符
\ 转义
() 提取()中的内容,用 $1 取到第1个()中的内容
break 若跳转失败,则直接返回(默认404)
last 若跳转失败,会从新发起请求,继续往下查找是否有匹配的location规则
redirect 临时重定向
permanent 永久重定向
server {
root /opt/app/code;
location ~ ^/break {
rewrite ^/break /test/ break;
// 路径下没有文件,404
}
location ~ ^/last {
rewrite ^/last /test/ last;
// 路径下没有文件,但下面定义了匹配路由,成功返回该路由
}
location /test/ {
default_type application/json;
return 200 '{"status":"success"}';
}
}
location / {
// 匹配
rewrite ^/test-(\d+)\.html$ /test-.html break;
// 当请求的浏览器是Chrome时,重定向
if ($http_user_agent ~* Chrome) {
rewrite ^/nginx http://test.html redirect;
}
// 当访问的文件不存在时,重定向
if (!-f $request_filename) {
rewrite ^/(.*)$ http://www.baidu.com/$1 redirect;
}
index index.html index.htm;
}
限制链接生效周期
检查链接的真实性
Syntax: secure_link expression;
Default: -
Context: http,server,location
Syntax: secure_link_md5 expression;
Default: -
Context: http,server,location
校验时主要针对两点:加密验证、过期校验
location / {
// 校验的参数项,本例分别是从链接取到的 md5 参数,以及 expires 参数
secure_link $arg_md5,$arg_expires;
// 加密的生成方式
secure_link_md5 "$secure_link_expires$uri test";
// 判断是否校验成功
if ($secure_link = "") {
return 403;
}
if ($secure_link = "0") {
return 410;
}
}
链接的生成方式是用 openssl
#!/bin/sh
servername="test.com"
download_file="/download/file.img"
time_num=$(date -d "2018-10-18 00:00:00" +%s)
secret_num="test" // 与nginx的配置一致
res=$(echo -n "${time_num}${download_file} ${secret_num}"|openssl md5 -binary | openssl base64 | tr +/ -_ | tr -d =)
echo "http://${servername}${download_file}?md5=${res}&expires=${time_num}"
基于ip地址匹配MaxMind GeoIp二进制文件,读取ip所在地域信息
可以实现根据地域访问特定服务器
// 1. 由于不是默认模块,需要手动引入(在全局块配置)
load_module "module/ngx_http_geoip_module.so";
load_module "module/ngx_stream_geoip_module.so";
http{
// 定义地域文件地址变量
geoip_country /etc/nginx/geoip/GeoIP.dat;
geoip_city /etc/nginx/geoip/GeoLiteCity.dat;
server {
...
// 即可获取到geoip变量
// $geoip_country_name 国家名
// $geoip_country_code 国家代号
// $geoip_city 城市
location / {
if ($geoip_country_code != CN) {
return 403;
}
root /usr/share/nginx/html;
index index.html index.htm;
}
location /myip {
default_type text/plain;
return 200 "$remote_addr $geoip_country_name $geoip_country_code $geoip_city";
}
}
}
对称加密:
对称加密,即加密与解密双方都用同一套密钥
缺点: 一旦第三方 c 劫持了密钥,a 发送给 b 的信息,c 也可以解密出来,不安全
非对称加密:
非对称加密,即 b 掌管私钥,a 获得公钥,a 发给 b 的信息,只有 b 自己能解密出来,c 劫持了公钥也不能解密
上述非对称加密虽然拦截后不能识别消息,但黑客可以生成自己的一套私钥与密钥,伪装成正经服务器,这样客户收到的公钥也是黑客传的,依然不安全。
ca证书是服务器端向证书机构申请的,客户端只要用签名证书信息去查询比对即可知道是不是真的服务器,而不是黑客伪造的链接
1. 安装 openssl
2. nginx -v 查看是否有 --with-http_ssl_module 模块
3. 生成密钥key
4. 生成证书签名请求文件(csr文件)
5. 生成证书(CA 文件)
Syntax: ssl on|off;
Default: off
Context: http,server
Syntax: ssl_certificate file;
Default: -
Context: http,server
Syntax: ssl_certificate_key file;
Default: -
Context: http,server
server
{
listen 443;
server_name test.com;
keepalive_timeout 100;
ssl on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeour 10m;
ssl_certificate /etc/nginx/ssl_key/jesonc.crt;
ssl_certificate_key /etc/nginx/ssl_key/jesonc.key;
location / {
...
}
}
安装 lua 解释器 :yum -y install lua
#!/user/bin/lua
print("i am test")
-- 行注释
--[[
块注释
]]--
-- 变量
a = "xxx"
-- 布尔类型只有 nil 和 false 是 false,
-- 数字0 与空字符串,都是 true
-- 变量若无特殊说明都是全局变量
-- 若声明非全局变量,前面加 local
-- while 循环
sum = 0
num = 1
while num <= 10 do
sum = sum + num
num = num + 1
end
print("sum = ",sum);
-- for 循环
sum = 0
for i=1,100 do
sum = sum + i
end
-- if else
if a = 10 and b = "xxx" then
print("xxx")
elseif c ~= 30 then
print("xxx")
else
local d = io.read()
print(d)
end
-- ~= 不等于
-- 字符串拼接符:".."
1. 下载LuaJIT(更高效的解释器)
2. ngx_devel_kit 和lua-nginx-module
3. 重新编译 Nginx
当指定路径不存在时,转到try_files定义的路径
对缓存很有用,当缓存文件不存在时,跳转到动态页面
location / {
root /opt/app/code;
try_files /cache $uri @java_page;
}
location @java_page{
proxy_pass http://127.0.0.1:9090;
}
// 当请求 /url/img/1.png 时
// 实际请求的地址是 root+location 即 /local/url/img/1.png
location /url/img/ {
root /local/;
}
// 实际请求的地址是 root+location 即 /local/1.png
location /url/img/ {
alias /local/;
}
ip1 -> ip2 -> ipn -> 后端
1. X-Forwarded-For 获取,但容易被篡改
2. 在第一层代理设置ip变量 set x_real_ip = $remote_addr
413 Request Entity Too Large 用户上传文件过大
用户上传文件限制 client_max_body_size
502 Bad Gateway 后端错误
504 Gateway Time Out 后端超时
yum -y install httpd-tools
ab -n 1000 -c 100 http://www.test.com 共发起 2000 次连接请求,并发数是 10
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests
Server Software: Apache/2.0.63
Server Hostname: sports.sina.com.cn
Server Port: 80
Document Path: /k/2011-05-24/12095590365.shtml
Document Length: 86680 bytes
Concurrency Level: 100
Time taken for tests: 66.453 seconds // 用时多少秒
Complete requests: 1000 // 总共多少请求
Failed requests: 0 // 失败几个
Write errors: 0
Total transferred: 87135790 bytes
HTML transferred: 86680000 bytes
Requests per second: 15.05 [#/sec] (mean) // 每秒处理多少请求
Time per request: 6645.294 [ms] (mean) // 每个请求用时
Time per request: 66.453 [ms] (mean, across all concurrent requests) // 后端处理每个请求用时
Transfer rate: 1280.51 [Kbytes/sec] received // 数据传输速率,与网络情况有关
Connection Times (ms)
min mean[+/-sd] median max
Connect: 1 56 398.3 2 3003
Processing: 89 6331 2603.7 6293 14626
Waiting: 2 1748 1485.9 1590 6284
Total: 90 6388 2615.0 6302 14627
Percentage of the requests served within a certain time (ms)
50% 6302
66% 7121
75% 8435
80% 9193
90% 9231
95% 9385
98% 11549
99% 12459
100% 14627 (longest request)
vim /etc/security/limits.conf
* soft nofile 20000
* hard nofile 20000
worker_processes 16; // 16核
#worker_cpu_affinity 0000000000000010 0000000000000010 0000000000000100 0000000000001000 0000000000010000 0000000000100000 0000000001000000 0000000010000000 0000000100000000 0000001000000000 0000010000000000 0000100000000000 0001000000000000 0010000000000000 0100000000000000 1000000000000000; // 手动绑定
worker_cpu_affinity auto; // 自动绑定(推荐)