1. 前言
我们真实的服务器不应该直接暴露到公网上去, 否则更加容易泄露服务器的信息, 也更加容易受到攻击. 一个比较 "平民化" 的方案是使用 Nginx 反向代理它. 今天就来聊一聊使用 Nginx 反向代理的一些能力, Nginx 代理能帮助我们实现很多非常有效的 API 控制功能. 这也解释了我为什么一直推荐使用 Nginx 来代理我们的 Spring Boot 应用.
2. Nginx 可以提供哪些能力
Nginx 已经不用太多的赞美了, 它已经得到了业界的广泛认可. 我们就聊聊它具体能够实现什么功能.
2.1 代理能力
这是针对服务器端我们最常用的功能, 一台具有公网的 Nginx 服务器可以代理和它能进行内网通信的真实的服务器. 让我们的服务器不直接对外暴露, 增加其抗风险能力.
假如 Nginx 服务器 192.168.1.8 可以和同一内网网段的 192.168.1.9 的应用服务器进行通信, 同时 Nginx 服务器具有公网能力并将公网绑定到域名 felord.cn 上. 那么我们 Nginx 代理的对应的配置 (nginx.conf) 是这样的:
- server {
- listen 80;
- server_name felord.cn;
- # ^~ 表示 uri 以某个常规字符串开头, 如果匹配到, 则不继续往下匹配. 不是正则匹配
- location ^~ /API/v1 {
- proxy_set_header Host $host;
- proxy_pass http://192.168.1.9:8080/;
- }
- }
经过以上配置后我们服务器真实的接口地址是 http://192.168.1.9:8080/foo/get 就可以通过 http://felord.cn/api/v1/foo/get 访问.
proxy_pass 如果以 / 结尾, 就相当于是绝对根路径, 那么 Nginx 不会把 location 中匹配的路径部分代理走; 如果不以 / 结尾, 也会代理匹配的路径部分.
2.2 Rewrite 功能
Nginx 还提供了一个 rewrite 功能让我们在请求到达服务器时重写 URI, 有点类似 Servlet Filter 的意味, 对请求进行一些预处理.
在 2.1 的例子中如果我们要实现如果判断请求为 POST 的话返回 405, 只需要更改配置为:
- location ^~ /API/v1 {
- proxy_set_header Host $host;
- if ($request_method = POST){
- return 405;
- }
- proxy_pass http://192.168.1.9:8080/;
- }
你可以使用 Nginx 提供的全局变量 (如上面配置中的 $request_method) 或自己设置的变量作为条件, 结合正则表达式和标志位 (last,break,redirect,permanent) 实现 URI 重写以及重定向.
2.3 配置 HTTPS
之前很多同学在群里问如何在 Spring Boot 项目中配置 HTTPS, 我都推荐使用 Nginx 来做这个事情. Nginx 比 Spring Boot 中配置 SSL 要方便的多, 而且不影响我们本地开发. Nginx 中 HTTPS 的相关配置根据下面的改一改就能用:
- http{
- #http 节点中可以添加多个 server 节点
- server{
- #ssl 需要监听 443 端口
- listen 443;
- # CA 证书对应的域名
- server_name felord.cn;
- # 开启 ssl
- ssl on;
- # 服务器证书绝对路径
- ssl_certificate /etc/ssl/cert_felord.cn.crt;
- # 服务器端证书 key 绝对路径
- ssl_certificate_key /etc/ssl/cert_felord.cn.key;
- ssl_session_timeout 5m;
- # 协议类型
- ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
- # ssl 算法列表
- ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
- # 是否 服务器决定使用哪种算法 on/off TLSv1.1 的话需要开启
- ssl_prefer_server_ciphers on;
- location ^~ /API/v1 {
- proxy_set_header Host $host;
- proxy_pass http://192.168.1.9:8080/;
- }
- }
- # 如果用户通过 http 访问 直接重写 跳转到 https 这个是一个很有必要的操作
- server{
- listen 80;
- server_name felord.cn;
- rewrite ^/(.*)$ https://felord.cn:443/$1 permanent;
- }
- }
这里就用到了 rewrite 来提高用户体验.
2.4 负载均衡
一般项目都是从小做到大起来的, 起步的时候部署一个服务器就够用了, 如果你的项目用户多了起来, 首先恭喜你, 说明你的项目方向很对. 但是伴随而来还有服务器压力, 你一定不想服务器宕机带来的各种损失, 你需要快速提高服务器的抗压能力, 或者你想不停机维护避免业务中断, 这些都可以通过 Nginx 的负载均衡来实现, 而且非常简单. 假如 felord.cn 我们部署了三个节点:
最简单的轮询策略
轮番派发请求, 这种配置是最简单的:
- http {
- upstream App {
- # 节点 1
- server 192.168.1.9:8080;
- # 节点 2
- server 192.168.1.10:8081;
- # 节点 3
- server 192.168.1.11:8082;
- }
- server {
- listen 80;
- server_name felord.cn;
- # ^~ 表示 uri 以某个常规字符串开头, 如果匹配到, 则不继续往下匹配. 不是正则匹配
- location ^~ /API/v1 {
- proxy_set_header Host $host;
- # 负载均衡
- proxy_pass http://App/;
- }
- }
- }
加权轮询策略
指定轮询几率, weight 和访问比率成正比, 用于后端服务器性能不均的情况:
- upstream App {
- # 节点 1
- server 192.168.1.9:8080 weight = 6;
- # 节点 2
- server 192.168.1.10:8081 weight = 3;
- # 节点 3
- server 192.168.1.11:8082 weight = 1;
- }
最终请求处理数将为 6:3:1 进行分配. 其实简单轮询可以看作所有的权重均分为 1. 轮询宕机可自动剔除.
IP HASH
根据访问 IP 进行 Hash, 这样每个客户端将固定访问服务器, 如果服务器宕机, 需要手动剔除.
- upstream App {
- ip_hash;
- # 节点 1
- server 192.168.1.9:8080 weight = 6;
- # 节点 2
- server 192.168.1.10:8081 weight = 3;
- # 节点 3
- server 192.168.1.11:8082 weight = 1;
- }
最少连接
请求将转发到连接数较少的服务器上, 充分利用服务器资源:
- upstream App {
- least_conn;
- # 节点 1
- server 192.168.1.9:8080 weight = 6;
- # 节点 2
- server 192.168.1.10:8081 weight = 3;
- # 节点 3
- server 192.168.1.11:8082 weight = 1;
- }
其它方式
我们可以借助一些插件来实现其它模式的负载均衡, 例如借助于 nginx-upsync-module 实现动态负载均衡. 我们是不是借助于此可以开发一个灰度发布功能呢?
2.5 限流
通过对 Nginx 的配置, 我们可以实现漏桶算法和令牌桶算法, 通过限制单位时间的请求数, 同一时间的连接数来限制访问速度. 这一块我并没有深入研究过这里就提一提, 你可以查询相关的资料研究.
3. 总结
Nginx 非常强大, 推荐使用它来代理我们的后端应用, 我们可以通过配置实现很多有用的功能, 而不必进行一些非业务逻辑的编码来实现, 如果你在 Spring Boot 中实现限流, 配置 SSL 的话, 麻烦不说, 还影响本地开发, 使用 Nginx 可以让我们专心到业务中去. 可以说 Nginx 在这里充当了一个小网关的作用, 其实很多知名网关底层都是 Nginx, 比如 Kong,Orange,Apache APISIX 等, 如果你有兴趣可以玩一玩 Nginx 的高级形态 Openresty. 另外我这里也有一份非常不错的 Nginx 入门资料送给你, 可以关注: 码农小胖哥 回复 nginx 获取.
关注公众号: Felordcn 获取更多资讯
个人博客: https://felord.cn https://felord.cn/
来源: https://www.cnblogs.com/felordcn/p/13363331.html