使用nginx作为API网关

使用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.hqwc.cn/news/125272.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

智能AI创作系统ChatGPT商业运营版源码+AI绘画系统/支持GPT联网提问/支持Midjourney绘画+Prompt应用+支持国内AI提问模型

一、AI创作系统 SparkAi创作系统是基于OpenAI很火的ChatGPT进行开发的Ai智能问答系统。本期针对源码系统整体测试下来非常完美,可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI创作ChatGPT?小编这里写一个详细图文教程吧&…

MacOS怎么安装Nacos(附带:Windows系统)

MacOS安装Nacos(一定要配置JDK的环境变量,后面告诉你为什么?) (1)进入Nacos官网,前往githubhomehomehttp://nacos.io/zh-cn/ (2)点击右下角的releases 然后点击Tags 选择…

STL upper_bound和lower_bound函数

声明&#xff1a; 首先包含头文件#include<algorithm> 这里的两个函数所运用的对象必须是非递减的序列&#xff08;也就是数组&#xff0c;数组必须是非递减的&#xff09;&#xff0c;只有这样才可以使用upper_bound和lower_bound这两个函数。 还有一点&#xff0c;就…

IBT机考-PBT笔考,优劣分析,柯桥口语学习,韩语入门,topik考级韩语

IBT机考&#xff0c;顾名思义就是在电脑上答题考试&#xff0c;区别于现在的PBT纸笔答题&#xff0c;不需要发卷、收卷&#xff0c;也不需要填涂和用笔写字。 考试不需要带任何文具&#xff0c;就连笔试要用到的修正带都将省去。因为听力、阅读的选择题都是用鼠标点击&#xf…

各种机器码的本质(原码、反码、补码、移码、IEEE754格式阶码)

总述 无论使用什么格式的机器码来表示真值&#xff0c;若取一定位数n以后&#xff0c;各个比特位的排列个数是一定的&#xff0c;为 2 n 2^n 2n种排列&#xff0c;所以选择什么格式的机器码实质上选择什么映射方式来完成从这 2 n 2^n 2n种离散排列到离散的整数真值的映射&…

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

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

string类的模拟实现(万字讲解超详细)

目录 前言 1.命名空间的使用 2.string的成员变量 3.构造函数 4.析构函数 5.拷贝构造 5.1 swap交换函数的实现 6.赋值运算符重载 7.迭代器部分 8.数据容量控制 8.1 size和capacity 8.2 empty 9.数据修改部分 9.1 push_back 9.2 append添加字符串 9.3 运算符重载…

LangChain 用例(未完)

在Azure上的OpenAI端点 注意 OpenAI key 可以用微软 用例【1. 嵌入 &#xff0c;2. 问答】 1. import os import openai from langchain.embeddings import OpenAIEmbeddings os.environ["OPENAI_API_KEY"] "****" # Azure 的密钥 os.environ["OP…

ChainForge:衡量Prompt性能和模型稳健性的GUI工具包

ChainForge是一个用于构建评估逻辑来衡量模型选择&#xff0c;提示模板和执行生成过程的GUI工具包。ChainForge可以安装在本地&#xff0c;也可以从chrome浏览器运行。 ChainForge可以通过聊天节点对多个对话可以使用不同的llm并行运行。可以对聊天消息进行模板化&#xff0c;并…

数据挖掘(3)特征化

从数据分析角度&#xff0c;DM分为两类&#xff0c;描述式数据挖掘&#xff0c;预测式数据挖掘。描述式数据挖掘是以简介概要的方式描述数据&#xff0c;并提供数据的一般性质。预测式数据挖掘分析数据建立模型并试图预测新数据集的行为。 DM的分类&#xff1a; 描述式DM&#…

Python安装指南:安装Python、配置Python环境(附安装包)

1. 选择正确的版本&#xff0c;下载安装包 根据你的实际需要选择Python发行版本。 值得注意的是&#xff0c;编程语言包并不是越新越好的&#xff0c;不同版本的Python之间可能会产生兼容性问题。 如果你不确定你的项目需要哪个版本&#xff0c;请查阅您可能需要使用到的插件的…

洛谷题目题解详细解答

洛谷是一个很不错的刷题软件&#xff0c;可是找不到合适的题解是个大麻烦&#xff0c;大家有啥可以私信问我&#xff0c;以下是我已经通过的题目。 你如果有哪一题不会&#xff08;最好是我通过过的&#xff0c;我没过的也没关系&#xff09;&#xff0c;可以私信我&#xff0…