分布式集群的无状态化

HTTP

众所周知,HTTP 是无状态的,何谓无状态呢,指的是 HTTP 本质上是由一个请求和一个响应组成,客户端发起一个请求,服务端提供一个响应。在服务端来看,所有发起的请求除了 URL 有所不同之外,其余的应该是无区别的,因而视为无状态。

COOKIE

然而,当多个用户发起请求时,必须区分出各个用户,此时状态又是有必要的,为了解决这个问题,引入了 COOKIE 的概念。COOKIE 是以键值对存储在客户端本地的,当用户发起请求时,浏览器自动带上 COOKIE,也因此使得 HTTP 从服务端视野来看,具有一定的状态。

SESSION

又因为 COOKIE 存储在客户端本地,通常被视为不安全的,又引入了 SESSION 的概念。SESSION 是存储在服务端的,以客户端上的一个随机 SESSIONID(COOKIE)作为索引,客户端请求时带上 SESSIONID,服务端根据 SESSIONID 从本地(服务端)匹配到对应的 SESSION。

URL

由 SESSION 的特性我们可以知道,如果浏览器禁用了 COOKIE,那么 SESSION 也是无效的,那么在这种情况下,我们如何去区分用户状态呢?通常采用的办法是,将用户该状态所对应的 TOKEN 附加到用户每个请求的 URL 后,以 TOKEN 来区分用户状态。当然,很多时候这个 TOKEN 就是用户的 SESSIONID。

分布式

由上可知,在分布式集群中,当用户请求按照一定规则分发到不同子机时,请求一定携带有 COOKIE,而 SESSION 因为其本身存储在服务器,并不能便捷地同步。

为了解决这个问题,能采用的方案无非几种:

  1. 使用 COOKIE 代替 SESSION;
  2. 将 SESSION 使用分布式的 NoSQL 代替(如Redis等);
  3. 使用加密的 COOKIE 来验证,如果 COOKIE 有效,则重建 SESSION;
  4. 调整分布式分发策略,将固定用户的请求分发到固定子机;

目前在我部署的分布式集群中,采用的是1、2方案并行的策略。

3 方案非常有效,常用于异地系统的多点登陆,即机器不在一个集群中。

使用 Redis 来保存 SESSION,可以使用配置文件修改,也可以使用 ini_set() 来设置:

ini_set("session.save_handler", "redis");
ini_set("session.save_path", "tcp://localhost:6379");

解决了这个 HTTP 状态化的问题之后,只需要将SQL、NoSQL、静态资源从运算集群中分离出来,开发时就无须太在意代码层面关于分布式的特殊设计了。

共有 0 条评论

Top