FastAPI-1:现代网络

1 现代网络

曾几何时,网络小而简单。开发者们把 PHP、HTML 和 MySQL 调用放到一个文件中,然后自豪地告诉大家去看看他们的网站,这样做非常有趣。但随着时间的推移,网络发展到了数以亿计,不对,是数以万亿计的页面,早期的游乐场变成了主题公园的元宇宙。

在本章中,我将指出一些与现代网络日益相关的领域:

  • 服务和应用程序(API)
  • 并发
  • 数据

1.1 服务和应用程序(API)

网络是一个巨大的连接结构。尽管很多活动仍然发生在内容方面--HTML、JavaScript、图像等,但连接事物的应用程序编程接口(API)越来越受到重视。

通常情况下,网络服务负责处理低层次的数据库访问和中层业务逻辑(通常统称为后端),而JavaScript或移动应用程序则提供丰富的高层前端(交互式用户界面)。这些前端和后端世界变得更加复杂和多样化,通常需要开发人员专门从事其中一项工作。

这两个世界通过应用程序接口(API)相互对话。在现代网络中,API 的设计与网站本身的设计同等重要。API 是一种契约,类似于数据库模式。现在,定义和修改 API 已成为一项重要工作。

1.1.1 API种类

每个应用程序接口都定义了以下内容:

  • 协议: 控制结构
  • 格式: 内容结构

随着技术的发展,从孤立的机器到多任务系统,再到网络服务器,已经开发出多种API方法。你可能会在某一时刻遇到其中的一种或多种:

  • 在联网之前,API通常意味着非常紧密的连接,比如调用与应用程序使用相同语言的库的函数--例如,在数学库中计算平方根。
  • 远程过程调用(RPC)的发明是为了调用同一台机器或其他机器上其他进程中的函数,就像调用应用程序中的函数一样。当前流行的例子是 gRPC。
  • 消息传递(Messaging)在进程间通过管道发送小块数据。消息可以是类似动词的命令,也可以只是表示感兴趣的类似名词的事件。目前流行的消息传递解决方案包括 Apache Kafka、RabbitMQ、NATS和ZeroMQ等,从工具包到完整的服务器,种类繁多。

通信可以遵循不同的模式:

  • 请求-响应: 如网络浏览器调用网络服务器。
  • 发布-订阅(Publish-subscribe, or pub-sub):发布者发布消息,订阅者根据消息中的某些数据(如主题)对每条消息采取行动。
  • 队列:与发布-订阅类似,但只有一个订阅者会抓取信息并对其采取行动。

其中任何一种都可与网络服务一起使用,例如,执行发送电子邮件或创建缩略图等缓慢的后端任务。

1.1.2 HTTP

伯纳斯-李为他的万维网提出了三个组成部分:

  • HTML: 显示数据的语言
  • HTTP: 客户端-服务器协议
  • URLs: 网络资源的寻址方案

随着网络的发展,人们不断尝试,有些想法,比如 IMG 标签,在达尔文式的斗争中幸存了下来。随着需求越来越明确,人们开始认真地定义标准。

1.1.3 REST(ful)

罗伊-菲尔丁(Roy Fielding)的博士论文中有一章定义了表征状态转移(REST Representational State Transfer)--一种HTTP使用的架构风格。虽然经常被提及,但它在很大程度上被误解了。一种大致相同的RESTful已经发展起来,并在现代网络中占据主导地位。具有以下特点:

  • 使用HTTP和客户端-服务器协议
  • 无状态(每个连接都是独立的)
  • 可缓存
  • 基于资源

资源是可以区分和执行操作的数据。网络服务为其希望公开的每项功能提供一个端点--不同的URL和HTTP verb(操作)。端点也称为路由,因为它将URL路由到一个函数。

数据库用户对程序的 CRUD 缩写很熟悉:创建、读取、更新、删除。HTTP的动词也非常CRUD:

  • POST: 创建(写)
  • PUT: 完全修改(替换)
  • PATCH: 部分修改(更新)
  • GET: 获取(读取、检索)
  • DELETE: 删除

客户端向RESTful端点发送请求时,数据包含在HTTP报文的以下内容:

  • Headers
  • URL 字符串
  • 查询参数
  • Body

HTTP响应会返回以下内容:

  • 返回码:表示以下内容的整数状态代码:
    • 1xx:信息,继续
    • 2xx:成功
    • 3xx:重定向
    • 4xx:客户端错误
    • 5xx:服务器错误
  • Headers
  • Body

1.1.4 JSON和API数据格式

前端应用程序可以与后端网络服务交换纯ASCII文本,但如何表达诸如事物列表之类的数据结构呢?

就在我们开始真正需要它的时候,JavaScript Object Notation(JSON)出现了--这又是一个简单的想法,却解决了一个重要的问题,而且事后看来是显而易见的。虽然J代表JavaScript,但其语法看起来也很像Python。

JSON在很大程度上取代了XML和SOAP等。

1.1.5 JSON:API

RESTful设计与JSON数据格式的结合现在已经非常普遍。但仍有一些回旋的余地,容易产生歧义和书呆子的争论。最近提出的JSON:API提议旨在稍微收紧规范。本书将使用松散的RESTful方法,但如果有重大争议,JSON:API或类似的严格规范可能会有用。

1.1.6 GraphQL

RESTful接口对于某些用途来说可能很麻烦。Facebook(现为 Meta)设计了图形查询语言(GraphQL)来指定更灵活的服务查询。我不会在本书中介绍GraphQL,但如果你发现RESTful设计无法满足你的应用需求,你可能想了解一下GraphQL。

参考资料

1.2 并发

我们希望减少以下情况:

  • 延迟: 前期等待时间
  • 吞吐量: 服务与其调用者之间每秒的字节数

并发一词并不意味着完全并行。多重处理并不是在同一纳秒内,在单个CPU中进行的。相反,并发主要是避免繁忙等待(CPU 闲置,直到有响应为止)。CPU速度很快,但网络和磁盘的速度却要慢上几千到几百万倍。因此,每当我们与网络或磁盘对话时,我们都不希望只是坐在那里干瞪眼,直到它做出响应。

正常的Python执行是同步的:按照代码指定的顺序一次执行一件事。有时我们想要异步:做一点一件事,然后做一点另一件事,再回到第一件事,以此类推。如果我们所有的代码都使用CPU来计算(CPU 受限),那就真的没有空闲时间来做异步了。但是,如果我们执行的任务需要CPU等待外部任务完成(I/O 绑定),我们就可以采用异步方式。

异步系统提供了一个事件循环:慢速操作的请求会被发送和记录,但我们不会占用CPU来等待它们的响应。相反,每次通过循环时都会立即进行一些处理,在此期间收到的任何响应都会在下一次循环中进行处理。

这样做的效果会非常显著。在本书的后面部分,您将看到 FastAPI 对异步处理的支持如何使其比典型的Web框架更快。

异步处理并不神奇。您仍需注意避免在事件循环中执行过多的 CPU 密集型工作,因为这会减慢所有工作的速度。在本书的后面,您将看到Python的async和await关键字的用法,以及FastAPI如何让您混合同步和异步处理。

1.3 分层

  • 网络: 通过HTTP传输的输入/输出层,负责汇集客户端请求、调用服务层并返回响应

  • 服务层: 业务逻辑,在需要时调用数据层

  • 数据层: 访问数据存储和其他服务

  • 模型: 所有层共享的数据定义

  • 网络客户端:网络浏览器或其他HTTP客户端软件

  • 数据库:数据存储,通常是SQL或NoSQL服务器

各层之间通过API进行对话。这些API可以是对独立Python模块的简单函数调用,也可以通过任何方法访问外部代码。正如我前面所展示的,这可以包括RPC、消息等。在本书中,我假设只有一个Web服务器,Python代码导入其他Python 模块。分离和信息隐藏由模块处理。

用户通过客户端应用程序和API看到的是网络层。我们通常说的是 RESTful 网络接口,包括URL以及JSON编码的请求和响应。但也可以在网络层旁边构建其他文本(或命令行界面,CLI)客户端。Python Web代码可以导入服务层模块,但不应导入数据模块。

服务层包含该网站所提供服务的实际细节。这一层本质上看起来像一个库。它导入数据模块来访问数据库和外部服务,但不应该知道细节。

数据层通过文件或客户端调用其他服务为服务层提供数据访问。也可能存在其他数据层,与单个服务层通信。

模型框不是一个实际的层,而是各层共享的数据定义源。如果在这些层之间传递内置的Python数据结构,则不需要模型。正如您将看到的,FastAPI包含的Pydantic可以定义具有许多有用特性的数据结构。

为什么要进行这些划分?原因有很多,其中之一就是每一层都可以

  • 由专家编写。
  • 单独测试。
  • 替换或补充:您可能会添加第二个网络层,使用不同的应用程序接口(如 gRPC),以及网络层。

  • 客户端 ⇔ 网络: JSON的RESTful HTTP
  • Web ⇔ 服务: Models
  • 服务 ⇔ 数据: Models
  • 数据 ⇔ 数据库和服务: 特定应用程序接口

无论如何设计,这些都是要点:

  • 分离特定领域的细节。
  • 在各层之间定义标准的应用程序接口。
  • 不要作弊,不要泄密。

有时,决定哪一层是代码的最佳归宿是一项挑战。例如,第 11 章探讨了身份验证和授权要求,以及如何将其作为 Web 和服务之间的额外层或其中一层来实现。软件开发有时既是艺术,也是科学。

1.4 数据

网络通常被用作关系数据库的前端,尽管已经发展出许多其他存储和访问数据的方式,如NoSQL或NewSQL数据库。
但是,除了数据库之外,机器学习(ML)--或称深度学习或人工智能--正在从根本上重塑技术格局。开发大型模型需要对数据进行大量处理,这在传统上被称为提取、转换、加载(ETL)。

作为一种通用的服务架构,网络可以帮助解决人工智能系统的许多繁琐问题。

1.5小结

网络使用许多应用程序接口,尤其是RESTful应用程序接口。异步调用可以提高并发性,从而加快整个流程。网络服务应用程序通常规模庞大,需要分层处理。数据本身已成为一个重要领域。所有这些概念都将在下一章的Python编程语言中得到阐述。

posted @ 2024-06-05 16:49  磁石空杯  阅读(20)  评论(0编辑  收藏  举报