基于Nginx深入浅出亿级流量架构设计
- 环境准备/安装部署
- Nginx四个发行版本简单介绍
- Nginx的安装
- Nginx的目录结构与基本运行原理及其最小配置解析
- Nginx虚拟主机与域名配置
- ServerName匹配规则
- 反向代理在系统结构中的应用场景
- Nginx的反向代理配置
环境准备/安装部署
虚拟机使用VMware Workstation Pro 16
版本
省略安装系统过程,可参考VMware 安装 Centos7(超详细教程)
本次实验学习基于源码编译安装 nginx 1.21.6
# 系统环境
3.10.0-862.el7.x86_64
CentOS Linux release 7.5.1804 (Core)
# 设置Yum源
curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo
sed -i -e '/mirrors.cloud.aliyuncs.com/d' -e '/mirrors.aliyuncs.com/d' /etc/yum.repos.d/CentOS-Base.repo
yum makecache fast
# 必备工具安装
yum install wget vim net-tools telnet yum-utils -y
# 关闭firewalld selinux
systemctl disable --now firewalld
setenforce 0
sed -i 's#SELINUX=enforcing#SELINUX=disabled#g' /etc/sysconfig/selinux
sed -i 's#SELINUX=enforcing#SELINUX=disabled#g' /etc/selinux/config
reboot
# 如未关闭防火墙也可放行端口
firewall-cmd --zone=public --add-port=80/tcp --permanent
# 重启防火墙
firewall-cmd --reload
学习时的电脑配置
内存:建议8G以上
磁盘:建议使用SSD
CPU:4核以上主流即可
主机 | IP地址 | 主机配置 | 安装的软件 |
---|---|---|---|
lr-nginx-01 | 192.168.100.111 | 2核4G | Nginx |
lr-nginx-02 | 192.168.100.112 | 2核4G | Nginx |
lr-nginx-02 | 192.168.100.113 | 2核4G | Nginx |
Nginx四个发行版本简单介绍
常用版本分为四大阵营
- Nginx开源版 http://nginx.org/
- Nginx plus 商业版 https://www.nginx.com
- Openresty http://openresty.org
- Tengine http://tengine.taobao.org
Nginx的安装
基于
rpm
包进行离线安装
http://nginx.org/packages/centos/7/x86_64/RPMS/
wget -P /opt/ http://nginx.org/packages/centos/7/x86_64/RPMS/nginx-1.20.0-1.el7.ngx.x86_64.rpm
rpm -ivh /opt/nginx-1.20.0-1.el7.ngx.x86_64.rpm
基于
源码
编译安装
# 安装相关依赖
yum install gcc pcre pcre-devel zlib zlib-devel -y
# 编译安装
wget -P /opt/ http://nginx.org/download/nginx-1.21.6.tar.gz
tar xf nginx-1.21.6.tar.gz
cd nginx-1.21.6
./configure --prefix=/opt/nginx && make && make install
# 启动Nginx
cd /opt/nginx/sbin/
./nginx # 启动
./nginx -s stop # 快速停止
./nginx -s quit # 优雅关闭,在退出前完成已经接受的连接请求
./nginx -s reload #重新加载配置
安装成
系统服务
并创建服务脚本
vim /usr/lib/systemd/system/nginx.service
[Unit]
Description=nginx - web server
After=network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
PIDFile=/opt/nginx/logs/nginx.pid
ExecStartPre=/opt/nginx/sbin/nginx -t -c /opt/nginx/conf/nginx.conf
ExecStart=/opt/nginx/sbin/nginx -c /opt/nginx/conf/nginx.conf
ExecReload=/opt/nginx/sbin/nginx -s reload
ExecStop=/opt/nginx/sbin/nginx -s stop
ExecQuit=/opt/nginx/sbin/nginx -s quit
PrivateTmp=true
[Install]
WantedBy=multi-user.target
# 加载系统服务
systemctl daemon-reload
# 启动nginx并设置开机启动
systemctl enable nginx.service --now
Nginx的目录结构与基本运行原理及其最小配置解析
Nginx
的目录结构
基本请求流程
启动nginx后,/sbin/nginx
可执行文件运行,①master开启主进程读取nginx.conf
文件并校验配置文件②开启多个子进程响应请求,运行时会有两种进程,主进程master
不处理业务协调子进程,子进程worker
等待用户请求接入,读取nginx.conf
站点目录,由worker响应并解析,再加载index.html
nginx启动后是多进程的,由主进程fork
出的子进程响应请求,master协调子进程
Nginx
最小配置解析
worker_processes 1; # 工作的子进程个数默认为1,对应物理服务器内核CPU数,一个内核对应一个worker_processes
events { # 事件驱动模块
worker_connections 1024; # 每一个worker创建多少连接(单个业务进程可接受连接数),默认1024
}
http {
include mime.types; # mime.types(请求头),对应文件后缀名,引入http mime类型
default_type application/octet-stream; # 如果mime类型没有匹配上,默认使用二进制流的的方式传输
sendfile on; # 数据0拷贝,使用Linux的sendfile(socket,file,len)高效网络传输
keepalive_timeout 65; # 保持连接,超时断开时间
server { # 虚拟主机(vhost),一个nginx可以运行多个主机,一个主机有自己独立的站点
listen 80; # 当前主机监听端口号,不能重复
server_name localhost; # 主机名(配置域名)或IP地址
charset utf-8;
# location匹配路径, uri(资源)+server_name=url
location / { # http://atguigu.com/xxoo/index.html
root html; # 文件根目录(相对路径),相对于nginx主目录/opt/nginx
index index.html index.htm; # 默认页名称
}
# 服务器端内部错误报错,资源无法访问
error_page 500 502 503 504 /50x.html; # 报错编码对应页面
location = /50x.html {
root html;
}
}
}
Nginx虚拟主机与域名配置
域名、DNS和IP之间的关系
- 因为在网络上机器彼此连接只能互相识别IP,而数字标识较难记忆,所以才演化出域名来代替IP地址,当我们将在地址栏输入域名欲跳转到某个页面时,点击提交后会由专门的域名解析服务器(DNS服务器)对我们的域名进行解析,得出域名对应的IP地址再进行连接。所以如果我们直接在地址栏输入与域名对应的IP也可以跳转到同一个页面。
- 虽然同一个域名只能绑定一个IP地址,但是因为一个域名可以设定多个DNS服务或者服务器进行解析,同一个域名的每个解析就可以指向不同的IP地址,这样应答快的DNS优先进行解析,能保证最快定向到指定的网站空间去,这是用户所不知道的。
总结
- 地址栏输入域名后,会由专门的域名解析服务器
- 同一个域名只能绑定一个IP地址
- 一个域名可以设定多个DNS服务或者服务器进行解析,同一个域名的每个解析就可以指向不同的IP地址
- 应答快的DNS优先进行解析
http协议
HTTP
协议(超文本传输协议HyperText Transfer Protocol),它是基于TCP协议的应用层传输协议,简单来说就是客户端和服务端进行数据传输的一种规则。
注意:客户端与服务器的角色不是固定的,一端充当客户端,也可能在某次请求中充当服务器。这取决与请求的发起端。HTTP协议属于应用层,建立在传输层协议TCP之上。客户端通过与服务器建立TCP连接,之后发送HTTP请求与接收HTTP响应都是通过访问Socket接口来调用TCP协议实现。
HTTP
是一种无状态 (stateless) 协议, HTTP协议本身不会对发送过的请求和相应的通信状态进行持久化处理。这样做的目的是为了保持HTTP协议的简单性,从而能够快速处理大量的事务, 提高效率。
然而,在许多应用场景中,我们需要保持用户登录的状态或记录用户购物车中的商品。由于HTTP是无状态协议,所以必须引入一些技术来记录管理状态,例如Cookie。
虚拟主机原理
Nginx虚拟主机:Nginx部署在一个物理服务器上,却通过ip、端口、域名对外实现多个访问入口,让客户端以为是多个服务器,这就是虚拟主机
参考文章: Nginx从基本原理到开发实践
原本一台服务器只能对应一个站点,通过虚拟主机技术可以虚拟化成多个站点同时对外提供服务
Notepad++可以更改hosts文件,Nodepad++ 下载:https://notepad-plus.en.softonic.com/download
# 本机hosts文件路径
C:\Windows\System32\drivers\etc
...
192.168.100.111 nginx-devops.com
本机hosts
文件设置解析
# 虚拟主机环境准备
# 准备站点
mkdir /www && cd /www && mkdir web video
[root@lr-nginx-01 www]# ls
video web
echo "this is video web site." > video/index.html
echo "this is master web site." > web/index.html
# 基于端口的虚拟主机vhost
...
server {
listen 80;
server_name localhost;
charset utf-8;
location / {
root /www/web/;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
server {
listen 88;
server_name localhost;
charset utf-8;
location / {
root /www/video;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
...
...
# 基于域名的虚拟主机vhost
server {
listen 80;
server_name www.cloud611.fun;
charset utf-8;
location / {
root /www/web/;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
server {
listen 80;
server_name video.cloud611.fun;
charset utf-8;
location / {
root /www/video;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
...
公网域名解析与泛域名解析实战
DNS解析记录类型及分别代表什么含义?
A记录
:所对应的域名匹配一个独立的IP地址,把域名转向到IP地址记录在DNS服务器上CNAME记录
:将域名指向另外一个域名地址上,好处:有可能IP地址主机地址不是固定的,故直接解析到域名AAAA记录
:暂未普及NS记录
:DNS服务器MX记录
:邮件服务器
关于阿里云直接解析内网IP并且可以访问的问题
- DNS只是记录了你要解析的IP,无论是内网还是外网,你在当前环境下用域名访问你的内网IP,跟直接访问内网IP一样的道理
- 又或者说这种配置是本地
hosts
作用域提升到了局域网,简单来说是在公网DNS注册了一条记录,这条记录最后会返回给你,本机拿到记录会去找对应的IP
ServerName匹配规则
可以在同一个servername中配置多个域名
需要注意的是servername匹配分先后顺序,写在前面的匹配上就不会继续往下匹配了
# 完整匹配,我们可以在同一servername中匹配多个域名
server_name www.cloud611.fun video.cloud611.com;
# 通配符匹配
server_name *.cloud611.fun
# 通配符结束匹配
server_name cloud611.*;
# 正则匹配
server_name ~^[0-9]+\.cloud611\.fun$;
server_name
的配置格式之正则匹配
server {
listen 80;
server_name ~^(?<user>.+)\.example\.net$;
...
}
正则匹配格式,必须以~
开头,比如:server_name ~^www\d+\.example\.net$;
如果开头没有~
,则nginx认为是精确匹配,或者如果匹配字符中含有*
号,则会被认为是通配符匹配,不过非法的通配符格式。在逻辑上,需要添加^
和$
锚定符号。注意,正则匹配格式中.
为正则元字符,如果需要匹配.
,则需要反斜线转义。如果正则匹配中含有{
和}
则需要双引号引用起来,避免nginx报错,如果未加双引号,则nginx会报如下错误:directive "server_name" is not terminated by ";" in ...
特殊匹配格式
server_name ""; 匹配Host请求头不存在的情况。
server_name "-"; 无任何意义。
server_name "*"; 它被错误地解释为万能的名称,它从不用作通用或通配符服务器名称.
相反,它提供了server_name_in_redirect指令现在提供的功能.
现在不建议使用特殊名称"*",而应使用server_name_in_redirect指令.
匹配顺序
- 精确的名字
- 以*号开头的最长通配符名称,例如 *.example.org
- 以*号结尾的最长通配符名称,例如 mail.*
- 第一个匹配的正则表达式(在配置文件中出现的顺序)
优化
- 尽量使用精确匹配;
- 当定义大量server_name时或特别长的server_name时,需要在http级别调整
server_names_hash_max_size
和server_names_hash_bucket_size
,否则nginx将无法启动。
参考文章:Nginx系列之server_name定义与匹配规则
反向代理在系统结构中的应用场景
何为反向代理?
- 在介绍反向代理之前,先来了解一下正向代理。
- 正向代理: 如果把局域网外的 Internet 想象成一个巨大的资源库,则局域网中的客户端要访问 Internet,则需要通过代理服务器来访问,这种代理服务就称为正向代理。下面是正向代理的原理图。
- 由于工作环境原因,日常工作只能局限于单位的局域网,如果想要访问互联网,怎么办呢?这就需要用到正向代理。本人经常用正向代理来进行上网。
- 反向代理:看下面原理图,就一目了然。其实客户端对代理是无感知的,因为客户端不需要任何配置就可以访问,我们只需要将请求发送到反向代理服务器,由反向代理服务器去选择目标服务器获取数据后,在返回给客户端,此时反向代理服务器和目标服务器对外就是一个服务器,暴露的是代理服务器地址,隐藏了真实服务器 IP 地址。
- 正向代理和反向代理的区别,一句话就是:如果我们客户端自己用,就是正向代理。如果实在服务器用,我们用户无感知,就是反向代理。
- 这里有个问题:反向代理服务器,怎么选择挂在它后面的哪一台具体服务器呢?答案在后文揭晓,这就是
负载均衡
。
参考文章:https://zhuanlan.zhihu.com/p/451825018
Nginx的反向代理配置
# nginx01主机nginx.conf配置
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
server_tokens off;
keepalive_timeout 65;
server {
listen 80;
server_name www.cloud611.fun;
charset utf-8;
location / {
proxy_pass http://www.atguigu.com;# 如果不添加www,地址会自动跳转www.atguigu.com而不是阿里云DNS解析
# root /www/web/;
# index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
基于反向代理的负载均衡配置
<!-- 修改192.168.100.112&192.168.100.113 index.html文件 112&113 -->
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>开始HTML</title>
</head>
<body>
<h1>我是192.168.100.112!!!</h1>
</body>
</html>
将后端代理服务器转到192.168.100.111上
...
location / {
proxy_pass http://192.168.100.112;
}
...
——————————————————————————————————————————
# 和server同一级 http模块下
upstream upup {
server 192.168.100.112:80;
server 192.168.100.113:80;
}
负载均衡策略
- 轮询:默认情况下使用轮询方式,逐一转发,这种方式适用于无状态请求。无法保持会话
- weight(权重):指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。
upstream upup {
server 127.0.0.1:8050 weight=10 down; # down:表示当前的server暂时不参与负载
server 127.0.0.1:8060 weight=1; # weight:默认为1 weight越大,负载的权重就越大
server 127.0.0.1:8060 weight=1 backup; # backup:其它所有的非backup机器down或者忙的时候,请求backup机器.
}
- ip_hash:根据客户端的ip地址转发同一台服务器可以保持回话
- least_conn:最少连接访问
- url_hash:根据用户访问的url定向转发请求定向流量转发
- fair:根据后端服务器响应时间转发请求