Cookie、会话和持久性
简介
HTTP(超文本传输协议)旨在支持一种无状态的请求-响应模型,用于将数据从服务器传输到客户端。其首个版本1.0仅支持1:1的请求与连接比率(即每个连接支持一组请求-响应)。
1.1版将这一比例扩展为N:1,即每个连接可处理多个请求。此项改进旨在应对网页日益增加的复杂性,包括需要从服务器传输到客户端的大量对象和元素。
随着HTTP 2.0的采用,HTTP继续支持每个连接处理多个请求的模式。其最显著的变化涉及标头交换,并将传输方式从文本改为二进制。
不知从何时起,HTTP不再只是将文本和图像从服务器传输到客户端的简单机制,而是成为了应用平台。浏览器的普及、跨平台特性,以及无需承担支持多种操作系统和环境的高昂成本即可轻松部署应用,这些优势无疑极具吸引力。但遗憾的是,HTTP并非为用作应用传输协议而设计,而是为传输文档而设计。即使是API等HTTP的现代用途,也假定有效负载采用类似文档的形式。JSON就是一个典型示例,它是一种以文本形式传输的键值对数据格式。虽然文档和应用协议通常都基于文本,但二者的相似之处也仅限于此。
传统应用需要通过某种方式维护状态,而文档则不需要。应用基于逻辑流和流程构建,两者都要求应用了解用户当前所处的环节,因此需要维护状态。尽管HTTP本质上是无状态的,但它已成为Web事实上的应用传输协议。通过技术史上一种广受认可且实用的变通方法,HTTP获得了在应用使用过程中跟踪状态的能力。会话和Cookie正是在这种“变通方法”中发挥作用。
会话
将无状态转变为有状态
会话是Web服务器和应用服务器维持状态的方式。这些简单的内存块与连接到Web服务器或应用服务器的每个TCP连接相关联,并作为基于HTTP的应用中信息的内存存储空间。
当用户首次连接到服务器时,系统会创建一个会话,并将其与该连接关联。随后,开发人员会使用该会话存储与应用相关的数据。这些数据既可以是客户ID等重要信息,也可以是网站首页显示偏好等相对次要的信息。
购物车是体现会话用途的典型示例,因为几乎每个人都曾有过网购经历。购物车中的商品会在整个“会话”期间保留,这是因为购物车中的每件商品都会以某种形式记录在服务器上的会话中。另一个典型示例是向导式产品配置或定制应用。这些“小型”应用可供您浏览并选择一组选项;到最后,添加的各种附加功能往往会让预估费用高得出人意料。逐一浏览各个“选项页面”时,之前选择的其他选项会存储在会话中,以便轻松检索、添加或删除。
现代应用在设计上采用无状态模式,但其架构可能并不符合这一原则。现代扩展方法通常依赖分片等架构模式,而分片需要根据用户名或账号等可索引数据来路由请求。这就需要采用某种有状态方法,即每个请求都携带可索引数据,以确保正确路由和应用行为。因此,现代“无状态”应用和API通常需要像其有状态前身一样进行类似的维护和管理。
问题在于,会话与连接绑定,而连接闲置时间过长就会超时。此外,连接和会话对“时间过长”的定义也大不相同。例如,某些Web服务器的默认配置是:连接闲置15秒(即在此期间未再发出请求)后将其关闭。相比之下,这些Web服务器中的会话默认会在内存中保留300秒,即5分钟。显然,两者相互冲突,因为连接一旦超时,与其关联的会话也就失去了意义。
您可能会认为,只需增大连接超时值,使其与会话超时值一致,就能解决这种差异。但延长超时时间可能会占用内存来维持一个不一定会被使用的连接。这可能会降低服务器可支持的并发用户总数,并最终影响其性能。当然,也不应缩短会话超时时间来与连接超时时间保持一致,因为大多数人选购商品或定制新产品所需的时间都不止5分钟。
重要说明:虽然HTTP/2解决了其中一些问题,但也带来了与状态维护相关的其他问题。尽管规范并未要求,但主流浏览器仅允许通过TLS/SSL使用HTTP/2。这两种协议都需要持久连接,以避免重新协商带来的性能开销,而这又要求具备会话感知能力,也就是有状态行为。
因此,即使关联连接因不活动而终止,会话仍会驻留在服务器内存中,占用宝贵资源,还可能导致应用无法正常使用,令用户不满。
好在,使用Cookie可以解决这个问题。
Cookie
循着 Cookie 的踪迹找到源头
Cookie是浏览器存储在客户端上的少量数据。Cookie可以存储并且确实存储了与您、您的应用以及您访问的网站有关的各种有趣信息。“cookie”一词源自“magic cookie”,这是UNIX计算领域的一个知名概念,Cookie的理念和名称均由此而来。Cookie通过HTTP标头Cookie在浏览器与服务器之间创建和共享。
Cookie: JSESSIONID=9597856473431 Cache-Control: no-cache Host: 127.0.0.2:8080 Connection: Keep-Alive
浏览器会自动将HTTP标头中的Cookie存储到计算机上的文件中,并按域跟踪Cookie。浏览器始终会通过HTTP标头将指定域的Cookie传递给服务器,因此Web应用程序开发人员只需在应用程序的服务器端请求这些值,即可将其检索出来。
会话和连接的持续时间问题可通过Cookie解决。几乎所有现代Web应用都会生成“会话ID”,并将其作为Cookie传递。这样,即使创建会话时使用的连接已关闭,应用仍可在服务器上找到该会话。通过交换会话ID,即使HTTP这类无状态协议也能维持状态。但是,当Web应用的使用规模超出单台Web服务器或应用服务器的处理能力时,该怎么办?通常会引入负载均衡器,在当今的架构中则会引入应用交付控制器(ADC),以扩展应用,满足所有用户对可用性和性能的需求。
在现代应用中,虽然仍可使用Cookie,但其他HTTP标头也变得至关重要。用于身份验证和授权的API密钥通常通过HTTP标头传输,其他自定义标头也会携带后端服务进行路由和适当扩展所需的数据。无论使用传统的“Cookie”还是其他HTTP标头来携带这些数据,更重要的是认识到这些数据对整体架构的重要性。
问题在于,负载均衡算法通常只关注如何将请求分发到各服务器。负载均衡技术基于轮询、最少连接或最快响应时间等行业标准算法。这些算法都不具备状态感知能力,因此同一用户向应用发出的每个请求都可能被分发到不同的服务器。这样一来,为HTTP实现状态所做的工作便失去了意义,因为存储在一台服务器会话中的数据很少会与“池”中的其他服务器共享。
这正是持久性概念发挥作用之处。
会话保持
维系纽带
持久性(也称为粘性)是ADC采用的一项技术,用于确保来自同一用户的请求始终分发到最初处理这些请求的服务器。一些负载均衡产品和服务将这项技术称为“粘性会话”,这个名称十分贴切。
Persistence has long been used in load balancing SSL/TLS-enabled sites because once the negotiation process—a compute intensive one—has been completed and keys exchanged, it would significantly degrade performance to start the process again. Thus, ADCs implemented SSL session persistence to ensure that users were always directed to the same server to which they first connected.
多年来,浏览器的实现方式促使业界开发出一种技术,以避免对这些会话进行代价高昂的重新协商。这项技术称为基于Cookie的持久性。
Rather than rely on the SSL/TLS session ID, the load balancer would insert a cookie to uniquely identify the session the first time a client accessed the site and then refer to that cookie in subsequent requests to persist the connection to the appropriate server.
此后,基于cookie的持久性概念被应用于应用会话,利用Web服务器和应用服务器生成的会话ID信息,确保同一会话期间的用户请求始终定向到同一台服务器。如果没有此功能,需要负载均衡的应用必须另寻方法共享会话信息,或者延长会话和连接超时时间,最终导致支持其用户群所需的服务器数量迅速增长到难以管理的程度。
虽然最常见的会话保持方式是使用HTTP标头中传递的会话ID来实现,但如今ADC也可以根据其他数据实现会话保持。任何可存储在Cookie中或从IP、TCP或HTTP标头中提取的数据,都可用于保持会话。事实上,应用消息中任何能够唯一标识用户的数据,都可供智能ADC用于保持浏览器与服务器之间的连接。
结论
HTTP或许是一种无状态协议,但我们已设法将状态机制融入这一无处不在的协议。借助持久性和应用交付控制器,可以构建高可用、高性能的Web应用,同时避免破坏为维持状态所需但较为脆弱的Cookie与会话集成。
正是这些功能让HTTP具备了状态,尽管其实现和执行过程仍然是无状态的。如果没有Cookie、会话和持久性,我们很可能会采用某种有状态协议来构建应用。Application Delivery Controller中的特性和功能则在浏览器(客户端)与服务器之间发挥协调作用,提供这种能力,使HTTP不再局限于静态网页和传统应用,还可用于现代微服务架构以及数字经济中备受青睐的API。
发布于2018年1月19日
