【高可用架构】理解有状态服务和无状态服务


前言

“有状态"和"无状态” 这个两词经常会出现在一些架构设计的文章中,怎么去理解这两个的含义?这2种场景下该如何做高可用,数据一致性怎么解决?

正文

对于"状态"我个人的理解是, 对于同一时刻同一个请求产生的数据的状态数为一的则为无状态,大于一则认为有状态,至于是否允许多状态共存,取决于对一致性的要求。

从数据层面看状态

数据的状态往往受2个纬度有关,一是与时间相关或者顺序相关的,不同的操作顺序可能导致同一个时间点上的数据状态> 1个,二是与数据的副本状态相关的,数据落在多个副本上,可能出现多种数据状态的组合。

时间状态: 操作顺序有一定的限制,同一个状态的数据不能出现在2个时间点(重复请求)。

  • 如有个数据新增 ,更新,删除这3个顺序的请求,在下游业务也需要同样的顺序操作。
  • 对于单状态的数据,如计数器,不能出现重复添加,也就是这个数据只有第一次出现的时间状态是对的,后来的数据在时间状态上是不允许的,对于这种场景,往往通过把这个"点"状的数据,换成"线"数据,比如换把计数器记录成操作历史,这个点的状态由这些历史数据聚合而成,"线”数据容易做幂等操作。

位置状态 : 数据落地点的状态。

  • 数据拆分后的应用,同一个数据就有了状态,他只能落在指定的节点上。
  • 对于复制集架构,数据是存在多个副本的,也就是说数据落在的位置在集群上需要有一定的数量保证,以满足一定的共识基础,比如要写半数以上节点,也就是说这个数据是存在2个状态的,对于已经写成功的节点是成功状态,对于未写成功的节点是未成功/处理中的状态。如何协调这些状态,往往要引入一些共识协议(Paxos,Raft)。

从服务层面看状态

服务层面的状态取决于实例是单独维护数据还是共享数据,或者说是否存在多个数据闭环让数据的流向产生了多条路径。有状态的服务往往比较难进行水平拓展,在现在容器盛行的环境,把服务设计成无状态的更加高效,即便是有状态的服务,也要将状态内敛在系统的某个范围,比如分布式的存储,对于业务服务,我不需要关系数据在多个副本的状态,数据的状态由分布式存储这个服务本身解决。

有状态服务

  • 服务本身依赖或者存在局部的状态数据,这些数据需要自身持久化或者可以通过其他节点恢复。
  • 一个请求只能被某个节点(或者同等状态下的节点)处理。
  • 存储状态数据,实例的拓展需要整个系统参与状态的迁移。
  • 在一个封闭的系统中,存在多个数据闭环,需要考虑这些闭环的数据一致性问题。
  • 通常存在于分布式架构中。

无状态服务

  • 服务不依赖自身的状态,实例的状态数据可以维护在内存中。
  • 任何一个请求都可以被任意一个实例处理。
  • 不存储状态数据,实例可以水平拓展,通过负载均衡将请求分发到各个节点。
  • 在一个封闭的系统中,只存在一个数据闭环。
  • 通常存在于单体架构的集群中。

怎么做转换

  1. 采用复制或者集中式消除数据状态。

  • 对于Web服务,如果数据存在session中,那么这个服务就有了状态。
  • 一种是对session进行复制,同步复制还是异步复制,取决于你对数据一致性的敏感程度。
  • 也可以将session集中式管理,如用redis,出现性能或者容量的瓶颈,再换分布式的缓存,把状态交于缓存服务维护。
  • 我们可以看出,有状态的服务,它的数据是存在多个闭环的,比如Web01-session-01-> DB 和 Web02-session->DB 。通过复制,将session-01 和 02 等同于同一个。
  • 或者我们可以将数据进行分区,让负载均衡器通过hash算法将请求落在固定的处理节点上。
  1. 采用控制节点来保证集中式存储的高可用和一致性。

  • 在高可用的架构下,数据往往得存在多副本(鸡蛋别放一个篮子里面)
  • CAP理论,C和A不可能同时满足,多副本的存在让A可在有限时间内恢复,而C可用采用Quorum 机制来控制多个副本节点的数据一致性问题,保证半数以上的节点的写成功。