2024-04-07

Nginx应用案例

1. Nginx概述

nginx [engine x] 是一个高性能的HTTP和反向代理服务器,同时也是一个IMAP/POP3/SMTP代理服务器。nginx 在其高并发连接处理能力上表现得尤为出色,能够支持高达50000个并发连接数。

2. Nginx缘起历史

nginx 由俄罗斯的程序员Igor Sysoev所开发,公开发布于2004年。Sysoev开始开发nginx的原因是他想要解决C10K问题 —— 如何在一台普通的硬件服务器上同时处理大量客户端的请求。

3. 主流企业场景

nginx在全球各大互联网公司都有着广泛的应用,它们中的很多都是世界流量最大的网站,如:Netflix、Facebook、Zhilian Zhaopin等。这些公司使用nginx,主要是基于其出色的稳定性和高并发处理能力。

4. Nginx优势

nginx之所以能在众多的Web服务器软件中脱颖而出,主要是由于它具有以下几个显著的优点:

  • 能够处理更多的并发连接,且性能稳定,内存占用极低。
  • 配置文件简洁明了,易于理解。
  • 支持热部署,对业务无感。
  • 强大的反向代理和负载均衡能力,可以方便地进行A/B测试。

5.Nginx 应用程序命令

nginx -s reload # 向主进程发送信号,重新加载配置文件,热重启
nginx -s reopen # 重启 Nginx
nginx -s stop # 快速关闭
nginx -s quit # 等待工作进程处理完成后关闭
nginx -T # 查看当前 Nginx 最终的配置
nginx -t # 检查配置是否有问题

二、nginx进程结构与模块化设计

image.png
  1. nginx进程结构
    nginx采用多进程模型,主要包括一个主进程(master process)和多个工作进程(worker process)。这种设计使得nginx能够充分利用多核CPU资源,提高并发处理能力。

主进程:

负责读取和验证配置文件
创建、管理和监控工作进程
接受外部信号,并进行相应处理(如平滑升级、重载配置等)
工作进程:

处理实际的网络连接和请求
采用非阻塞IO模型,实现高并发处理
工作进程之间通过共享内存进行通信,协同工作

  1. nginx模块化设计机制
    nginx的模块化设计是其灵活性和可扩展性的关键所在。nginx核心提供基础功能,而各种功能模块则通过插件形式加载,实现不同的功能需求。

nginx模块分为核心模块、标准HTTP模块和可选HTTP模块。核心模块负责nginx的基本功能,如事件处理、网络连接等;标准HTTP模块提供HTTP协议处理的基本功能;可选HTTP模块则提供了诸如访问控制、负载均衡、缓存等扩展功能。

模块化的设计使得nginx可以轻松添加新功能,而不必修改核心代码。同时,模块之间的独立性也保证了系统的稳定性和可靠性。

  1. nginx热部署
    nginx支持热部署(hot deployment),即在不停止服务的情况下升级nginx或重载配置文件。这一特性使得nginx在生产环境中具有极高的可用性和灵活性。

通过发送特定的信号给nginx主进程,可以实现热部署操作。例如,发送HUP信号可以重载配置文件,而发送USR2信号则可以实现平滑升级。

  1. nginx配置文件结构
    nginx的配置文件采用层次化的结构,主要由全局块、events块、http块等部分组成。每个块内又可以包含多个指令,用于配置nginx的各种参数和行为。

例如:

# main段配置信息
user  nginx;                        # 运行用户,默认即是nginx,可以不进行设置
worker_processes  auto;             # Nginx 进程数,一般设置为和 CPU 核数一样
error_log  /var/log/nginx/error.log warn;   # Nginx 的错误日志存放目录
pid        /var/run/nginx.pid;      # Nginx 服务启动时的 pid 存放位置

# events段配置信息
events {
    use epoll;     # 使用epoll的I/O模型(如果你不知道Nginx该使用哪种轮询方法,会自动选择一个最适合你操作系统的)
    worker_connections 1024;   # 每个进程允许最大并发数
}

# http段配置信息
# 配置使用最频繁的部分,代理、缓存、日志定义等绝大多数功能和第三方模块的配置都在这里设置
http { 
    # 设置日志模式
    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;   # Nginx访问日志存放位置

    sendfile            on;   # 开启高效传输模式
    tcp_nopush          on;   # 减少网络报文段的数量
    tcp_nodelay         on;
    keepalive_timeout   65;   # 保持连接的时间,也叫超时时间,单位秒
    types_hash_max_size 2048;

    include             /etc/nginx/mime.types;      # 文件扩展名与类型映射表
    default_type        application/octet-stream;   # 默认文件类型

    include /etc/nginx/conf.d/*.conf;   # 加载子配置项
    
    # server段配置信息
    server {
     listen       80;       # 配置监听的端口
     server_name  localhost;    # 配置的域名
      
     # location段配置信息
     location / {
      root   /usr/share/nginx/html;  # 网站根目录
      index  index.html index.htm;   # 默认首页文件
      deny 172.168.22.11;   # 禁止访问的ip地址,可以为all
      allow 172.168.33.44;# 允许访问的ip地址,可以为all
     }
     
     error_page 500 502 503 504 /50x.html;  # 默认50x对应的访问页面
     error_page 400 404 error.html;   # 同上
    }
}
  • main 全局配置,对全局生效;
  • events 配置影响 Nginx 服务器与用户的网络连接;
  • http 配置代理,缓存,日志定义等绝大多数功能和第三方模块的配置;
  • server 配置虚拟主机的相关参数,一个 http 块中可以有多个 server 块;
  • location 用于配置匹配的 uri ;
  • upstream 配置后端服务器具体地址,负载均衡配置不可或缺的部分;


    image.png
  1. 目录结构
# Nginx配置文件
/etc/nginx/nginx.conf # nginx 主配置文件
/etc/nginx/nginx.conf.default

# 可执行程序文件
/usr/bin/nginx-upgrade
/usr/sbin/nginx

# nginx库文件
/usr/lib/systemd/system/nginx.service # 用于配置系统守护进程
/usr/lib64/nginx/modules # Nginx模块目录

# 帮助文档
/usr/share/doc/nginx-x.x.x
/usr/share/doc/nginx-x.x.x/CHANGES
/usr/share/doc/nginx-x.x.x/README
/usr/share/doc/nginx-x.x.x/README.dynamic

# 静态资源目录
/usr/share/nginx/html/404.html
/usr/share/nginx/html/50x.html
/usr/share/nginx/html/index.html

# 存放Nginx日志文件
/var/log/nginx

6. nginx虚拟主机分类及具体示例

虚拟主机是一种将单个服务器划分成多个独立的网站托管环境的技术。Nginx 支持三种主要类型的虚拟主机:

基于 IP 地址的虚拟主机(常用)

这种类型的虚拟主机是通过不同的 IP 地址来区分不同的网站。每个 IP 地址绑定到一个特定的网站或应用程序。这种虚拟主机适用于需要在同一服务器上为每个网站提供独立的资源和配置的场景。

基于域名的虚拟主机(常用)

基于域名的虚拟主机是根据不同的域名来区分不同的网站。多个域名可以共享同一个 IP 地址,并通过 Nginx 的配置来分发流量到正确的网站。这种虚拟主机适用于在单个服务器上托管多个域名或子域名的情况。

基于多端口的虚拟主机(不常用)

基于多端口的虚拟主机是一种将单个服务器上的多个网站隔离开来的方式。每个网站使用不同的端口号进行访问,从而实现隔离。这种方法特别适用于那些无法使用不同域名或 IP 地址的情况,或者需要在同一服务器上快速托管多个网站的需求。

基于 IP 地址的虚拟主机实现

# 基于 192.168.1.10 代理到百度网站
server {

  listen 192.168.1.10:80;

  server_name www.baidu.com;

  root /var/www/baidu ;

   index index.html; 

 } 

# 基于 192.168.1.11:80 代理到 bing 网站

server {

  listen 192.168.1.11:80;

  server_name www.bing.com;

  root /var/www/bing;

  index index.html;

}

最佳场景实践

  • 资源隔离: 每个网站都有独立的 IP 地址、资源和配置,避免了资源冲突和相互影响。
  • 安全性提升: 基于 IP 地址的虚拟主机可以增强安全性,减少不同网站之间的潜在风险。
  • 独立访问: 每个网站都有独立的 IP 地址,可以实现独立的访问控制和限制。
  • 多租户托管: 基于 IP 地址的虚拟主机适用于多租户托管场景,为不同客户提供独立环境。

基于域名的虚拟主机实现

# 通过 www.baidu.com 转发到 80

server {

  listen 80;

  server_name www.baidu.com;

  root /var/www/baidu;

  index index.html;

}

# 通过 www.bing.com 转发到 80

server {

  listen 80;

  server_name www.bing.com;

  root /var/www/bing;

  index index.html;

}

最佳场景实践

基于域名的虚拟主机为多站点托管提供了高度的定制性和灵活性:

  • 品牌差异化: 不同域名的虚拟主机允许您为不同品牌或应用提供独立的网站定制,提升用户体验。
  • 定向流量: 基于域名的虚拟主机可以将特定域名的流量引导至相应的网站,实现定向流量管理。
  • 子域名托管: 可以将不同子域名配置为独立的虚拟主机,为多个应用或服务提供托管。
  • SEO 优化: 每个域名的虚拟主机可以针对不同的关键词进行 SEO 优化,提升搜索引擎排名。

基于多端口的虚拟主机

  server {

  listen 8081;

  server_name www.baidu.com;

  root /var/www/baidu;

  index index.html;

}

server {

  listen 8082;

  server_name www.bing.com;

  root /var/www/bing;

  index index.html;

}

最佳场景实践

基于多端口的虚拟主机为多站点托管提供了更多的灵活性和选择:

  • 快速设置: 使用多端口可以快速设置多个网站,适用于临时性或开发环境。
  • 资源隔离: 每个网站都有独立的端口和配置,避免了资源冲突和相互干扰。
  • 开发和测试: 多端口虚拟主机适用于开发和测试环境,每个开发者可以使用不同的端口进行开发和调试。
  • 灰度发布: 基于多端口的虚拟主机可以实现灰度发布,逐步引导流量至新版本网站。

三、Nginx进程结构及应用

一、配置文件main段核心参数和用法

在nginx.conf的main部分,我们可以配置一些全局有效的参数。

例如:

user www www; # 用户和用户组
worker_processes 2; # 工作进程数
error_log /var/log/nginx/error.log crit; # 错误日志路径和级别
pid /var/run/nginx.pid; # pid文件路径
worker_rlimit_nofile 51200; # 设置每个nginx进程的最大打开文件数
worker_cpu_affinity 0001 0010 0100 1000; # 4个物理核心,4个worker子进程

worker_cpu_affinity
将每个 worker 子进程与我们的 cpu 物理核心绑定。


image.png

将每个 worker 子进程与特定 CPU 物理核心绑定,优势在于,避免同一个 worker 子进程在不同的 CPU 核心上切换,缓存失效,降低性能。但其并不能真正的避免进程切换。

二、events段核心参数和用法

在events部分,我们可以配置与连接有关的参数。

例如:

events {
    worker_connections 1024; # 单个后台worker process进程的最大并发链接数
    use epoll; # 设置IO模型,select/poll/epoll/kqueue/rtsig/devpoll/eventport
    multi_accept on; # 是否打开多网络连接接受
}

三、server_name指令用法和优先级

server_name指令用来设置服务器的名称,也就是虚拟主机的名字。Nginx会按照以下优先级来处理请求:

  1. 完全匹配
  2. 最长的基于前缀的通配符,例如 *.example.com
  3. 通配符在中间的名称,例如 www.*.com
  4. 正则表达式
server {
    listen       80;
    server_name  www.example.com;
    ...
}

四、root和alias的区别

  1. root 配置:

使用 root 指令时,Nginx 会将请求的 URL 路径与指定的根目录路径进行拼接。这意味着 URL 中的路径会映射到文件系统中的对应位置。

例如,假设我们有以下配置:

location /static/ {
    root /var/www/;
}

当收到的请求是 http://example.com/static/image.jpg 时,Nginx 会查找文件系统中的 /var/www/static/image.jpg 并返回该文件。

这里需要注意的是,root 指令会将匹配的 URL 路径直接映射到文件系统中的相对路径,而不是将请求 URL 中的路径添加到指定的根目录路径后。

  1. alias 配置:

与 root 不同,alias 指令允许我们在返回文件时,重写 URL 路径的部分或全部。这对于需要在返回文件时修改 URL 路径的情况非常有用。

例如,假设我们有以下配置:

location /static/ {
    alias /var/www/;
}

当收到的请求是 http://example.com/static/image.jpg 时,Nginx 会查找文件系统中的 /var/www/image.jpg 并返回该文件。

alias 指令会将匹配的 URL 路径替换为指定的文件系统路径。在上面的例子中,/static/ 被替换为 /var/www/,而 /image.jpg 部分保持不变。

这里需要注意的是,alias 指令需要确保文件路径的完整性,因为它会完全替换 URL 路径,而不会将请求 URL 的路径添加到指定的根目录路径后。

综上所述,root 用于直接映射 URL 路径到文件系统中的相对路径,而 alias 允许在返回文件时修改 URL 路径的部分或全部。选择使用哪种方式取决于具体的需求。

alias 后面必须要用 “/” 结束,否则会找不到文件,而 root 则对 ”/” 可有可无。

五、location基本用法和匹配规则优先级

location 指令用于根据请求的目录或文件名进行路由。优先级如下:

精确字符串匹配(=)
正则表达式(~, ~*)
最长字符串匹配(^~)
一般匹配
location = / {
[ configuration A ]
}

location / {
[ configuration B ]
}

location ~ .(gif|jpg|png)$ {
[ configuration C ]
}

location ^~ /images/ {
[ configuration D ]
}

补充:

nginx中location匹配规则与proxy_pass代理转发

一、location匹配规则

1.前缀匹配:不带符号

server {
    listen 80;
    server_name 192.168.100.123;
    location /abc {}  
}
#可以匹配到
http://192.168.100.123/abc
http://192.168.100.123/abc?name=zs
http://192.168.100.123/abc/
http://192.168.100.123/abcd

# 下列写法,当输入http://192.168.100.123时匹配到
location / {} 

2.精确匹配:符号=:表示精确匹配

server {
    listen 80;
    server_name 192.168.100.123;
    location = /abc {}  
}
#可以匹配到
http://192.168.100.123/abc
http://192.168.100.123/abc?name=zs
#不能匹配到
http://192.168.100.123/abc/
http://192.168.100.123/abcd

3.正则匹配:符号~~*:执行一个正则匹配,前者区分大小写,后者不区分

server {
    listen 80;
    server_name 192.168.100.123;
    location = ~* \.(jpg|png|gif)$  {}
}

4.符号^~:一旦匹配到,就不继续匹配

server {
    listen 80;
    server_name 192.168.100.123;
    # 匹配静态文件
    location ^~ /static/ {}
}

5.匹配优先级

1.精确匹配 =:如果匹配到,匹配结束,否则往下匹配;
2.前缀匹配(三种情况):
(1)如果匹配到,记录所有成功项,最长项如果有^~,停止匹配;
(2)如果匹配到,记录所有成功项,最长想如果没有^~,进行正则匹配;
(3)如果没有匹配到,进行正则匹配
3.正则匹配 ~与~*:从上往下匹配,以最后一个匹配项为匹配结果
4.没有匹配项,返回404

image.png

六、深入理解location中url结尾的反斜线

在 location 配置中,URL结尾的反斜线" / "很重要。如果没有以"/"结尾,那么Nginx会认为你配置的是一个具体的文件名;而如果以"/"结尾,Nginx会认为你配置的是一个目录。例如:

location /test {
 ...
}

location /test/ {
 ...
}

不带 / 当访问 www.nginx-test.com/test 时, Nginx 先找是否有 test 目录,如果有则找 test 目录下的 index.html ;如果没有 test 目录, nginx 则会找是否有 test 文件。
带 / 当访问 www.nginx-test.com/test 时, Nginx 先找是否有 test 目录,如果有则找 test 目录下的 index.html ,如果没有它也不会去找是否存在 test 文件。

另外,在 ngnix 中 location 进行的是模糊匹配

  • 没有“/”结尾时,location /abc/def 可以匹配 /abc/defghi 请求,也可以匹配 /abc/def/ghi 等
  • 而有“/”结尾时,location /abc/def/ 不能匹配 /abc/defghi 请求,只能匹配 /abc/def/anything 这样的请求

第四部分:Nginx进程结构

一、connection和request

在Nginx中,connection代表一个客户端到服务器的连接,而request则代表客户端通过该连接向服务器发送的HTTP请求。一个connection可以包含多个request。

二、对connection做限制的limit_conn模块

limit_conn模块可以限制每个key(如IP、server等)的并发连接数。例如,我们可以通过以下配置来限制每个IP的并发连接数不超过10:

http {
    limit_conn_zone $binary_remote_addr zone=perip:10m;
    
    server {
        location /download/ {
            limit_conn perip 10;
            ...
        }
    }
}

三、对request处理速率做限制的limit_req模块

limit_req模块可以限制处理请求的速率,以防止恶意攻击。例如,我们可以限制每秒处理不超过1个请求。

http {
    limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
    
    server {
        location /search/ {
            limit_req zone=one burst=5;
            ...
        }
    }
}

四、限制特定IP或网段访问的access模块

access模块可以控制哪些IP或者网络可以访问。例如,我们可以只允许特定IP访问:

location /admin/ {
    allow 192.168.1.0/24;
    deny all;
}

五、限制特定用户访问的auth_basic模块

auth_basic模块可以对访问进行基本的HTTP身份验证。

location /private/ {
    auth_basic "Admin Login";
    auth_basic_user_file conf/htpasswd;
}

六、基于HTTP响应状态码做权限控制的auth_request模块

auth_request模块允许基于另外一个请求的结果来授权客户端的请求。例如,当我们需要第三方认证服务器进行身份验证时。

location /private/ {
    auth_request /auth;
    ...
}

location = /auth {
    proxy_pass http://auth-server;
    ...
}

### 1. rewrite模块中的`return`指令
在Nginx的rewrite模块中,`return`指令可以用于控制页面跳转或者错误处理。其一般的使用格式如下:

```nginx
location /oldpath {
    return 301 /newpath;
}

在以上的代码示例中,如果用户尝试访问/oldpath,他们将会被301重定向到/newpath

2. rewrite模块中的rewrite指令

rewrite指令用于根据正则表达式对URL进行重写。其一般的使用格式如下:

location / {
    rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 last;
}

在以上的代码示例中,所有匹配到的符合正则表达式的URL将会被重写替换。

3. returnrewrite指令执行顺序

return指令和rewrite指令的执行顺序基于它们在Nginx配置文件中的顺序。如果return指令在rewrite指令之前,那么return指令将优先执行。

4. rewrite模块中的if指令

if指令可以基于给定条件决定是否执行某个指令。其一般的使用格式如下:

if ($http_user_agent ~ MSIE) {
    return 301 https://www.microsoft.com;
}

在以上的代码示例中,如果用户的浏览器是Internet Explorer,他们将会被301重定向到Microsoft官方网站。

5. autoindex模块用法

autoindex模块可以创建一个简单的目录索引页面。其一般的使用格式如下:

location / {
    autoindex on;
}

在以上的代码示例中,如果在一个目录下没有找到index文件,Nginx将会展示该目录下的文件列表。

1. Nginx变量的分类

Nginx变量可以大致分为以下几类:

  • 配置变量:这类变量由nginx配置文件中的指令定义,例如$http_$host等。
  • 内部变量:nginx内部使用的变量,如$uri$args等。
  • 外部变量:通过nginx扩展模块引入的变量。

2. TCP连接相关变量

一些与TCP连接相关的变量包括:

  • $remote_addr:客户端的IP地址;
  • $remote_port:客户端的端口;
  • $server_addr:服务器的IP地址;
  • $server_port:服务器的端口。

例如:

log_format tcpinfo '$remote_addr:$remote_port -> $server_addr:$server_port';

以上代码定义了一个log格式,包含了TCP连接各项参数。

参考:
nginx变量

3. 发送HTTP请求相关变量

当发送HTTP请求时,可以使用如下变量:

  • $request_method:请求方法(GET、POST等);
  • $request_uri:请求的URI;
  • $http_user_agent:用户代理。

例如:

if ($request_method = POST ) {
    return 405;
}

以上代码中,如果请求方法是POST,服务器将返回405方法不被允许。

4. 处理HTTP请求相关变量

处理HTTP请求时,常用的变量有:

  • $status:响应状态码;
  • $body_bytes_sent:响应的字节数;
  • $request_time:请求处理时间。

例如:

log_format myformat '$status, $body_bytes_sent, $request_time';

以上代码定义了一个log格式,记录了处理HTTP请求的相关信息。

第五部分:反向代理

1. 反向代理基础原理

反向代理是代理服务器接收互联网上的连接请求,然后将请求转发到内部网络上的服务器,并将从服务器上得到的结果返回给互联网上请求连接的客户端,此时代理服务器对外就表现为一个代理人。

2. 动静分离

通过反向代理,Nginx可以实现动静分离,即将动态请求转发给动态应用服务器,而直接处理静态请求。这样能够减轻应用服务器的压力,提高服务效率。

3. 使用Nginx作为反向代理时支持的协议

Nginx作为反向代理时支持HTTP、HTTPS、SMTP、POP3以及IMAP协议。

4. 用于定义上游服务的upstream模块

Nginx使用upstream模块定义后端服务器群组。例如:

upstream backend {
    server backend1.example.com;
    server backend2.example.com;
}

5. upstream模块指令用法详解

以下是一些常见的upstream指令:

  • server:定义后端服务器的地址和其他参数。
  • ip_hash:这个指令让请求按来源IP的hash结果进行负载均衡,这样每个用户都会连接到同一台后端服务器,有利于session的保持。

6. 配置一个可用的上游应用服务器

以下是一个简单的例子:

upstream app_server {
    server localhost:8080;
}

这行代码定义了一个名为app_server的后端应用服务器服务器群组,其中只包含一个服务器,即监听本地8080端口的服务器。

7. 配置nginx反向代理实例

以下是一个简单的反向代理配置:

location / {
    proxy_pass http://app_server;
}

所有匹配该位置的请求都会被转发到先前定义好的app_server上游服务器群组。

8.proxy_pass指令用法常见误区

如果proxy_pass指令的参数是一个复杂值(比如变量),那么在该指令的作用范围内,location不能包含正则表达式,且必须是精确匹配。

1. 代理场景下Nginx接收用户请求包体的处理方式

在处理POST请求时,Nginx需要接收到完整的请求包体后,才能将请求转发至上游服务器。这个过程可通过proxy_request_buffering 指令控制。例如:

location / {
    proxy_request_buffering on;
    proxy_pass http://app_server;
}

以上配置使得Nginx在转发请求之前,会先接收并缓存完整的用户请求包体。

2. 代理场景下Nginx如何更改发往上游的用户请求

Nginx可以通过修改请求头来改变发往上游的用户请求。比如,添加一个自定义的头字段X-Real-IP,记录下用户的真实IP地址。示例代码如下:

location / {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_pass http://app_server;
}

在这个例子中,每个发往app_server的请求都会带有X-Real-IP字段,值为用户的真实IP。

3. 代理场景下Nginx与上游服务建立连接细节

Nginx和上游服务的连接默认是短连接,即每次请求结束后都会断开连接。为了提高效率,可以通过设置keepalive指令使得这些连接保持活动状态。例如:

upstream app_server {
    server localhost:8080;
    keepalive 64;
}

上面的配置使得与app_server的连接在完成请求后,将会保持活跃而不会马上断开。

PS: 使用nginx做动态域名解析

Nginx进行反向代理的时候会进行域名解析,把域名解析为具体IP后缓存在本地,如果域名对应的IP发生了改变,则会导致Nginx代理失效,下面使用Nginx的resolver指令来实现域名动态解析。

基于自定义DNS服务器动态解析

default.conf配置

server {

    listen       80;

    root         /usr/share/nginx/html/;

    resolver 192.168.137.110  valid=5s;

    set $proxy_url huzhihui.local;

    include /etc/nginx/default.d/*.conf;

    location / {

      index index.html index.htm;

      try_files $uri $uri/ /index.html;

      client_max_body_size  100m;

      add_header tenantId $arg_tenantId;

      add_header appId $arg_appId;

    }

    location /api/ {

      proxy_set_header Host $http_host;

      proxy_set_header X-Real-IP $remote_addr;

      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

      proxy_set_header X-Forwarded-Proto $scheme;

      rewrite /api/(.*) /$1 break;

      proxy_pass http://$proxy_url:8070;

    }

}

主要配置点
resolver:配置DNS服务器,和解析地址的有效期valid,

set:用来配合resolver做域名的IP地址解析

rewrite:对访问路径进行修改

proxy_pass:实际跳转到的代理服务,不要带路径参数,因为上面已经用rewrite重写了

基于K8S的CoreDns动态域名解析

default.conf

server {

    listen       80;

    root         /usr/share/nginx/html/;

    resolver kube-dns.kube-system.svc.cluster.local  valid=10s;

    set $a_part_host a-part-http-service.huzhihui.svc.cluster.local;

    include /etc/nginx/default.d/*.conf;

    location / {

      index index.html index.htm;

      try_files $uri $uri/ /index.html;

      client_max_body_size  100m;

      add_header tenantId $arg_tenantId;

      add_header appId $arg_appId;

    }

    location /api/ {

      proxy_set_header Host $http_host;

      proxy_set_header X-Real-IP $remote_addr;

      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

      proxy_set_header X-Forwarded-Proto $scheme;

      proxy_pass http://127.0.0.1:5031/;

    }

      location /a-part/ {

        client_max_body_size  100m;

      proxy_set_header Host $http_host;

      proxy_set_header X-Real-IP $remote_addr;

      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

      proxy_set_header X-Forwarded-Proto $scheme;

      rewrite /a-part/(.*) /api/$1 break;

      proxy_pass http://$a_part_host;

    }

    location ~ .*\.(html)$ {

         #html disabled cache

         add_header Cache-Control no-store;

     }

    error_page 404 /404.html;

        location = /40x.html {

    }

    error_page 500 502 503 504 /50x.html;

        location = /50x.html {

    }

}

主要配置点
kube-dns.kube-system.svc.cluster.local:这个域名是K8S DNS的域名
a-part-http-service.huzhihui.svc.cluster.local:a-part-http-service是K8S定义的svc名称,huzhihui是我定义的namespaces,
做完上面的配置,svc重启后ip改变也不会导致反向代理失效了。

第六部分:场景实践-负载均衡

1. 负载均衡基础

负载均衡是在多台服务器间分配工作负载的过程。依靠负载均衡,可以扩展系统吞吐量,提高资源使用率,避免单点故障,保证系统可用性。

2. 配置实现Nginx对上游服务负载均衡

Nginx默认的负载均衡方式是轮询。相应配置为:

upstream backend {
    server backend1.example.com;
    server backend2.example.com;
}

在该配置中,Nginx会将请求交替地分发给backend1和backend2。

3. 负载均衡算法-哈希算法

哈希算法可以根据某个固定值(比如客户端IP地址)来进行哈希计算,从而决定请求发送到哪个服务器。例如:

upstream backend {
    hash $remote_addr;
    server backend1.example.com;
    server backend2.example.com;
}

4. 负载均衡算法-ip_hash算法

ip_hash可以确保来自同一IP的客户端请求总是被发送到相同的服务器。例如:

upstream backend {
    ip_hash;
    server backend1.example.com;
    server backend2.example.com;
}
好的,接下来我将会为你编写关于“场景实践-负载均衡”的演讲稿,主要涉及Nginx在负载均衡方面的应用和相关算法。

## 第六部分:场景实践-负载均衡

### 1. 负载均衡基础
负载均衡是通过分配系统负载(事务、工作负载等)到多个计算资源(如服务器、网络链接、硬盘驱动器或其他资源),从而最大化吞吐量、最小化响应时间、同时避免过度使用某一资源。

### 2. 配置实现Nginx对上游服务负载均衡
Nginx默认的负载均衡策略是轮询。例如:

```nginx
upstream backend {
    server backend1.example.com;
    server backend2.example.com;
}
location / {
    proxy_pass http://backend;
}

3. 负载均衡算法-hash算法

Hash负载均衡算法通过特定的hash函数将请求分配给特定的后端服务器,可以实现会话保持。示例代码如下:

upstream backend {
    hash $request_uri consistent;
    server backend1.example.com;
    server backend2.example.com;
}

4. 负载均衡算法-ip_hash算法

ip_hash算法将同一IP地址的用户请求分配到同一后端服务器,适用于需要保持用户会话或者用户登录状态的应用。示例代码如下:

upstream backend {
    ip_hash;
    server backend1.example.com;
    server backend2.example.com;
}

5. 负载均衡算法-最少连接数算法

最少连接数算法会将新的请求分配到当前连接数最少的后端服务器。示例代码如下:

upstream backend {
    least_conn;
    server backend1.example.com;
    server backend2.example.com;
}

6. 负载均衡场景下Nginx针对上游服务器返回异常时的容错机制

当一个上游服务器不能正常处理请求时,Nginx不会立即将其标记为失效,而是会在后续的请求中尝试再次向这个服务器发送请求。如果经过多次尝试仍然无法正常响应,那么Nginx会将其临时标记为失效,对其他请求不再转发。

例如,配置如下:

upstream backend {
    server backend1.example.com max_fails=3 fail_timeout=30s;
    server backend2.example.com;
}

以上配置表示,如果backend1.example.com在30秒内连续失败3次,那么Nginx会暂时不向其转发请求。
好的,以下是第七部分【缓存】的演讲稿内容:

# 七、Nginx缓存应用案例

## 1. 缓存基础

Nginx的缓存能力主要来自其反向代理和FastCGI代理功能。通过缓存上游服务器响应的内容,Nginx可以快速地为客户端请求提供服务,从而减少了对上游服务器的压力。

## 2. 缓存相关指令用法

以下是一些在配置Nginx缓存过程中会用到的主要指令:

- proxy_cache_path: 定义存储缓存的文件路径以及缓存的其他参数。
- proxy_cache: 启用或禁用缓存。
- proxy_cache_valid: 设置响应的缓存时间。
- proxy_no_cache: 定义不进行缓存的情况。

## 3. 缓存用法配置示例

以下是一个简单的Nginx缓存配置示例:

```nginx
http {
    proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=my_cache:10m;
    server {
        location / {
            proxy_cache my_cache;
            proxy_pass http://my_upstream;
            proxy_cache_valid 200 302 60m;
            proxy_cache_valid 404 1m;
        }
    }
}

上述内容中,我们定义了一个名为my_cache的缓存,缓存的内容存储在/data/nginx/cache目录下,缓存键值对的内存区为10MB。对于200和302状态的响应,缓存有效期为60分钟,对于404状态的响应,缓存有效期为1分钟。

4. 配置Nginx不缓存上游服务特定内容

有时候,我们需要特定的响应不被缓存,这个时候就可以使用proxy_no_cache指令:

location / {
    proxy_cache my_cache;
    proxy_no_cache $http_cookie $arg_nocache;
    proxy_pass http://my_upstream;
}

这样如果请求中含有cookie或者请求参数中含有nocache参数,那么Nginx就不会缓存该次请求的响应。

5. 缓存失效降低上游压力机制一-合并源请求

当多个并发请求针对同一个资源,并且这个资源的缓存刚好在那一刻失效,那么Nginx默认的机制是只向后端服务器发送一个请求,其他的请求等待这个请求返回结果,并利用这个结果进行缓存。这就是所谓的合并源请求,可以减少向后端服务器发送的请求数量。

6. 缓存失效降低上游压力机制二-启用陈旧缓存

我们还可以通过配置proxy_cache_use_stale指令来在缓存失效、错误或者超时的情况下,允许Nginx继续使用旧的缓存内容来响应请求,这样也能在一定程度上减轻上游服务器压力:

location / {
    proxy_cache my_cache;
    proxy_cache_use_stale updating error timeout invalid_header http_500 http_502 http_503 http_504;
    proxy_pass http://my_upstream;
}

浏览器本地缓存静态数据

1)使用Firefox浏览器查看缓存

以Firefox浏览器为例,在Firefox地址栏内输入about:cache将显示Firefox浏览器的缓存信息,如图所示,点击List Cache Entries可以查看详细信息。


image.png

2)清空firefox本地缓存数据,如图所示。


image.png

3)改Nginx配置文件,定义对静态页面的缓存时间

[root@proxy ~]# vim /usr/local/nginx/conf/nginx.confserver {        listen       80;        server_name  localhost;        location / {            root   html;            index  index.html index.htm;        }location ~* \.(jpg|jpeg|gif|png|css|js|ico|xml)$ {expires        30d;            //定义客户端缓存时间为30天}}[root@proxy ~]# cp /usr/share/backgrounds/day.jpg /usr/local/nginx/html[root@proxy ~]# /usr/local/nginx/sbin/nginx -s reload#请先确保nginx是启动状态,否则运行该命令会报错,报错信息如下:#[error] open() "/usr/local/nginx/logs/nginx.pid" failed (2: No such file or directory)

4)优化后,使用Firefox浏览器访问图片,再次查看缓存信息

[root@client ~]# firefox http://192.168.4.5/day.jpg

在firefox地址栏内输入about:cache,查看本地缓存数据,查看是否有图片以及过期时间是否正确。

八、深入Nginx架构

1. Nginx高可用基础

在很多场景下,我们需要确保服务的高可用性,也就是说,即使某个节点出现故障,服务也能够正常提供。在Nginx中,我们一般通过配置多个节点并结合负载均衡和故障转移技术来实现高可用。

2. 虚拟路由冗余协议VRRP原理

虚拟路由冗余协议(VRRP)是一种用于实现网络路径冗余的互联网协议,以确保网络节点通信的高可用性。它可以创建一个虚拟路由器,该路由器包含多个物理路由器。如果主路由器发生故障,备份路由器将接管,保证网络通信不会中断。

3. KeepAlived软件架构

KeepAlived是Linux下一个健康检查和故障恢复的软件。它使用VRRP协议来实现负载均衡器的冗余,并在负载均衡器节点之间管理和切换虚拟IP。

4. 使用KeepAlived配置实现虚IP在多服务器节点漂移

下面是一个基本的KeepAlived配置示例,显示了如何在两个服务器节点之间漂移虚拟IP:

global_defs {
    router_id LVS_DEVEL
}

vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 100
    advert_int 1
    nopreempt
    virtual_ipaddress {
        192.168.1.10
    }
}

在另一个节点的配置中,我们把state改为BACKUP,priority设置为较低的值,比如50。这样,当MASTER节点发生故障时,BACKUP节点就会接管虚拟IP。

5. KeepAlived Nginx高可用原理

在实现Nginx的高可用时,我们可以在每个节点上运行一个Nginx服务和一个KeepAlived服务。KeepAlived会监控本节点的Nginx服务状态,只有在Nginx服务正常运行时,KeepAlived才会将本节点设置为MASTER状态,接管虚拟IP。

如果MASTER节点的Nginx服务发生故障,KeepAlived会立刻将虚拟IP切换到其它的BACKUP节点。用户的请求会被自动转发到新的MASTER节点的Nginx服务上,保证了服务的高可用。
Nginx+keepalived 实现高可用,防盗链及动静分离配置,写得太好了!

九、Nginx性能优化

1. 提升Nginx利用CPU的效率

Nginx可以通过调整各种参数来提高对CPU的利用效率。比如,我们可以增加worker_processes的数量(通常设置为等于CPU核心数),使得Nginx能够在多个CPU核心上并行处理请求。

此外,worker_connections 参数也十分重要,它决定了每个worker process可以同时打开的最大连接数。在系统允许的范围内适当提高这个参数,可以进一步提升Nginx处理请求的能力。

2. TCP三次握手和四次挥手

TCP三次握手和四次挥手是TCP协议中建立连接和断开连接的过程。

  • 三次握手:在建立TCP连接时,客户端和服务器需要进行三次握手。首先,客户端发送一个SYN包,请求建立连接;然后,服务器回应一个SYN+ACK包,表明同意建立连接;最后,客户端再回应一个ACK包,确认已经准备好进行数据传输。
  • 四次挥手:在断开TCP连接时,需要进行四次挥手。首先,任一方(以客户端为例)发送一个FIN包,请求关闭连接;然后,服务器回应一个ACK包,表示已经知晓请求;在完成所有数据传输后,服务器发送一个FIN包,请求关闭连接;最后,客户端回应一个ACK包,服务器收到后关闭连接。

3. TCP建立连接优化

由于TCP必须通过三次握手来建立连接,如果客户端频繁地建立和关闭连接,会导致大量的网络延迟和资源浪费。Nginx可以通过keepalive_timeout 参数来启用持久连接,保持连接在一段时间内不关闭,这样可以避免频繁的三次握手。

例如,下面的配置会使得Nginx保持连接60秒不关闭:

http {
    keepalive_timeout 60s;
}

4. 启用TCP的Fast Open功能

TCP Fast Open (TFO) 是一项TCP协议的优化技术,它允许数据在建立连接的握手阶段就开始发送,从而减少了网络延迟。在Linux系统中,我们可以通过修改系统参数来启用TFO:

echo 3 > /proc/sys/net/ipv4/tcp_fastopen

然后,在Nginx配置中启用TFO:

server {
    listen 80 fastopen=5;
}

PS:
一个可以在在线编辑生成nginx配置的网站

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容