提升 API 可靠性的五种方法

news2024/11/27 23:55:04

API 在我们的数字世界中发挥着关键的作用,使各种不同的应用能够相互通信。然而,这些 API 的可靠性是保证依赖它们的应用程序功能正常、性能稳定的关键因素。本文,我们将探讨提高 API 可靠性的五种主要策略。

1.全面测试

要确保 API 的可靠性,第一步是进行全面的测试。需要进行的测试包括:功能测试以验证 API 的正确运行,集成测试以确保 API 能与其他系统正常协同,以及负载测试以理解 API 在大规模使用下的表现。

自动化测试能在开发周期的早期发现问题,回归测试能保证新的修改不会对现有功能造成破坏。使用虚拟化或模拟技术可以模拟 API 依赖,进行更深度的测试。此外,为了确保 API 的提供者和消费者都能满足约定的接口,契约测试非常重要。

下面我们将使用 Go 的内置 testing 包,通过一个简单的例子对一个假设的 API 端点(用于访问 API 的 URI)进行测试。

假设我们有一个端点 GET /users/{id} ,用于返回用户的详细信息。

下面是我们可能编写的测试代码:

package main

import (
"net/http"
"net/http/httptest"
"testing"
)

// 这是一个简化的实际处理器函数示例
func UserHandler(w http.ResponseWriter, r *http.Request) {
// ... 处理器逻辑
}

func TestUserHandler(t *testing.T) {
req, err := http.NewRequest("GET", "/users/1", nil)
if err != nil {
t.Fatal(err)
}

rr := httptest.NewRecorder()
handler := http.HandlerFunc(UserHandler)

handler.ServeHTTP(rr, req)

if status := rr.Code; status != http.StatusOK {
t.Errorf("handler returned wrong status code: got %v want %v",
status, http.StatusOK)
}

// 你还可以检查响应体是否符合预期的输出
expected := `{"id": "1", "name": "John Doe"}`
if rr.Body.String() != expected {
t.Errorf("handler returned unexpected body: got %v want %v",
rr.Body.String(), expected)
}
}

这个测试创建了一个新的 HTTP 请求,模拟了对我们的  /users/{id} 端点的调用,然后把请求传递给了处理器函数。测试会检查响应状态是否为  200 OK(即我们期望的成功请求应返回的结果)以及响应体是否与预期的输出一致。

这个例子只是一个简单的示例,在实际应用中,你可能会面临更复杂的场景,包括测试各种边界条件、错误路径等。此外,net/http/httptest 包提供了许多用于测试 HTTP 客户端和服务器的工具。

总之,你可以结合单元测试、性能测试和持续的集成测试,为你的 API 构建一个全面的测试套件。

单元测试的目的是确保你的 API 中每个组件的正确性。它通过验证每个部分的功能和隔离它们,使得你可以在早期发现并纠正问题。单元测试通常通过模拟依赖项并独立测试函数来完成。在 Go 语言中,可以利用诸如 testify 等包来达成这一目标。

性能测试则是为了在高流量的情况下对 API 进行压力测试。这种测试有助于你确定系统在高负载情况下的表现,识别瓶颈,并确保 API 能处理真实世界的使用情况。性能测试可以使用 JMeter 或Gatling 等工具进行。

最后,持续集成测试则通过模拟用户或客户端对 API 进行一系列连续操作,来测试系统的工作流程。这类测试能够提供对端到端工作流程、潜在的障碍或延迟,以及整体用户体验的深入理解。这个过程可以自动化并集成到你的 CI/CD 流程中,使得你可以持续监控并及时反馈任何代码更改的影响。

通过实施包括功能测试、单元测试、性能测试和持续合成测试在内的全面的测试策略,你可以确保你的 API 不仅稳定且高性能,还能为使用者提供无缝的体验。而在问题出现时,这种多元化的测试方法可以帮助你快速定位并解决问题的根源。

2.版本控制

在维护软件系统的稳定性方面,API 版本管理扮演了核心角色。随着时间推移,API 可能会随着需求变化和优化,如果没有适当的版本管理,可能会对现有的客户端应用造成破坏。这就是 API 版本管理的关键所在。通过维护 API 的各个版本,你可以在引入新功能和优化的同时,确保不影响使用旧版本 API 的应用。

这种策略提升了系统的稳定性,因为即使 API 经过改动和优化,客户端应用依然可以稳定运行。它让开发者能够部署 API 更新,而不需要担心这些变化会对正在运行的应用造成破坏,保障了系统的稳定性和正常运行。

保持向后兼容性是实现 API 稳定性的关键一环,也就是说,新系统应能与旧版 API 兼容。即使新的版本发布,使用旧 API 版本的应用依然可以正常运行。这避免破坏用户体验,并给了开发者足够的时间,让他们可以按照自己的节奏更新应用以适应新的 API ,而不是为了防止应用出错而被迫升级。这样做,有助于创建一个整体上更稳定、更强大和更具有弹性的系统。

示例

在 Go 语言中,我们可以使用多种方式来进行 API 的版本管理。

下面这个例子展示了如何通过在 URL 中嵌入 API 版本实现版本管理,这种方法通常被称为"路径版本控制"。

package main

import (
"fmt"
"net/http"
)

func handleRequest(w http.ResponseWriter, r *http.Request) {
  switch r.URL.Path {
case "/v1/users":
fmt.Fprintf(w, "You've hit the version 1 of the users API!")
case "/v2/users":
fmt.Fprintf(w, "You've hit the version 2 of the users API!")
default:
http.NotFound(w, r)
}
}

func main() {
http.HandleFunc("/", handleRequest)
http.ListenAndServe(":8080", nil)
}

在这个例子中,我们定义了一个处理函数,它根据请求的 URL 路径来匹配响应的代码。当访问 "/v1/users" 路径时,我们认为这是对我们 API 第一版本的请求。同样地,"/v2/users" 则对应我们 API 的第二个版本。通过添加更多的分支,你可以轻松地扩展这种模式以适应更多版本和端点。

此外,你也可以通过自定义头部或媒体类型版本管理(也称为"内容协商")来实现版本管理。

不论你选择何种版本管理策略,都应为 API 的每个版本维护清晰且最新的文档,这是一种良好的实践。

但是,我们也需要谨慎使用版本管理。我们应尽可能地保持向后兼容性,并提供清晰的文档。文档应详细说明每个新版本中的变化,并提供废弃旧版本的合理时间表。

3. 面向失败设计

在理想情况下,API 始终能够正确运行。然而在实际操作中,出现失败的情况并不罕见。在设计 API 的过程中,我们需要考虑其容错能力,这可能涉及到诸如优雅降级(即系统继续运行但是功能有所缩减)和故障转移机制(即出现故障时,系统自动切换到备份系统)等策略。

将明确的错误消息和代码纳入 API,能有助于应用程序更好地理解问题所在以及采取应对策略。我们可以通过重试逻辑、速率限制和断路器,让系统从临时性问题中恢复,避免故障级联。

下图显示了应对各种故障类型的操作方法:

示例:断路器模式

在断路器模式中,Go 语言有一个叫 go-hystrix 的热门库,该库专注于延迟和容错处理。它主要是在服务停止时,通过快速失败阻止故障级联。以下是一个基本示例:

package main

import (
"github.com/afex/hystrix-go/hystrix"
"log"
"net/http"
"errors"
)

func main() {
hystrix.ConfigureCommand("my_command", hystrix.CommandConfig{
Timeout:               1000,
MaxConcurrentRequests: 100,
ErrorPercentThreshold: 25,
})

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
err := hystrix.Do("my_command", func() error {
// 调用其他服务
return nil
}, nil)

if err != nil {
log.Printf("Failed to talk to other services: %v", err)
http.Error(w, "Failed to talk to other services", http.StatusInternalServerError)
}
})

log.Fatal(http.ListenAndServe(":1234", nil))
}

在上述示例中,我们将一个命令封装在 hystrix.Do() 中。如果基于我们设置的参数,传入 Do() 的函数失败或超时,断路器就会被触发,后续的调用将会立即失败,而不再调用该函数。

请注意,这只是一个基本的示例,实际应用场景将涉及更多复杂的用法,需要针对这个库以及其他的弹性实用程序库涉及的各种参数进行细致调整。请务必阅读各种库的文档,深入理解如何在你的代码中有效地使用它们。

4. 监控与分析

实时监控与及时分析对于保证 API 的稳定性至关重要。执行一套全面的 API 监控策略可以包括对运行时间、性能以及错误的检测,这有助于我们在问题扩散影响用户前,及时发现并处理。

同时,深入分析 API 的使用模式可以让我们得到重要的洞察。了解到高峰负载时段、最常使用的端点以及其他使用详情后,您就可以主动地找出可能存在的弱点,并据此进行 API 优化。

选择正确的指标去追踪,对于了解你的 API 的健康状态和性能至关重要。以下是一些需要考虑的关键指标:

1.吞吐量:您的 API 单位时间内处理的请求数量,可以进一步分为端点、HTTP 方法(如 GET、POST、PUT、DELETE 等)或响应状态码。

2.错误率:单位时间内的错误响应数量,通常是指含有 4xx 或 5xx 状态码的响应。同吞吐量一样,这个指标也可以按端点、HTTP 方法或具体的状态码进行细分。

3.延迟:处理一个请求所需的时间,通常以一系列百分位数(如第 50、95 和 99 百分位)来追踪,这可以帮助您了解典型和极端情况下的性能表现。您可能需要针对不同的端点或 HTTP 方法单独追踪此项。

4.流量:发送和接收的数据量,可以按端点、HTTP 方法或响应状态码进行细分。

5.可用性:您的 API 正常运行并能够处理请求的时间占比,可以作为一个整体进行测量,或者针对每一个单独的端点进行测量。

6.饱和度:系统达到最大容量的程度,这可以通过测量 CPU 使用率、内存使用率、磁盘 I/O 或其他可能限制系统处理更多负载的资源来了解。

7.断路器触发:如果您使用断路器模式处理故障,您可能需要追踪断路器被触发的频率,这可以帮助您了解 API 或其依赖项失败的频率。

请记住,根据你的 API 特性和应用需求,选择追踪的具体指标可能会有所不同。关键是要选择那些能为你提供有意义的 API 健康状况和性能洞察力的指标。

以 Prometheus 为例:

Prometheus 是一款内建客户端库的开源系统监控和警告工具包,它支持用各种语言度量您的服务。下面就是一个示例,说明如何使用 Go 客户端库在 HTTP 端点上展示指标。

我们将使用 Prometheus 的 Go 客户端 来展示和创建这些指标。

package main


import (
"net/http"


"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)


var (
httpRequestsTotal = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "http_requests_total",
Help: "Number of HTTP requests",
},
[]string{"path"},
)


httpRequestDuration = prometheus.NewSummaryVec(
prometheus.SummaryOpts{
Name: "http_request_duration_seconds",
Help: "Duration of HTTP requests in seconds",
},
[]string{"path"},
)
)


func init() {
// Register the metrics.
prometheus.MustRegister(httpRequestsTotal)
prometheus.MustRegister(httpRequestDuration)
}


func handler(w http.ResponseWriter, r *http.Request) {
// Increment the counter for the received requests.
httpRequestsTotal.WithLabelValues(r.URL.Path).Inc()


// Measure the time it took to serve the request.
timer := prometheus.NewTimer(httpRequestDuration.WithLabelValues(r.URL.Path))
defer timer.ObserveDuration()


// Handle the request.
w.Write([]byte("Hello, world!"))
}


func main() {


http.HandleFunc("/", handler)


// Expose the registered metrics via HTTP.
http.Handle("/metrics", promhttp.Handler())
http.ListenAndServe(":8080", nil)
}

在这个例子中,我们创建并注册了两个指标:http_requests_total 和 http_request_duration_seconds。前者是一个计数器,每接收到一个请求就增加一次计数,后者是一个汇总指标,用于记录处理每个请求所花费的时间。

然后,我们创建了一个 HTTP 处理器,每处理一个请求,就会增加计数器并测量请求的执行时长。我们利用 promhttp.Handler() 在 /metrics 端点上展示这些指标。

现在,只要你启动了服务器并向其发送请求,就可以通过访问 http://localhost:8080/metrics 或者使用工具如 curl 来查看这些指标。

这只是一个基础的示例,在实际应用中,你可能会希望追踪更多的指标,并基于其他维度(如 HTTP 方法、响应状态码等)对它们进行细分。

5. 利用 API 网关

API 网关是一种强大的工具,能有效提升 API 的健壮性。作为系统的统一入口,API 网关能够处理诸如路由、负载均衡、认证、限流等多项功能。通过将这些问题从 API 本体中抽离,你能更专注于业务逻辑,而非基础设施。

另外,API 网关还可提供额外的弹性特性,如自动故障转移、为提高性能而对响应进行缓存,以及在高负载时对请求进行缓冲或排队。

下面列出了 API 网关能提供的部分功能,帮助你为技术栈选择适合的 API 网关:

  1. 请求路由: API 网关可以依据请求中的路由信息将客户端请求路由到合适的后端服务。
  2. API 版本管理: API 网关能管理多版本的 API,允许客户端并行使用不同版本。
  3. 限流: 为了避免请求过量淹没后端服务,API 网关能够限制某个或某组客户端的请求速率。
  4. 身份验证和授权: API 网关通常处理客户端请求的身份验证和授权,确保只有经过验证并授权的请求才能到达后端服务。
  5. API 密钥管理: API 网关通常管理 API 密钥,这些密钥用于跟踪和控制 API 的使用方式。
  6. 缓存: 为了提升性能并降低后端服务的负载,API 网关可以缓存后端服务的响应,并在收到相同的请求时返回缓存的响应。
  7. 请求和响应转换: API 网关可以将请求和响应转换为客户端或后端服务所需的格式。
  8. 熔断器功能: 当服务出现故障,API 网关可以通过将请求路由到正常运行的服务来防止应用程序崩溃。
  9. 监控和分析: API 网关能收集 API 的使用和性能数据,用于分析、监控和警报。
  10. 安全策略: API 网关可以执行安全策略,如 IP 白名单,同时防止 SQL 注入、跨站脚本攻击(XSS)等安全威胁。

以下是一些知名的开源 API 网关:

  1. Kong:Kong 是一个云原生、快速、可扩展、分布式的微服务管理层(也称为 API 网关或 API 中间件)。自 2015 年以来,它以开源项目的形式存在,其核心功能是用 Lua 编写的,并运行在 Nginx 网络服务器上。
  2. Tyk:Tyk 是一个开源的 API 网关,运行速度快且可扩展性强,既可以运行在独立服务器上,也可与已有的 Nginx 安装进行协同工作。
  3. Express Gateway:Express Gateway 是一个基于 Express.js 构建的微服务 API 网关。该网关完全可扩展,不依赖任何特定框架,能够在短时间内提供强大且可扩展的解决方案。
  4. KrakenD:KrakenD 是一个高性能的开源 API 网关。KrakenD 消除了所有 SOA 架构的复杂性,以支持应用程序开发者快速发布新功能,同时保持出色的性能。

总的来说,提升 API 的可靠性不是一项一次性任务,而是需要持续投入的工作。这包括严格的测试、精确的版本控制、遵循好的设计原则,智能地使用如 API 网关这样的工具,以及持续的监控和分析。有了这些策略,你就能构建出能经受住时间考验并为你的应用程序提供可靠基础的 API。

原文标题:https://www.codereliant.io/5-ways-to-improve-your-api-reliability/

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

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

相关文章

Kubernetes 入门

Kubernetes 入门 文章目录 Kubernetes 入门一、Kubernetes 环境部署1. 环境准备2. 测试部署 Nginx3. 在任意节点使用 kubectl 二、深入 pod1. 使用配置文件部署引用2. 探针 三、资源调度1.标签与选择器2.Deployment3.StatefulSet4.DaemonSet5.HPA6. Service7. Ingress8. 配置管…

【Unity】为角色添加动画

如何添加动画 在Animations的AnimationClips文件夹下自己为角色创建一个文件夹 为角色添加Animator 然后选中上面创建的文件夹,拖动到上图中的Controller中 点击最上方任务栏的Window>Animation>Animation,这会弹出一个Animation窗口 该窗口存在时…

算法leetcode|63. 不同路径 II(rust重拳出击)

文章目录 63. 不同路径 II:样例 1:样例 2:提示: 分析:题解:rust:go:c:python:java: 63. 不同路径 II: 一个机器人位于一个 m x n 网格…

SQL_SQL_常见面试问题

问题类型 :SQL优化 问题描述 :用户浏览日志(date, user_id, video_id), 统计 2020.03.29 观看不同视频个数的前5名 user_id。 思路 :主要注意预计算,避免直接去重 解决方案 : Hive_HQL_Hive…

【VB6|第20期】遍历Excel单元格的四种方法

日期:2023年7月19日 作者:Commas 签名:(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释:如果您觉得有所帮助,帮忙点个赞,也可以关注我,我们一起成长;如果有不对的地方&#xf…

架构实战微服务架构拆解

作业内容 拆分电商系统为微服务。 背景:假设你现在是一个创业公司的 CTO,开发团队大约 30 人左右,包括 5 个前端和 25 个后端,后端开发人员 全部都是 Java,现在你们准备从 0 开始做一个小程序电商业务,请你…

2023牛客暑期多校训练营1--K Subdivision(最短路树)

题目描述 You are given a graph with n vertices and m undirected edges of length 1. You can do the following operation on the graph for arbitrary times: Choose an edge (u,v) and replace it by two edges, (u,w) and (w,v), where w is a newly inserted vertex.…

【毕业季】九年程序猿有话说

活动地址:毕业季进击的技术er 九年程序猿有话说 勇敢前行,绽放青春,不负韶华!选择IT的原因职场新人如何选择工作工作中,如何快速成长工作中用技术做过的最有成就感的事?程序员三十五岁瓶颈你怎么看&#xf…

445. 两数相加 II

445. 两数相加 II 给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。 你可以假设除了数字 0 之外,这两个数字都不会以零开头。 示例1: 输入:l1 [7,2,4,…

RocketMQ教程-(4)-主题(Topic)

本文介绍 Apache RocketMQ 中主题(Topic)的定义、模型关系、内部属性、行为约束、版本兼容性及使用建议。 定义​ 主题是 Apache RocketMQ 中消息传输和存储的顶层容器,用于标识同一类业务逻辑的消息。 主题的作用主要如下: 定义…

断路器分、合闸线圈直流电阻试验和绝缘电阻试验

断路器分、合闸线圈直流电阻试验 试验目的 对于断路器来说, 分、 合闸线圈是用于控制断路器分合闸状态的重要控制元件。 断路器停电检修时, 可以通过测试分、 合闸线圈的直流电阻来判断其是否正常。 试验设备 万用表 厂家: 湖北众拓高试代销 试验接线 分、 合闸线圈…

Linux系统进程概念详解

这里写目录标题 冯诺依曼体系结构操作系统(Operator System)1.概念2.目的3.管理4.系统调用和库函数概念 进程1.概念2.描述进程-PCB3.查看进程4.通过系统调用获取进程标示符5.通过系统调用创建进程-fork 进程状态1.Linux内核源代码2.进程状态查看 进程优先级1.基本概念2.查看系统…

dxf怎么转换成PDF格式?转换方法其实很简单

PDF文件是一种可靠的文件格式,可以在各种操作系统和软件上打开和查看。而dxf是CAD文件的一种格式,打开它一般都是需要相关的操作软件才能打开,不是特别方便,将dxf文件转换成PDF格式就可以很好的解决这一问题,下面教大家…

python:基于反卷积算法的 GEDI 波形树高特征提取

作者:CSDN @ _养乐多_ 本文将介绍如何对 GEDI(Global Ecosystem Dynamics Investigation)激光雷达数据中所标识激光测高数据点的波形数据使用反卷积算法提取树高特征。 文章目录 一、波形数据提取二、代码详细解释三、完整代码一、波形数据提取 波形数据提取参考博客:《p…

Nodejs+vue+elementui手机电脑产品维修售后服务管理系统

需求分析,也称为软件需求分析、系统需求分析或需求分析工程,是指开发人员经过充分的研究和分析,准确地理解用户和项目在功能、性能、可靠性等方面的具体需求,并将用户的非正式需求表述转化为确定系统必须执行的需求的完整定义的过…

pytorch实现图像remap

def gpu_remap(numpy_img,map_tensor):# 准备图像数据img_tensor torch.from_numpy(numpy_img).contiguous().cuda(non_blockingTrue)img_tensor img_tensor.permute(2,0,1).unsqueeze(0).float()res torch.nn.functional.grid_sample(img_tensor,map_tensor,modebilinear,p…

c语言练手项目【编写天天酷跑游戏2.0】EASYX图形库的运用。代码开源,素材已打包

天天酷跑项目的开发 项目前言 项目是基于Windows,easyX图形库进行开发的, 开发环境:Visual Studio 2022 项目技术最低要求: 常量,变量,数组,循环,函数。 文章目录 天天酷跑项目的…

单体架构与微服务架构

什么是单体架构 单体架构(Monolithic Architecture)是一种传统的软件架构模式,它将整个应用程序作为一个单一、自治的单元构建和部署。在这种架构中,应用程序的所有功能和组件都被集成到一个统一的代码库中。 在单体架构中&…

【Linux网络】网络编程套接字(一)基础部分

目录 理解源IP地址和目的IP地址理解源MAC地址和目的MAC地址数据在网络传输过程中有两套地址socket通信的本质端口号和目的端口号 Post(端口号) 和 Pid (进程ID)认识TCP协议和UDP协议 网络字节序 理解源IP地址和目的IP地址 因特网上每台计算机都有自己的…

Jmeter-使用http proxy代理录制脚本

Jmeter-使用http proxy代理录制脚本 第1步:打卡jmeter工具新增1个线程组 第2步:给线程组添加1个HTTP请求默认值 第3步:设置下HTTP请求默认值第4步:在工作台中新增1个----HTTP代理服务器 第5步:设置HTTP代理服务器…