使用 Apache APISIX 实现粘性会话
粘性会话(也称为会话亲和性)是一种机制,它确保作为外观模式的路由组件始终将请求路由到同一个底层上游节点。本文将介绍粘性会话背后的原理、可用的替代方案以及如何通过 Apache APISIX 实现它们。
为什么需要会话粘性?
当我们把状态存储在上游节点而不是数据库中时,粘性会话就变得流行起来。我将以一个简化的电子商务商店为例来进一步解释。
小型电子商务网站的基本架构可以包括一个网络应用程序和一个数据库。
如果业务成功,它就会发展壮大,而你迟早需要扩展这个架构。一旦无法进行垂直扩展(使用更强大的机器),就必须进行水平扩展(增加节点)。随着应用节点的增加,你还需要在 Web 应用节点前面部署负载均衡器,以便在它们之间分配负载。
每次都访问数据库是一项开销很大的操作。对于访问频率不高的数据来说,这尚可接受。但是,我们希望每次请求都能显示购物车的内容。有几种方法可以提高速度。假设 Web 应用使用服务器端渲染 (SSR),那么传统的解决方案是将购物车相关数据存储在 Web 应用节点的内存中。
但是,如果我们把用户 X 的购物车存储在节点 1 上,就需要确保将用户 X 的每个请求都转发到同一个节点。否则,他们会感觉购物车里的商品丢失了。粘性会话(或会话亲和性)就是将同一用户始终路由到同一节点的机制。
粘性会话的限制
在深入探讨之前,我必须先解释一下粘性会话的一个重大局限性。如果存储数据的 Web 应用程序节点因任何原因宕机,数据将永久丢失。对于上述电子商务场景,这意味着用户偶尔会丢失购物车中的商品,这从商业角度来看是不可接受的。
因此,粘性会话必须与会话复制相结合:存储在节点上的数据必须被复制,并与其他所有节点保持同步。
虽然所有技术栈都存在会话复制,但并没有相关的规范。我对 JVM 比较熟悉,所以这里提供几种方案:
- Tomcat 提供开箱即用的会话复制功能。
- Hazelcast提供了一种集群式内存解决方案,您可以将其集成到不同层级。
- Spring Session是特定解决方案之上的一个抽象层。
当数据复制到所有节点(或远程集群)时,您可能会认为不再需要粘性会话。如果仅考虑可用性而不考虑性能,这种说法是正确的。但关键在于数据本地性:在当前节点上获取数据比通过网络从其他位置获取数据要快得多。
Apache APISIX 上的粘性会话
对于任何合格的负载均衡器、反向代理和 API 网关来说,会话保持功能都是必不可少的。不过,我必须承认,Apache APISIX 的文档确实需要一个更易于理解的入门指南。
Apache APISIX 将路由绑定到上游节点。上游节点由一个或多个节点组成。当请求与路由匹配时,Apache APISIX 必须从所有可用节点中选择一个来转发请求。默认情况下,算法是加权轮询。轮询算法会依次使用每个节点,并在使用完最后一个节点后返回到第一个节点。在加权轮询中,权重会影响 Apache APISIX 在切换到下一个节点之前将多少请求转发到该节点。
然而,还有其他算法可用:
- 一致性哈希
- 指数加权移动平均线图
- 最少连接
- 定制的
一致性哈希允许根据某些值(例如 NGINX 变量、HTTP 标头、cookie 等)将请求转发到同一节点。
请记住,HTTP 是一个无状态协议,因此应用服务器会在首次响应时设置一个 cookie,以便在 HTTP 请求之间跟踪用户。这就是我们所说的“会话”。我们需要知道底层会话 cookie 的名称。不同的应用服务器会发放不同的 cookie:
JSESSIONID适用于基于 JVM 的服务器PHPSESSID适用于 PHPASPSESSIONID适用于 ASP.NET- ETC。
我将使用常规的 Tomcat,因此会话 cookie 为JSESSIONID。以下是 Apache APISIX 中关于双节点部署的文档:
routes:
- uri: /*
upstream:
nodes:
"tomcat1:8080": 1 #1
"tomcat2:8080": 1 #1
type: chash #2
hash_on: cookie #3
key: cookie_JSESSIONID #4
- 定义上游节点
- 选择一致性哈希算法
- cookie 上的哈希
- 定义要对哪个 cookie 进行哈希处理。
结论
在这篇文章中,我们详细介绍了粘性会话,您应该始终将会话复制与粘性会话一起使用,以及如何在 Apache APISIX 上实现粘性会话。
更进一步:
原文发表于A Java Geek网站,日期为2023 年6 月 25日。
文章来源:https://dev.to/apisix/sticky-sessions-with-apache-apisix-3l03

