使用nginx作为API网关

news2024/10/7 16:17:01

使用nginx作为API网关

如果我们需要部署反向代理,我们可能已经听说过 nginx。如果我们还没听说过,让我们在这篇文章谈一谈它,以及我们如何使用它作为API网关。

什么是nginx?

nginx是一个HTTP服务器和反向代理,一个邮件代理服务器,及一个通用的TCP/UDP代理服务器。

目前,nginx有一个开源和商业版本(nginx+)。在本文章中,我们将尝试使用免费版本的一些功能,但也可以在付费版本中使用。

什么是API网关

API网关是允许开发人员创建、发布、维护、监视和安全API的流量管理器。

使用API网关有几个优点,例如:

  • 通过单一接口使API更加安全。
  • 使我们能够更容易地执行访问控制策略、速率限制、路由等。
  • 使得能够收集最全面的指标

我们要什么

假设我们有两种APIa用于产品,我们称之为 Product API ,另一种是用于消费者,我们称之为 Users API。最终,我们将发布API。我们的架构图是开始的:

在这里插入图片描述

我们要创建以下路由:

  • /api/products:指向Product API服务
  • /api/users: 指向Users API服务

在我们的设置中,并不想公开我们的服务。因此,我们的唯一网关应该是我们在上面的图表中称为API网关的nginx

为了模拟我们的API,我们构建了两个简单的服务( Product APIUsers API )。

为此,让我们在gateway.conf文件中创建一个简单的规则。

server {
   listen 80 default_server;
   listen [::]:80 default_server;
 
   #
   # Products API
   #
   location /api/products {
       proxy_pass http://products_api:8001;
   }
 
   #
   # Users API
   #
   location /api/users {
       proxy_pass http://users_api:8002;
   }
}

在上面的配置中,请注意我为API容器创建了gateway别名(可查看配置docker-compose.yml)。

当我们请求不同路径时就会调用不同的服务:

GET http://localhost/api/products
{
  "name": "Product 1",
  "description": "Detail about product 1"
}

GET http://localhost/api/users
{
  "name": "User 1",
  "email": "email@email.com"
}

这样,我们就有了 nginx 作为反向代理的作用。为了改进我们的配置,我们将定义upstream 用于我们的 API,而不是直接使用它们的地址。因此,我们将配置修改成:

upstream products_api_server {
       server products_api:8001;
}
 
upstream users_api_server {
       server users_api:8002;
}

之后:

server {
   listen 80 default_server;
   listen [::]:80 default_server;

   #
   # Products API
   #
   location /api/products {
       proxy_pass http://products_api_server;
   }
 
   #
   # Users API
   #
   location /api/users {
       proxy_pass http://users_api_server;
   }
}

upstream用于定义一组可以通过proxy_passfastcgi_passuwsgi_passscgi_passmemcached_passgrpc_pass directives声明的服务器。

负载均衡

在下一个场景中,假设我们的Users API 被重载,我们想要添加一个新的实例(users_api_balance )接收用户的请求。

在这里插入图片描述
我们将配置API网关来实现平衡。为此,我们将把新服务器添加到 Users API服务器组中。

upstream products_api_server {
       server products_api:8001;
}
 
upstream users_api_server {
       server users_api:8002;
       server users_api_balance:8002;
}

通过这些设置,请求在服务器之间均匀分布。

但是我们如何配置我们的平衡规则呢?现在让我们定义一下,我们应该将新请求引导到活动连接数量最少的服务器。同样,我们只需要配置一下least_conn字段

upstream products_api_server {
       server products_api:8001;
}
 
upstream users_api_server {
least_conn;
       server users_api:8002;
       server users_api_balance:8002;
}

我们将暂时使用这个设置,但是nginx还有一些其他的平衡方法:

  • ip_hash
  • Generic Hash
  • Random
  • Last Time (nginx+专属)

不过,我们假设Users_API 服务器有一个更好的基础结构,我们希望优先处理对这个服务器的请求。我们可以通过设置 weight 参数。

upstream products_api_server {
       server products_api:8001;
}
 
upstream users_api_server {
least_conn;
       server users_api:8002 weight=5;
       server users_api_balance:8002;
}

就这样,users_api 服务器的优先级是其他服务器的五倍。

缓存

在这个场景中,让我们假设Users API服务有波动性,并且我们希望优化响应时间。为此,我们将在API网关中添加一个基本缓存,

实现基本缓存只需要两个指令:proxy_cache_pathproxy_cache

upstream products_api_server {
       server products_api:8001;
}
 
upstream users_api_server {
       ip_hash;
       server users_api:8002;
       server users_api_balance:8002;
}
 
 
proxy_cache_path /tmp/products levels=1:2 keys_zone=products_cache:10m max_size=10g inactive=60m use_temp_path=off;
 
server {
   listen 80 default_server;
   listen [::]:80 default_server;
 
   #
   # Products API
   #
   location /api/products {
       proxy_cache products_cache;
       proxy_pass http://products_api_server;
   }
 
   #
   # Users API
   #
   location /api/users {
       proxy_pass http://users_api_server;
   }
}

proxy_cache_path 指令定义了以下设置:

  • 缓存的本地磁盘目录被称为/tmp/products .
  • levels 设置了两个目录层次结构/tmp/products 。如果levels 参数为空,nginx 将所有文件放在同一个目录中。
  • keys_zone 设置共享内存区,用于存储缓存键和元数据,如使用计时器。
  • max_size 设置缓存大小的上限(在本例中为10m)。它是可选的,不指定一个值,允许缓存增长以使用所有可用磁盘空间。
  • inactive 指定一个项目可以在缓存中停留多长时间而不被访问(默认10分钟)。在本例中,缓存管理器过程自动从缓存中删除60分钟未请求的文件,无论该文件是否过期。
  • nginx首先将指定用于缓存的文件写入一个临时存储区,然后编写use_temp_path=off 指令指示 nginx 将它们写入将缓存的同一目录。

nginx生成的键的默认形式类似于下列 nginx 变量的MD5哈希:$scheme$proxy_host$request_uri,当然实际使用的算法稍微复杂一些。

速率限制

在定义了平衡和缓存规则之后,我们现在可以通过为Users API设置一个速率限制来保护我们的内部服务不受大量请求(DDOS攻击)的影响。

限速配置有两个主要指令:limit_req_zonelimit_req

upstream products_api_server {
       server products_api:8001;
}
 
upstream users_api_server {
       ip_hash;
       server users_api:8002;
       server users_api_balance:8002;
}
 
 
proxy_cache_path /tmp/products levels=1:2 keys_zone=products_cache:10m max_size=10g inactive=60m use_temp_path=off;
limit_req_zone $binary_remote_addr zone=products_rate:10m rate=1r/s;
limit_req_zone $binary_remote_addr zone=user_rate:10m rate=10r/s;
 
 
server {
   listen 80 default_server;
   listen [::]:80 default_server;
 
   #
   # Products API
   #
   location /api/products {
       proxy_cache products_cache;
       limit_req zone=products_rate;
       limit_req_status 429;
       proxy_pass http://products_api_server;
   }
 
   #
   # Users API
   #
   location /api/users {
       limit_req zone=user_rate;
       limit_req_status 429;
       proxy_pass http://users_api_server;
   }
}

limit_req_zone有以下三个参数:

  • key 定义应用限制所依据的请求特性。在这个例子中,它是nginx变量$binary_remote_addr,它拥有客户端IP地址的二进制表示形式。这意味着我们将每个唯一的IP地址限制在第三个参数定义的请求率上。
  • zone 定义用于存储每个IP地址状态的共享内存区域,以及它访问一个请求限制的URL的频率。将信息保存在共享内存中意味着它可以在nginx工作流程之间共享。
  • rate 设置最大请求率。在这个示例中,速率不能超过每秒10个Users API请求和每秒1个Product API请求。

默认情况下,当请求限制达到时,nginx 将返回503(服务暂时不可用)。为了改进,我们使用limit_req_status 自定义响应状态代码。在这种情况下,我们使用429(太多请求)。

API密钥认证

在没有某种形式的认证来保护API的情况下发布API是不寻常的。nginx提供了几种保护API和认证API客户端的方法。在我们的解决方案中,我们将使用一个简单的解决方案来验证对我们服务的访问。我们会利用 API键认证 .

使用API键身份验证,我们使用一个映射块来创建一个允许访问我们服务的客户机名称列表。

map $http_apikey $api_client_name {
    default       "";
    "KrtKNkLNGcwKQ56la4jcHwxF"  "client_one";
    "sqj3Ye0vFW/CM/o7LTSMEMM+"  "client_two";
    "diXnbzglAWMMIvyEEV3rq7Kt"  "client_ten";
}

map参数后边需要两个参数。第一个定义了在哪里找到API键,在本例中是apikey 客户端http请求存在$http_apikey 变量。第二个参数创建一个新的变量($api_client_name )并将其设置为第一个参数与键匹配的行上的第二个参数的值。

现在在我们的服务上启用API键身份验证。为了避免代码重复,我将把API键验证分离到另一种方法中。

# API key validation
location = /_validate_apikey {
    internal;
    
    if ($http_apikey = "") {
        return 401; # Unauthorized
    }
    
    if ($api_client_name = "") {
        return 403; # Forbidden
    }
    
    return 204; # OK (no content)
}
#
# Products API
#
location /api/products {
    auth_request /_validate_apikey;
    proxy_cache products_cache;
    limit_req zone=products_rate;
    limit_req_status 429;
    proxy_pass http://products_api_server;
}

#
# Users API
#
location /api/users {
    auth_request /_validate_apikey;
    limit_req zone=user_rate;
    limit_req_status 429;
    proxy_pass http://users_api_server;
}

在此配置到位后,Users APIProduct API现在就实现了API键身份验证。

其他可用于认证的更健壮的解决方案有: OAuth Proxy Module 或 Phantom Token Module.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1062122.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【软件测试】自动化测试selenium(二)

文章目录 三. 掌握Selenium常用的API使用1. webdriver API2. 操作测试对象3. 添加等待4. 打印信息5. 浏览器的操作6. 键盘事件7. 鼠标事件8. 定位一组元素9. 多层框架/窗口定位10. 下拉框处理11. 弹窗处理12. 上传文件13. 关闭浏览器14. 切换窗口15. 截图操作 三. 掌握Selenium…

python实现 线性卷积用Toeplitz 矩阵运算

python实现 线性卷积用Toeplitz 矩阵运算 前言 在看论文的时候,发现Toeplitz 矩阵和线性卷积有关系,于是翻了程佩青老师的数字信号处理课本,发现是有讲过这点的。 Toeplitz 矩阵:从左上到右下的斜对角线都相同,如下…

性能测试工具 - LoadRunner

什么是性能测试? 性能测试就是测试人员利用性能测试工具模拟系统在不同情况下的性能指标是否正常。 性能测试工具 - LoadRunner 接下来介绍LoadRunner的作用和使用。 LoadRunner 就是一个很常见的性能测试工具,它有三个部分组成: 这三个组…

GhostNet原理解析及pytorch实现

论文:https://arxiv.org/abs/1911.11907 源码:https://github.com/huawei-noah/ghostnet 简要论述GhostNet的核心内容。 Ghost Net 1、Introduction 在训练良好的深度神经网络的特征图中,丰富甚至冗余的信息通常保证了对输入数据的全面理…

MySQL:数据库的物理备份和恢复-冷备份(3)

介绍 物理备份: 直接复制数据文件进行的备份 优点:不需要其他的工具,直接复制就好,恢复直接复制备份文件即可 缺点:与存储引擎有关,跨平台能力较弱 逻辑备份: 从数据库中导出数据另存而进行的备…

Linux YUM源(本地/网络源)配置详解

目录 一、挂载 二、建立本地源 配置详解: 三、建立网络源 配置详解: 四、验证 一、挂载 ——将光盘挂载到 /mnt ——挂载光盘时要保证虚拟机光盘处于连接状态 命令:[rootlocalhost mnt]# mount /dev/sr0 /mnt # 此时还未挂载 [rootlo…

安装cad显示找不到msvcp140.dll怎么解决?靠谱的msvcp140.dll丢失的解决方法分享

在安装 CAD 软件时,出现找不到 msvcp140.dll 的困扰,让许多用户感到十分沮丧。msvcp140.dll 是 Visual C Redistributable for Visual Studio 2015 的运行库文件,对于 CAD 软件的正常运行至关重要。因此,解决这个问题是当务之急。…

玩转Linux—如何在Linux环境中部署MySQL、Redis和nginx

1、Linux常用命令 Linux学习之路: VMware虚拟机安装Linux系统(详解版) 查看当前文件目录:ls查看目录中文件详细信息:ll输出当前所处的目文件目录:pwdLinux查看当前IP地址:ifconfigWindows查看当前IP地址&#xff1…

如何使用大语言模型来绘制图画

请创作一张科技感十足的图片,包含siri和iphone两个元素,请帮我挑选合适的style和background 好的,我会为你创作一张科技感十足的图片,包含siri和iphone两个元素。我会根据你的要求,选择一种适合的风格和背景。请稍等一…

制作电子期刊没模板?请疯狂看我

你们是不是也在为制作电子期刊而烦恼?没有合适的模板,内容再精彩也难以展现。今天给大家分享一个超级实用的秘籍!✨ 首先,我们要明白,电子期刊制作的关键在于模板的选择。一个好的模板可以让你的内容瞬间焕发光彩。但是…

Nodejs 第十七章(events)

EventEmitter Node.js 核心 API 都是采用异步事件驱动架构,简单来说就是通过有效的方法来监听事件状态的变化,并在变化的时候做出相应的动作。 fs.mkdir(/tmp/a/apple, { recursive: true }, (err) > {if (err) throw err; });process.on(xxx,()>…

玩转ChatGPT:DALL·E 3生成图像

一、写在前面 好久不更新咯,因为没有什么有意思的东西分享的。 今天更新,是因为GPT整合了自家的图像生成工具,名字叫作DALLE 3。 DALLE 3是OpenAI推出的一种生成图像的模型,它基于GPT-3架构进行训练,但是它的主要目…

STM32CubeMX学习笔记-USART_DMA

STM32CubeMX学习笔记-USART_DMA 一、DMA的概念二、数据传输方式普通模式循环模式 三、以串口方式讲解串口DMA方式发送函数:HAL_UART_Transmit_DMA串口DMA方式接收函数:HAL_UART_Receive_DMA获取未传输数据个数函数:__HAL_DMA_GET_COUNTER关闭…

IIS解决上传文件大小限制

IIS解决上传文件大小限制 目的&#xff1a;通过配置文件和IIS来解决服务器对上传文件大小的限制 1&#xff1a;修改配置文件&#xff08;默认为4M 值的大小根据自己情况进行修改&#xff09; <httpRuntime maxRequestLength"2048000" /> 2&#xff1a;修改IIS配…

LVGL_基础控件Switch_Button

LVGL_基础控件Switch_Button 1、创建switch_button /* 创建一个 switch 部件(对象) */ lv_obj_t * sw lv_switch_create(lv_scr_act()); // 创建一个 switch 部件(对象),他的父对象是活动屏幕对象 lv_obj_center(sw); // 方法1&…

我的创作纪念日-第1024天

文章目录 一、机缘二、收获三、日常四、憧憬 一、机缘 不知不觉&#xff0c;已经加入CSDN这个大家庭5年多了&#xff0c;回想起3年前发布第一篇博客的时候&#xff0c;那时我记得很清楚&#xff0c;我在做项目时遇到报错&#xff0c;解决问题之后&#xff0c;然后想起了好多人…

10分钟了解数据架构、数据模型

写在前面&#xff1a;很多小伙伴分不清数据架构与数据模型&#xff0c;同时如何做好数据建模也有一定的疑问 1. 数据架构、数据模型、数据建模区别与联系 企业架构包含业务架构、数据架构、应用架构和技术架构。数据架构的主要目标是有效的管理数据&#xff0c;以及有效地管理…

Docker---cgroups资源限制

目录 一、cpu资源控制 1、 设置cpu使用率上限 2、设置cpu资源占用比&#xff08;设置多个容器时才有效&#xff09; 3、设置容器绑定指定的CPU 三、内存资源控制 四、磁盘IO配额控制 1、限制Block IO 2、限制bps和iops进行限制 一、cpu资源控制 cgroups是一个非常强大的…

Vue组件路由

1&#xff0c;安装vue-router组件&#xff0c;终端输入&#xff1a; npm i vue-router3.5.3 2&#xff0c;在src文件夹下创建router目录 3&#xff0c;创建index.js文件&#xff0c;配置路由&#xff0c;导入需要路由的组件。以后每次添加路由只要在routes中改变即可。 impo…

YOLOV7改进实操-添加Wise IoU,实现有效提点

1、打开utils->general.py&#xff0c;找到bbox_iou&#xff08;&#xff09;&#xff0c;345行左右&#xff0c;将下面的与源码进行替换 wiou有三个版本&#xff0c;可以替换&#xff0c;看看哪一个提点多 class WIoU_Scale: monotonous: {None: origin v1True: monotoni…