Cookie、会话和持久性

介绍

HTTP(超文本传输协议)旨在支持从服务器到客户端的无状态、请求-响应模型传输数据。 它的第一个版本 1.0 支持纯 1:1 的请求与连接比率(即每个连接支持一个请求-响应对)。

1.1 版将该比例扩展为 N:1,即每个连接有许多请求。 这样做是为了解决网页日益复杂的问题,包括需要从服务器传输到客户端的许多对象和元素。

随着 2.0 版本的采用,HTTP 继续支持每个连接多个请求的模型。 其最根本的变化涉及标题的交换以及从基于文本的传输到二进制的转变。

在某种程度上,HTTP 不再只是一种将文本和图像从服务器传输到客户端的简单机制,它成为了应用的平台。 浏览器的普遍性、跨平台特性以及应用的轻松部署而无需支持多种操作系统和环境的高昂成本无疑具有吸引力。 不幸的是,HTTP 并不是被设计为应用传输协议。 它被设计用于传输文件。 即使是 HTTP 的现代用途(例如 API)也假定具有类似文档的有效负载。 一个很好的例子是 JSON,一种以文本形式传输的键值对数据格式。 虽然文档和应用协议通常是基于文本的,但相似之处仅此而已。

传统应用需要某种方式来维持其状态,而文档则不需要。 应用建立在逻辑流程和过程之上,这两者都要求应用知道用户当时在哪里,并且需要状态。 尽管 HTTP 本质上具有无状态的特性,但它已经成为 Web 事实上的应用传输协议。 HTTP 无疑是技术史上最广泛接受、最有用的黑客技术之一,它提供了一种在应用使用过程中跟踪状态的方法。 这种“黑客攻击”就是会话和 cookie 发挥作用的地方。

会议
将无状态转变为有状态

会话是 Web 和应用服务器维护状态的方式。 这些简单的内存块与到 Web 或应用服务器的每个 TCP 连接相关联,并作为基于 HTTP 的应用中的信息的内存存储。

当用户第一次连接到服务器时,就会创建一个会话并与该连接相关联。 然后,开发人员使用该会话作为存储与应用程序相关的数据的地方。 这些数据可以是重要信息(例如客户 ID)也可以是不太重要的数据(例如您喜欢如何显示网站首页)。

会话实用性的最好例子就是购物车,因为几乎我们所有人都曾经在网上购物过。 购物车中的商品在“会话”过程中保持不变,因为购物车中的每个商品都会以某种方式在服务器的会话中呈现。 另一个很好的例子是向导式的产品配置或定制应用。 这些“迷你”应用使您能够浏览一组选项并选择它们;最后,您通常会对所添加的所有花哨功能的估计成本感到震惊。 当您点击每个“选项屏幕”时,您选择的其他选项将存储在会话中,以便您可以轻松地检索、添加或删除它们。

现代应用设计为无状态,但其架构可能不符合该原则。 现代的扩展方法通常依赖于分片等架构模式,这需要根据一些可索引数据(如用户名或帐号)来路由请求。 这需要一种有状态的方法,其中可索引数据随每个请求一起携带,以确保正确的路由和应用程序行为。 在这方面,现代“无状态”应用和 API 通常需要与有状态的前辈类似的关注和支持。

问题在于会话与连接相关,而连接闲置的时间过长。 此外,连接“太长”的定义与会话“太长”的定义有很大不同。 例如,某些 Web 服务器的默认配置是,一旦连接处于空闲状态(即 15 秒内没有发出任何请求),就会关闭连接。 相反,这些 Web 服务器中的会话默认会在内存中保留 300 秒,即 5 分钟。 显然两者是互相矛盾的,因为一旦连接超时,如果会话与连接相关联,那么会话还有什么用呢?

您可能认为只需增加连接超时值来匹配会话并解决这种差异即可。 增加超时时间意味着您可能会消耗内存来维持可能使用或可能不使用的连接。 这会降低服务器的总并发用户容量,并最终影响其性能。 而且您肯定不想减少会话超时来匹配连接超时,因为大多数人要花五分钟以上的时间货比三家或定制他们的新玩具。

 

重要提示: 虽然 HTTP/2 解决了其中一些问题,但它引入了与维护状态相关的其他问题。 虽然规范没有要求,但主流浏览器只允许通过 TLS/SSL 运行 HTTP/2。 两种协议都需要持久性以避免重新协商的性能成本,而这又需要会话意识,又称为有状态行为。

 

因此,最终的结果是,即使会话相关的连接由于不活动而终止,这些会话仍然作为内存保留在服务器上,从而消耗宝贵的资源,并可能激怒那些无法使用您的应用的用户。

幸运的是,这个问题可以通过使用 cookie 得到解决。

Cookie
面包屑的踪迹引领我们回家

Cookie 是浏览器存储在客户端上的一些数据。 Cookies 可以存储有关您、您的应用以及您所访问的网站的各种有趣的信息。 “cookie”一词源于“magic cookie”,这是 UNIX 计算中一个著名的概念,它启发了这个想法和名字。 Cookie 通过 HTTP Header、Cookie 在浏览器和服务器之间创建和共享。

 

  曲奇饼: JSESSIONID=9597856473431 缓存控制:无缓存 主机: 127.0.0.2:8080 连接: 保持活动
 

浏览器自动知道它应该将 cookie 存储在计算机上的文件中 HTTP 标头中,并且它会根据每个域跟踪 cookie。 任何给定域的 cookie 总是由浏览器在 HTTP 标头中传递到服务器,因此 Web应用的开发人员只需在应用的服务器端请求即可检索这些值。

会话/连接长度问题通过 cookie 解决。 几乎所有现代网络应用都会生成一个“会话 ID”并将其作为 cookie 传递。 这使得应用即使在创建会话的连接关闭后也能够在服务器上找到该会话。 通过这种会话 ID 的交换,即使对于像 HTTP 这样的无状态协议也可以维持状态。 但是,当 Web应用的使用超出了单个 Web 或应用服务器的能力时,会发生什么情况呢? 通常会引入负载平衡器(或在当今架构中引入应用交付控制器 (ADC))来扩展应用,以便所有用户都对可用性和性能感到满意。

在现代应用中,可能仍会使用 cookie,但其他 HTTP 标头变得至关重要。 用于身份验证和授权的 API 密钥通常通过 HTTP 标头传输,以及其他携带路由和后端服务适当扩展所需数据的其他自定义标头。 是否使用传统的“cookie”或某些其他 HTTP 标头来携带这些数据并不重要,重要的是认识到它对整体架构的重要性。

问题在于负载均衡算法通常仅关注在服务器之间分配请求。 负载均衡技术基于行业标准算法,例如循环、最少连接或最快响应时间。 它们都不是有状态的,并且同一个用户对应用的每个请求可能会分发到不同的服务器。 这使得为实现 HTTP 状态所做的所有工作都变得毫无用处,因为存储在一个服务器的会话中的数据很少与“池”中的其他服务器共享。

这就是持久性概念发挥作用的地方。

坚持不懈
束缚的纽带

持久性(也称为粘性)是 ADC 实施的一种技术,用于确保来自单个用户的请求始终分发到其启动的服务器。 一些负载均衡产品和服务将这种技术描述为“粘性会话”,这是一个完全恰当的绰号。

持久性长期以来一直用于对启用 SSL/TLS 的站点进行负载均衡,因为一旦协商过程(计算密集型过程)完成并交换密钥,重新启动该过程将显著降低性能。 因此,ADC 实施了 SSL 会话持久性,以确保用户始终被定向到他们首次连接的同一服务器。

多年来,浏览器实现需要开发一种技术来避免昂贵的重新协商这些会话。 这种技术被称为基于 cookie 的持久性。

负载均衡器不会依赖 SSL/TLS 会话 ID,而是在客户端第一次访问站点时插入一个 cookie 来唯一地标识会话,然后在后续请求中引用该 cookie 以保持与适当服务器的连接。

基于 cookie 的持久性概念从此被应用于应用会话,使用由 Web 和应用服务器生成的会话 ID 信息来确保在同一会话期间用户请求始终被定向到同一服务器。 如果没有此功能,需要负载均衡的应用将需要找到另一种方式来共享会话信息,或者增加会话和连接超时时间,以至于支持其用户群所需的服务器数量将迅速增长到难以管理的程度。

尽管最常见的持久性形式是使用 HTTP 标头中传递的会话 ID 来实现的,但如今的 ADC 也可以持久保存在其他数据上。 任何可以存储在 cookie 中或从 IP、TCP 或 HTTP 标头中派生的数据均可用于持久会话。 事实上,智能 ADC 可以使用应用消息中任何唯一标识用户的数据来维持浏览器和服务器之间的连接。

结论

HTTP 可能是一种无状态协议,但我们已经设法将状态强制融入到无处不在的协议中。 使用持久性和应用交付控制器,可以构建高可用性、高性能的 Web应用,而不会破坏维持状态所需的 cookie 和会话的脆弱集成。

这些特性赋予了 HTTP 状态,尽管它的实现和执行仍然是无状态的。 如果没有 cookie、会话和持久性,我们肯定会找到一个有状态的协议来构建我们的应用。 相反,应用交付控制器中的特性和功能在浏览器(客户端)和服务器之间进行调解以提供此功能,将 HTTP 的用途从静态网页和传统应用扩展到现代基于微服务的架构和数字经济宠儿 API。

2018 年 1 月 19 日发布
  • 分享至 Facebook
  • 分享到X
  • 分享至 Linkedin
  • 分享至电子邮件
  • 通过 AddThis 分享

通过 F5 进行连接

F5 实验室

最新的应用威胁情报。

DevCentral

F5 社区,提供讨论论坛和专家文章。

F5 新闻中心

新闻、F5 博客等等。