分布式系统CAP理论与分布式会话

1 CAP 概念

在分布式系统中,必定会遇到 CAP,如:

  • C(Consistency):一致性
    • 在分布式系统中,所有的计算机节点的数据在同一时刻都是相同的,数据都是一致的,不能因为分布式导致不同系统拿到的数据不一致。也就是说,用户在某个节点写了数据,在其它节点获得该数据的值是最新的;
  • A(Availability):可用性
    • 保证系统可用,也就是无论什么时候,系统都应该被用户访问到,用户可以获得正常的响应结果(阻塞也不允许)。比如做好集群、做好主备等等,这就是高可用。
  • P(Partition tolerance):分区容错性
    • 在整个发布式系统,都是部署到不同的节点上,或是不同的机房甚至不同的地域,某些服务会部署在不同的子网,每个子网就是一个区,也就是网络分区,分区之间的通信也有可能出现通信故障。当某个节点、区域、分区出现问题,整个系统还是能够提供一致性和可用性的服务。

1.1 CAP 无法同时满足

如果从理论上来讲,以上三点都应该满足,但在分布式系统中同时满足这三点不可能,所以对于 CAP 来讲,只能满足其中两者,要么 AP,要么 CP,要么 CA。
举例说明一下为什么CAP不能同时满足:
在这里插入图片描述
上图,ABCDE这5个节点都是分别部署在不同地域的机房的节点,假设现在我们的分区容错性 P 做的很好,保证不会出现网络方面的故障,这个时候看一下一致性 C 和可用性 A,如果此时一个请求把数据写到 A 点,随后又有请求从 B 节点,那么由于他们之间在不同的地域,数据的同步有时间延迟,可能几百毫秒可能几秒。

  • 如果此时要满足数据的一致性 C,那么请求就可能会被阻塞,而阻塞就表示当前系统不可用,即此时就是满足了 CP,就无法满足 A
  • 如果此时要满足系统的可用性 A,那么请求到的数据就可能达不到一致性 C,即此时就是满足了 AP,就无法满足 C
  • 如果不满足 P,即所有分布式系统都在同一内网内,避免了输送数据同步的时间延迟等问题,便可以满足 AC

对于 CP、AP、CA 这三种,平时开发的时候,要如何选择?
首先 P 分区容错是一定满足的,因为我们在部署的时候往往都是多节点集群部署,设置异地互备。

那么接下来就要抉择一致性 C 和可用性 A
主流的互联网公司会采取 AP,也就是 数据的弱一致性,因为很多数据没必要强一致性。都是要注意,数据层面的交互,关系型数据库,Redis,mongodb等,它们肯定是强一致性,因为需要提供给你的网站数据服务。

2 会话

会话代表的是客户端与客户端的一次交互过程,这个过程可以是连续也可以是时断时续。

2.1 无状态会话

Http 请求时无状态的,用户向服务端发起多个请求,服务端并不会知道这多次请求都是来自同一用户,这个就是无状态的。cookie 的出现就是为了有状态的记录用户。
常见的,ios与服务端交互、前后端分离、小程序与服务端交互,他们都是通过发起 Http 来调用接口数据。每次交互服务端都不会拿到客户端的状态,但是我们可以通过手段处理,比如每次用户发起请求的时候携带一个 userIduser-token,如此一来,就能让服务端根据 userIduser-token 来获取相应的数据。每个用户的下一次请求都能被服务端识别来自同一个用户。

2.2 状态会话

Tomcat 中的会话,就是有状态的,服务器 tomcat 会为用户创建一个 session,同时前端会有一个 jsessionid,每次交互都会携带。如此一来,服务器只要在接到用户请求时,就可以拿到 jsessionid,那么此时就可以操作会话了。

@GetMapping("/setSession")
public Object setSession(HttpServletRequest request) {
	HttpSession session = request.getSession();
	session.setAttribute("userInfo", "userMsg");
	session.setMaxInactiveInterval(3600);
	session.getAttribute("userInfo")
	return "ok";
}

2.3 集群分布式系统会话

集群或分布式系统本质都是多个系统,假设这个里有两个服务器节点,分别是 A、B 系统,它们可以是集群,也可以是分布式系统,一开始用户和 A 系统交互,那么这个时候的用户状态,我们可以保存到 Redis 中,作为 A 系统的会话信息,随后用户的请求进入到 B 系统,此时 B 系统的会话可以和 Redis 关联,如此一来 A、B 系统的会话就统一了。那么这个其实就是分布式会话,通过 Redis 来保存用户的状态。

2.4 SpringSession

除了每次直接操作 Redis 从而达到集群分布式会话,还可以使用 SpringSession 实现分布式会话。
导入 SpringSession 依赖:

<dependency>
	<groupId>org.springframework.session</groupId>
	<artifactId>spring-session-data-redis</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-security</artifactId>
</dependency>

配置 yml 文件,设置 session 存储类型:

spring:
	session:
		store-type: redis

然后在启动类 Application 文件中添加以下注解,开启 HttpSession 使用 Redis,同时去除安全自动装配(否则每次请求都需要输入密码)

/**
 * 开启 Redis 作为 SpringSession
 */
@EnableRedisHttpSession
/**
 * 去除安全自动装配,负责使用 SpringSession 而导入的SpringBoot安全依赖
 * 会导致前端那边每次使用都要输入密码
 */
@SpringBootApplication(exclude = {SecurityAutoConfiguration.class})

然后使用 SpringSession 的操作与普通使用 Session 的操作一致

@RestController
@RequestMapping("test")
public class TestController {
    @GetMapping("setSession")
    public ServerResponse setSession(HttpServletRequest request, HttpServletResponse reponse) {
        HttpSession session = request.getSession();
        session.setAttribute("title","content");
        return ServerResponse.createdBySuccess(session.getAttribute("title"));
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值