一点一滴成长

导航

反向代理服务

1、域名和DNS

  向阿里或腾讯申请域名,然后为域名设置一个权威DNS服务器,比如在腾讯云注册的域名,那么可以选择在腾讯DNS服务器上存储该域名的解析信息,那么腾讯云DNS就成为了该域名的权威DNS服务器。当有人通过 114.114.114.114 查询你的域名时,114DNS服务会先向根服务器查询顶级域名服务器地址,查询到该域名所属的顶级域名服务后,再向顶级域名服务器查询你的域名的 NS 记录(域名所属的权威服务器),查询到域名所属的权威服务器后,最后向你的权威 DNS 服务器查询具体解析记录,然后114会将该记录信息缓存一段时间,下次其他用户查询时直接返回缓存结果。

2、nginx反向代理

  目前Nginx和HAProxy都支持七层和四层转发,Nginx对于七层的处理功能更丰富,比如正则表达式强大、支持复杂URL路由。而HAProxy则在会话保持(Cookie)方面更精细,而且性能比Nginx更高(延迟低、并发高),同时支持MySQL/Redis长连接(Nginx长连接支持弱,如MySQL连接池容易超时)。

 1) nginx负载均衡

  nginx除了提供URL路由功能外,还提供负载均衡功能,常见的负载均衡策略有轮询(请求被顺序分配,nginx默认策略)、加权轮询(根据权重分配请求,权重越高被分配到的请求越多,可以根据后端服务性能来设置权重)、最少连接(优先分配请求到当前活跃连接最少的后端,适合长连接通信)、IP哈希(根据客户IP地址计算哈希值,将同一IP的请求固定分配给同一台后端服务)、通用哈希​(允许自定义哈希键,将相同键的请求定向到同一服务器,如将同一URL的请求固定到某台服务上)、随机(随机选择一台后端服务)、最短响应时间(按后端服务的响应时间来分配请求,属于第三方策略)。

 2) nginx高可用

  企业架构经常采用的模式是:公网入口→nginx反向代理服务(https)→内网服务(http),nginx的高可用通过keepalived来提供,内网集群服务的高可用由nginx的“健康监测”来实现:Nginx 会按照配置的频率向后端服务发送探测请求,比如一个 HTTP HEAD 请求(大部分Web服务器能够自动处理HEAD请求),如果某台后端服务器连续几次探测都失败,即无响应,标注该服务为非健康状态,新的请求不会被转发到该服务上,当健康检查探测到服务恢复健康后,会将其重新加入到可用的后端服务列表中。

  新增nginx后端服务的话,需要将其加入到nginx后端服务列表,传统的方式是手动修改nginx配置,然后使用nginx -s reload命令来重载配置(reload是重载配置而非重启服务,它允许在不停止服务的情况下应用新的配置)。推荐的方式是使用nginx插件nginx-upsync-module​ + 注册中心ETCD/Consul/ZooKeeper 来动态管理后端实例列表,省去手动修改 Nginx配置:新的后端服务启动后,自动向服务注册中心注册自己的地址和相关信息,nginx从注册中心动态获取(如每隔500ms发起一个请求)可用的服务实例列表(通过配置告诉 Nginx从 ETCD/Consul 的哪个路径拉取列表,拉取到的列表会存到本地,防止注册中心挂了)。

  一个完整的高可用架构通常是多层级的组合:

   111

 3) nginx连接复用

  nginx与后端应用服务之间推荐使用长连接来进行连接的复用:客户A发送请求,nginx与后端服务建立连接,数据传输结束后这个后端连接不会进行关闭,nginx将其放至连接池中,客户B发送请求的时候,nginx发现连接池中有空闲连接,然后就可以直接使用该连接与后端服务进行通信,通信结束后再将其放回连接池中。nginx连接池实际上是可以称为空闲连接池:请求到来的时候发现当连接池中无可用连接(连接都不是空闲的,都在使用)的时候会直接创建新连接,如果当前连接数没有超过worker_connections(默认为512或1024)的话。当连接使用完毕后如果连接池中连接大于等于设置的keepalive值的话,就直接关闭连接,小于的话就将连接放入连接池,该连接成为空闲连接。

  nginx开启连接池复用连接的配置如下所示,其中有五个关键设置:①、定义上游应用服务器组 ②、设置keepalive连接池大小(即最大空闲连接数)③、启用 HTTP/1.1 长连接 ④、清空客户端发来的Connection头,避免将Connection: close、Connection: keep-alive透传给后端服务来扰乱nginx与后端服务的长连接 ⑤、配置超时等其他常见配置。

http{
    # ================= 客户端侧 keepalive =================
    # 客户端与 Nginx 之间的长连接:即客户端与nginx之间也可以进行连接的复用
    keepalive_timeout 65s;          # 空闲超时:超过这个时间客户端没有发送请求的话nginx主动关闭与客户端的长连接(默认75秒),Tomcat的话为connectionTimeout(默认20秒)
    keepalive_requests 1000;        # 单连接最大请求数:该连接上接受的请求超过这个数的话连接会被nginx关闭
    keepalive_time 1h;              # 连接总存活时间(Nginx 1.21 + ),与客户端的连接总时长超过这个时间就关闭连接

    # ================= 后端侧 keepalive =================
    upstream backend_pool {
        # 上游服务器组
        server 10.0.0.1:8080;
        server 10.0.0.2:8080;
        server 10.0.0.3:8080;

        # 【核心】每个 worker 的最大空闲连接数:总空闲连接数 = worker_processes × keepalive 值,如worker_processes为4,keepalive为32的话,最大空闲连接数为4 × 32 = 128
        # 建议值:CPU 核心数 × 4 ~CPU 核心数 × 16
        keepalive 32;

        # 连接空闲超时:超过这个时间nginx主动关闭与后端的长连接
        keepalive_timeout 60s;

        # 【可选】单连接最大请求数(Nginx 1.21 + ):该连接上接受的请求超过这个数的话连接会被nginx关闭
        keepalive_requests 1000;
    }

    server {
        listen 80;
        server_name api.example.com;

        location / api / {
            proxy_pass http ://backend_pool;

            # 【必须】启用 HTTP / 1.1
            proxy_http_version 1.1;

            # 【必须】清空 Connection 头
            proxy_set_header Connection "";

            # 【推荐】标准代理头
            proxy_set_header Host $host;
            proxy_set_header X - Real - IP $remote_addr;
            proxy_set_header X - Forwarded - For $proxy_add_x_forwarded_for;

            # 【重要】超时配置(避免连接占用过久)
            proxy_connect_timeout 5s;
            proxy_send_timeout 10s;
            proxy_read_timeout 30s;

            # 【推荐】缓冲配置
            proxy_buffering on;
            proxy_buffer_size 4k;
            proxy_buffers 8 4k;
        }
    }
}

   nginx应该关注的几个超时:①、假设黑客以1字节/每秒的速度发送请求,那么其发送多个请求的话连接就会被占满,防护手段是设置请求头/体的发送超时,如client_header_timeout 15s;表示15秒内必须发完请求头,client_body_timeout 30s;表示30秒内必须发完请求体。②、nginx连接后端服务的超时时间通过proxy_connect_timeout来配置。③、nginx与后端服务之间建议不是永久连接,而是设置keepalive_timeout空闲连接超时,当一段时间无客户请求的话关闭连接。Nginx配置的keepalive_timeout空闲超时时间应该小于后端服务配置的空闲超时时间(比如Tomcat通过keepAliveTimeout(旧版本为connectionTimeout)控制 Tomcat 与客户端(此处客户端是 Nginx)的空闲超时),否则可能会出现后端服务提前把连接关闭,nginx还复用已关闭的连接的出错情况。④、为了应对SQL查询死锁,nginx和后端服务的连接被永久占用的情况(比如一直有客户请求,但后端SQL查询都是死锁),nginx应该设置读取后端服务数据超时时间proxy_read_timeout,超过这个时间后端无数据返回的话关闭连接,proxy_read_timeout超时应该设置的比后端服务的keepAliveTimeout空闲超时要小,避免失去对SQL死锁处理的主动控制权。可以根据请求类型配置不同的proxy_read_timeout值,比如普通数据库查询设置5-10秒,复杂数据库查询30秒。⑤、如果担心客户端处理响应慢的话,可以设置send_timeout,当发送缓冲区已满的话,连接关闭。

3、URL路由

  URL路由就是指将用户请求的URL映射到指定的处理程序,在 Spring 中,路由可以通过将注解(如@RequestMapping、@GetMapping、@PostMapping等)定义在控制器(Controller)的方法上实现,如下所示。

@RestController
public class UserController {
    // 匹配 GET /users 请求,对应"查询所有用户"逻辑(静态路由:URL 路径固定)
    @GetMapping("/users")
        public List<User> getAllUsers() {
        // 业务逻辑...
    }

    // 匹配 POST /users 请求,对应"创建用户"逻辑
    @PostMapping("/users")
        public User createUser(@RequestBody User user) {
        // 业务逻辑...
    }

    // 匹配 GET /users/{id} 请求,对应"查询单个用户"逻辑(动态路由:id为动态的)
    @GetMapping("/users/{id}")
        public User getUserById(@PathVariable Long id) {
        // 业务逻辑...
    }
}

4、使用Nginx对URL进行路由转发  

  1、使用location匹配指定的URL路径,进行不同的路由:

http{
    upstream backend1 { server 192.168.1.10:80; }
    upstream backend2 { server 192.168.1.20:80; }

    server {
        location /api1/ {     # 匹配以 /api1/ 开头的路径
            proxy_pass http ://backend1;  # 转发到backend1
        }
        location /api2/ {     # 匹配以 /api2/ 开头的路径
            proxy_pass http ://backend2;  # 转发到backend2
        }
    }
}

  通过location来定义不同请求的处理规则:

server{
    listen 80;
    server_name example.com;

    # 1. 静态文件请求由Nginx直接处理:任何请求路径,只要以jpg、png、css等指定的扩展名结尾,就由nginx响应,如www.test.com / images / photo.jpg
    location ~*\.(jpg | jpeg | png | gif | ico | css | js | html | txt | pdf)$ {
        root / var / www / static; # 如请求 / images / photo.jpg的话,实际查找路径为 / var / www / static / images / photo.jpg
        expires 30d;  # 缓存30天
        access_log off;  # 可选:关闭日志减少IO
    }

    # 静态文件由Nginx直接处理:只匹配 / static / 路径下以jpg、png、css等指定的扩展名结尾的请求
        # location ~*^/ static / . + \.(jpg | jpeg | png | gif | ico | css | js | html | txt | pdf)$ {
        # root / var / www;
        # expires 30d;
        # access_log off;
    # }

    # 静态文件由Nginx直接处理:只匹配 / static / 路径下的请求
    # location / static / {
        # root / var / www;
        # expires 30d;
        # access_log off;
    #}

    # 2. 接口请求转发给后端应用:只匹配/ api /路径下的请求,如www.test.com / api、www.test.com / api / users
    location / api / {
        proxy_pass http ://backend-server:8080;
        proxy_set_header Host $host;
        proxy_set_header X - Real - IP $remote_addr;
    }

    # 3. 其它请求处理规则:匹配www.test.com /、www.test.com / test、www.test.com / user / profile等请求
    location / {
        # 可以是静态文件,也可以是转发
        root / var / www / html;
        try_files $uri $uri / @backend;
    }

    # 4. 后备处理规则(比如当上面第3个location处理静态文件时该文件不存在)
    location @backend {
        proxy_pass http ://backend-server:8080;
    }
}

 

# 静态资源准发给OSS:OSS响应给nginx后,再由nginx响应给客户端
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
    proxy_pass https://your-oss-bucket.oss-cn-hangzhou.aliyuncs.com;
    add_header Cache-Control "public, immutable, max-age=31536000";
    expires 1y;
}

 2、通过参数值,动态决策路由:

location /{ #匹配所有请求:/表示最宽泛的路径匹配
        if ($arg_type = "app") {    # 检查参数type = app
                proxy_pass http ://app_server; #转发到 app_server
        }
        if ($arg_type = "game") {   # 检查参数type = game
                proxy_pass http ://game_server; #转发到 game_server
        }
        proxy_pass http ://default_backend;   # 默认路由
    }

  3、检查文件是否存在:

        location /{
            try_files $uri /index.html;  #将所有非静态资源请求重定向到入口文件:try_files用于按顺序检查文件是否存在,并返回第一个存在的文件,所以当访问的URL文件不存在的时候,返回index.html
        }
        location /{
            try_files $uri $uri/ @not_found;  #首先尝试访问 $uri,比如/static/file,如文件不存在则尝试访问/static/file/(将URI作为目录),若前两者都不存在,就跳转到名为 @not_found 的命名location
        }
        location @not_found{ #命名location(用 @ 前缀标识,不能被客户端直接访问,只能被 Nginx 内部调用)
            return 404 /custom_404.html; #返回404状态码以及/custom_404.html这个页面
        }
location / {
    # 先尝试直接访问文件,再尝试作为目录,最后返回404
    try_files $uri $uri / = 404;
}

 4、使用正则表达式(主要应用在location、rewrite指令等场景)

  将指定类型的URL请求转发到指定服务器:

location ~ ^/user/(\d+)$ { #匹配/user/开头,数字结尾的URL,比如/user/123:~表示区分大小写的正则匹配模式。^匹配字符串开头(只匹配以/user/开头的),(\d+)匹配一个或多个数字,$匹配字符串结尾(防止匹配/user/123abc),
    proxy_pass http://user-service:8080; #将匹配到的请求转发到指定的服务
    proxy_set_header Host $host; #在转发请求时,将 HTTP 头中的 Host 字段设置为客户端原始请求的 Host 值
}

  将指定的请求重定向&将指定的URL请求修改为新的URL请求

        server{
            rewrite ^/old-path$ /new-path permanent;  #当有请求访问/old-path时,将其重定向到/new-path:^/old-path$是一个正则表达式,表示匹配路径为/old-path的请求(^表示开头,$表示结尾,确保不会匹配类似/old-path/xxx 的路径)。permanent 表示这是 301 永久重定向,有利于搜索引擎权重的转移,避免因路径变更导致的流量损失
            rewrite ^/user/(\d+)$ /profile?id=$1;  #当请求以/user/开头,以数字结尾的时候,比如/user/123,URL会被重写成/profile?id=123: ^/user/(\d+)$是一个正则表达式,其中^/user/匹配以/user/开头的路径,(\d+)匹配一个或多个数字,$表示路径结束,确保不会匹配更长的路径(如/user/123会被匹配,/user/123abc不会被匹配), $1表示前面捕获到的数字。这里没有指定重定向类型(如 permanent 或 redirect),所以是内部重写(客户端不会感知到 URL 变化,地址栏显示的仍是原始 URL)
        }

  将静态文件与动态内容分开处理,并且由Nginx 直接处理静态资源请求:

location ~* \.(jpg|jpeg|png|gif|css|js)$ { #~*表示不区分大小写(.jpg和.JPG都会被匹配),\.(jpg|jpeg|png|gif|css|js)匹配以这些后缀结尾的文件,$ 确保匹配的是文件后缀(而非文件名中间包含这些字符的文件)
    root /var/www/static; #静态文件在服务器上的实际存储路径,例如,当请求/images/logo.png 时,Nginx 会去服务器的/var/www/static/images/logo.png路径寻找文件,然后直接返回给用户
    expires 30d; #设置 HTTP 响应头中的缓存过期时间为 30 天,浏览器会根据这个设置缓存这些静态资源,在 30 天内再次访问时不会重新请求服务器
}

  请求过滤,拦截不符合规则(恶意URL、爬虫)的请求。如下所示,为了防止路径遍历攻击,当URI中包含../的时候(比如../../etc/passwd 试图访问系统用户文件),返回403禁止访问 :

if ($request_uri ~* \.\../ ) { #$request_uri 是 Nginx 的内置变量,表示客户端请求的完整 URI,\.\../ 是匹配模式,用于检测 URI 中是否包含 ../ 字符串
    return 403;
}

  实现灰度发布:根据http请求头中的特定标识,如X-Env: canary,将符合条件的流量路由到新版本(金丝雀)服务,其他流量仍走旧版本服务。

 5、使用add_header指令向HTTP响应中添加自定义响应头,可用于缓存控制、安全控制、跨域(CORS)、调试等。

  配置安全头:

server{
    listen 80;
    server_name example.com;

    location / {
        # 安全相关头部
        add_header X - Content - Type - Options "nosniff" always; # 设置X - Content - Type - Options响应头的值为"nosniff",always表示即使响应状态码是错误码(如4xx、5xx)也强制添加此头
        add_header X - Frame - Options "SAMEORIGIN" always;
        add_header X - XSS - Protection "1; mode=block" always;
        add_header Referrer - Policy "strict-origin-when-cross-origin" always;

        # 现代安全策略
        add_header Content - Security - Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';" always;
    }
}

  配置缓存策略

# 静态资源 - 长期缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
    root /var/www/static;
    expires 1y;
    
    # 缓存控制头
    add_header Cache-Control "public, immutable, max-age=31536000" always;
    add_header Pragma "public" always;
    
    # 调试:显示资源类型
    add_header X-Static-Resource "true" always;
}

# API响应 - 不缓存
location /api/ {
    proxy_pass http://backend:8080;
    
    # 禁止缓存API响应
    add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate" always;
    add_header Pragma "no-cache" always;
    add_header Expires "0" always;
}

5、静态资源和动态资源  

 ①、版本化资源

  对于静态html、css、js、png这种静态资源,可以由nginx提供下载,并且配置immutable缓存策略,如下所示, max-age设置资源的缓存有效期为1年,immutable表示资源在其缓存有效期内不会发生任何更改,以指示浏览器资源在缓存有效期内的话直接使用其缓存,不用再发送请求,public表示资源可以被任何缓存(包括浏览器、CDN、代理服务器等)缓存。expires和max-age都是用来定义资源在Cookie的有效期,现代浏览器会优先使用`max-age`,这里使用expires是为了兼容老旧浏览器。

location ~*\.(js | css | png | jpg | jpeg | gif | ico | svg)$ {
    add_header Cache - Control "public, immutable, max-age=31536000";
    expires 1y;
}

  指示缓存永久有效:

location ~* \.[a-f0-9]{8,}\.(js|css)$ {
    add_header Cache-Control "public, immutable";
    expires max;
}

  指示缓存时间为2小时, must-revalidate表示资源在缓存有效期内的话直接使用缓存,缓存过期的话,必须向源服务器验证。与immutable不同的是,must-revalidate指示严格遵循过期后必须验证(某些配置可能允许使用过期缓存),而且immutable的作用对象仅针对浏览器缓存,must-revalidate则针对所有缓存:

location ~*\.(js | css)$ {
    add_header Cache - Control "public, must-revalidate";
    expires 2h;
}

  nginx上的这些静态文件,应该使用构建工具(Webpack/Vite)生成带哈希的文件名(如main.a1b2c3d4.css),当文件内容发生变化时,文件名随之改变——当静态文件需要更新的时候,构建工具会生成新的哈希文件名,如旧资源为main.a1b2c3d4.css,新资源为main.e5f6g7h8.css,修改html中引用资源的名称为新资源名称,如下所示。

   112

  整体的流程:浏览器首次请求资源的时候,根据nginx配置的缓存策略来缓存资源,再次请求资源的时候发现缓存期未过1年时间,直接从缓存读取资源。后端需要更新资源的时候,构建工具生成新的哈希文件名,修改到html文件里,浏览器解析html,发现有新资源需要下载(main.a1b2c3d4.css和main.e5f6g7h8.css相当于是两个URL),就会去nginx请求新资源。

  现代的做法是静态资源不再由nginx提供下载,而是将其放到对象存储OSS上,浏览器直接从OSS上下载资源。可以通过OSS控制台或API上传时设置资源的响应头,比如缓存控制头Cache-Control、Expires来设置浏览器对于该资源的缓存策略。在OSS前面还可以使用CDN,以缩短资源响应时间,需要注意的是CND会继承OSS的缓存头,可以在CDN控制台覆盖OSS的缓存设置——用户第一次请求资源,CDN回源(去OSS)拉取资源,同时收到OSS返回的响应头:Cache-Control: max-age=31536000,如果没有在CDN里设置缓存期限的话,CDN会将资源的缓存期设为1年,这1年内CDN都不会回源OSS。解决CDN不回源的办法就是使用前面说的带哈希的文件名。

  通过构建工具(如Webpack、Vite等)在文件名中嵌入内容哈希值的资源又被称作“版本化资源”,其特点为:文件名包含基于文件内容的哈希值,一般设置长期缓存(max-age=31536000或immutable)策略,通过文件名变化来触发浏览器重新下载,典型代表为 CSS、JS、静态HTML页面、图片 等静态资源。

  113

   ②、非版本化资源

    除了使用max-age或expires缓存策略外,还可以使用no-cache + etag/Last-Modified或no-store策略,no-cache指示浏览器在使用缓存前先向服务确认,no-store指示浏览器完全不使用缓存。如下所示,no-cache指示浏览器每次使用缓存之前先向服务发送确认请求,etag 用来向响应添加资源的eTag值(一般基于资源大小+资源最后修改时间生成),if_modified_since 用来添加文件最后修改时间Last-Modified(时间单位为秒,exact表示时间值精确匹配,即请求中携带的时间和当前资源最后修改时间必须相同,before表示请求中携带的时间可以大于当前资源的最后修改时间),浏览器发送确认请求的时候会携带eTag值和最后修改时间,当eTag值与当前资源eTag值不同就返回200响应码+新的资源,相同就返回304以提示浏览器使用缓存,如果eTag值丢失的话,使用最后修改时间来决定返回200或304。

location ~*\.html${
    proxy_pass http ://backend-server;
    add_header Cache - Control "no-cache, must-revalidate";
    etag on;
    if_modified_since exact;
}

  协商缓存:通过 Cache - Control:no-cache + eTag 或 Last-Modified 响应头,明确告诉浏览器使用缓存之前先跟服务端协商。

  强缓存:通过Cache - Control:max-age 或 expires 响应头,明确告诉浏览器在指定的时间内无需向服务器请求。

  通过文件名变化来控制缓存的资源(即使用强缓存),称作“版本化资源”,依赖协商验证(如ETag、Last - Modified)来管理缓存的资源称为“非版本化资源”。

  111

   ③、动态资源

   对于动态HTML、REST接口这种动态资源,一般是由后端服务来设置no-cache(ETag/Last-Modified)或no-store缓存策略,nginx通过透传这些头部来指示浏览器使用的策略。后端生成eTag值可以参考nginx中使用资源大小+最后修改时间,如下所示为基于数据库记录的更新时间来生成eTag。如果后端服务是集群的话,eTag值可以设置为资源内容哈希值(资源较大的话计算其哈希值可能影响性能),防止相同内容在不同节点生成不同ETag。

  115

   不论是静态资源还是动态资源,都强烈建议在nginx或REST接口里明确配置缓存策略,因为服务端没有指示浏览器使用的缓存策略的话,浏览器可能会使用自定义的缓存策略。

  6、解决端口冲突

  在同一台服务器上部署多个web服务的话,都使用80端口的话就会端口冲突,解决方法是后端各个web服务使用不同的端口号,如下所示,由nginx根据根据域名或路径把请求转发给对应的服务。如果服务使用的是docker容器的话,也可以每个服务都使用80端口号,每个服务映射到容器宿主机的不同端口号,如A服务映射到8081端口,B服务映射到8082端口,然后还是由nginx根据根据域名或路径把请求转发给对应的端口。

  111

  7、nginx.conf 

  nginx配置文件 nginx.conf 的五个核心块:

 112

 113

5、ALB

  也可以不使用nginx,直接购买阿里云的ALB(或腾讯云的CLB)来实现负载均衡、URL路由转发等功能。ALB通过使用Tengine(基于Nginx深度定制)来实现七层负载均衡和URL路由,使用Keepalived 实现七层负载均衡服务的高可用,使用Tengine的健康检测来提供后端服务的高可用。使用ALB还有以下优点:

  ①、创建ALB/CLB的时候可以选择多个可用区(多可用区部署),这样就会创建多个负载均衡服务节点,形成ALB/CLB的高可用集群:请求会被自动的分发到健康的节点上,某个节点故障的话自动被标记为不可用。不同云服务厂商的高可用模式略有不同,阿里云ALB是“多可用区多活”模式,多个可用区的节点同时对外提供服务,共同分担流量,提供负载均衡和高可用功能,腾讯云CLB采用“双可用区主备”模式,请求主要走主可用区,当主可用区整体不可用时,才会切换到备可用区。

  ②、类似nginx,ALB也提供对后端服务的高可用,仅需配置健康检测。比如用ALB挂载两台后端云服务节点,然后开启开启健康检查,单节点故障时自动切换服务。如果仅有一台后端服务节点的话,也可以配置自动重启脚本,节点故障的话自动重启服务。ALB健康检测原理:定期向后端服务发送健康探测请求即心跳(比如发送HEAD请求),如果某个实例连续多次检查失败(请求无响应),ALB 会自动将其从后端服务器列表中移除,后续流量不再分发到该故障实例,待实例恢复后,再自动加回。强烈建议后端服务配置一个专用的健康检查端点,例如 /health或 /status:通常ALB的默认“检测路径”为根路径/(可以通过配置修改),但是后端服务经常会提供根路径的映射处理方法,比如Controller方法@GetMapping(“/”),这样HEAD请求就会被这个方法处理,但HEAD请求的回应是会丢弃响应体的,相当于是浪费了请求的处理,所以一般是专门编写一个极简的Controller来专门处理健康监测请求,如下所示:

         111

  ③、类似nginx,提供了多种负载均衡策略,除了轮询(默认)、加权轮询、IP哈希外,还提供了加权最小连接数(将请求分配给连接数/权重比值最小的服务——连接数越小、权重越高分配的请求越多)、一致性哈希策略(根据请求指定的哈希因子来分配请求——对请求中的特定字段如源 IP 地址、URL 参数等进行哈希计算,相同的源IP地址、URL参数会分配到同一服务上)。  

  ④、类似nginx,提供连接池复用连接功能,通过简单的配置就可以开启后端长连接(默认不开放),类似nginx,ALB也可以配置后端长连接的空闲超时等。开启了后端长连接以后,如果是腾讯云的CLB的话,客户IP需从 X-Forwarded-For头获取,如果是阿里云的ALB的话,客户IP正常透传(可以正常获得),如果是自建nginx的话,客户IP通过proxy_set_header来获得。

  ⑤、提供丰富的URL路由功能,支持基于路径、HTTP标头、HTTP请求方法、查询字符串、Cookie、Source IP等多种条件来识别特定业务流量,将其转发至不同的后端服务器,同时支持重定向、重写等高级操作。

  ⑥、服务弹性伸缩,比如业务促销等情形自动扩展其处理能力以应对高并发,比如设置当 CPU 使用率超过 80% 时,系统自动购买新的 ECS后端云服务并自动挂载到 SLB 后端。新的后端服务器上服务的自动部署一般有三种方式:一种是通过云控制台预先制作一个“黄金镜像”,里边安装好JDK、Tomcat、部署好你的代码、配置好所有环境,在弹性伸缩组里,指定使用这个“自定义镜像”来创建新机器。这种方式的缺点就是如果代码更新了,需要重新制作镜像(不过现在很多 CI/CD 工具可以自动构建镜像)。第二种方式是使用“启动脚本”(阿里云叫“用户数据”,腾讯云叫“自定义数据”),在控制台选择使用标准镜像(比如纯净的 CentOS 或 Ubuntu),然后编写启动脚本,脚本内容为安装JDK、安装Tomcat、去指定地址下载你的应用包(比如从对象存储OSS/COS上下载JAR/WAR应用包)等命令,新增后端服务器的时候会自动执行这个脚本。这种方式的缺点是服务弹性扩展的时候较慢,因为是现场下载安装。第三种方式是结合云厂商的运维编排(OOS),如阿里云的“运维编排服务”、腾讯云的“自动化助手”,弹性伸缩只负责新机器的加入,然后触发运维编排任务——在新增机器上安装Tomcat等应用 -> 从Git拉取代码 -> 构建 -> 部署。这种方式的优点是实现了硬件交付(新机器)和应用交付(装软件应用)的解耦。

  ⑦、零运维,提供可视化控制台,且能与云服务厂商生态无缝集成,比如与ALB与ECS云服务器绑定,实现后端服务的自动扩缩容以构建一个完全自动化的弹性架构。而且云厂商通常规定,ALB 与后端云服务器之间的内网流量是免费的。

  ⑧、SSL 证书管理,支持直接在控制台上传和管理 SSL 证书,并开启 HTTPS 卸载(即 ALB 处理 HTTPS,后端只需处理 HTTP),比在 Nginx 里配置https证书更方便。

  ⑨、提供基础的 DDoS 等安全防护能力。

  ⑩、目前项目都是推荐前后端分离,静态文件(静态HTML / CSS / JS)交由专门的 CDN 或对象存储(OSS / COS),不再由nginx提供静态文件的访问。如果html是后端动态生成的,可以缓存到nginx(或CDN边缘计算优化),不过要配置合适的缓存策略,防止用户一直看到的是旧版页面。

  前面说过,ALB/CLB可以选择多可用区部署,以形成ALB/CLB的高可用集群,但是这个集群里的节点都是在一个区域内的,如果该区域出现设备问题的话,整个服务就不可用。可以购买两台不同地区的ALB/CLB服务(后端ESC/CVM也选择对应的地区),以实现跨地域的负载均衡服务的集群,比如北京地区网络故障后,上海地区服务可以继续提供服务。使用跨地域的负载均衡集群的话,同时还可以根据用户所在地区选择就近的服务:如下图所示,购买一个北京ALB实例,一个上海ALB实例,云厂商提供的DNS云解析服务除了可以使用轮询的负载均衡策略进行访问外,还提供就近访问策略——来自华北地区的用户解析到北京ALB的IP,来自华东地区的用户解析到上海ALB的IP。跨地域的负载均衡服务集群有一个问题:北京的ALB挂了后,除非手动修改DNS记录,否则华北的用户还会解析到北京的IP,而且修改了DNS后新的DNS记录生效时间依赖DNS TTL,最长可能会等几分钟才生效。使用云服务厂商的“全局流量管理GTM”可以解决这个问题,它通过健康检测(通过Ping、TCP、HTTP/HTTPS协议探测服务健康状态)和故障切换来提供跨地域ALB/CLB集群的高可用。单地域部署:DNS云解析+CLB多可用区部署(提供CLB高可用),多地域部署:DNS云解析+全局流量管理(提供跨区域CLB的高可用)。

   111

  如果服务是面向全球的话,可以使用云厂商的“全球加速”服务,如下所示,中国的用户想要访问位于美国的后端业务,可以使用“全球加速”来转发流量,因为“全球加速”访问业务服务的话走的是云厂商的网络专线,速度很快。

   113

  如果没有后端团队的话,也可以使用平台即服务PaaS / 软件即服务SaaS这种完整解决方案(比如阿里云的云·企业官网、腾讯云的微搭低代码平台), 这种SaaS/PaaS化的建站工具使开发者不用再关心Nginx、Tomcat等服务实现,适合业务简单(如一个静态展示官网),需要在几天内快速上线一个原型来验证市场等情形。

posted on 2026-04-08 09:45  整鬼专家  阅读(9)  评论(0)    收藏  举报