分布式session
原本在一台应用上的session会被放在不同的应用上,因为分布式式的原因,请求会被映射到不同的服务器上,目的是为了解决因此而产生重复登录的问题,优化用户体验,使用户无感的正常操作系统。举个例子:用户发起请求,被负载均衡器映射到A服务器上,然后又发起一次请求,被映射到B服务器上,如果没有分布式session的设计,B服务器中是没有登录信息的,难道要返回登录链接,让用户去登录吗?显然不可行的。
那么我认为只要是解决了上述的登录问题,那么就是分布式session
常用的分布式session方案有以下几种:
- session复制,通过web容器本身的发散广播协议,在局域网内对session进行复制,比如配置tomcat达到session在服务器间的复制,
缺点:有延迟,并且机器多的时候,很不方便,适用于量少的服务器,并且需要在局域网内,使用不多。 - session绑定,使用ngnix或者dubbo的负载均衡器,将同一个客户端的请求映射到同一台服务器上。
缺点:就是容易造成单点故障,如果服务器挂了,那么这台服务器上的session都会全部丢失。 - session服务器,单独提供一个服务器用于存储session信息或者登录信息,将session存储在缓存中或者DB中,重点是单独提供一个session服务,常用的方案就是基于redis的session服务器,使用sprig-session无感接入,spring-session是在创建session的时候就在redis中生成,getsession的时候,也是去redis中取,但是使用者来说是无感的。举例:登录成功后,将登录信息放在redis或者DB中,并将sessionid或者唯一标识返回,用户每次请求都带着这个标识。企业中使用最多的方案
- 客户端存储,将信息存储在cookie中
- JWT,Json Web Token。不使用session的方案,就是用户登录成功后,程序生成一个token字符串返回给客户端,客户端将token存储在cookie或者localstage中,每次请求都带着token去请求,每个服务器都有解码的逻辑,解码token就能知道用户信息了。
缺点:但是JWT的缺点就是无法控制过期时间,意思就是:服务器在发放token的时候就已经指定了过期时间,因为token存在客户端,服务器是无法控制的,如果在过期时间之前,用户修改了信息,客户端的token也无法更新,只能自己等待过期时间。
解决方案就是把token存到redis中,在redis中控制过期时间,但是这样的方案同session服务器的方案有啥区别了呢,还不如直接用session服务器的方案。
若没有网关设计,请求地址直接为目标的话,前端需要做cookie跨域的
问题,不同的浏览器地址是无法共享的,所以设置cookie的domain
进行跨域。
分布式事务
分布式锁
分布式锁,怎么理解这个分布式锁,怎么理解这个分布式锁就如同分布式session一样,传统系统的锁,是在同一台服务中,也就是说在同1个进程内,同1个进程内的东西,如果A线程上了锁,B线程去访问的时候,A线程肯定访问不了。那当应用被分布式,当两条处于不同进程内的线程去访问同一个资源,因为不在同一个进程中,所以另一个进程中的线程根本不知道你锁着呢,那怎么满足同步的需求呢?—那就是通过分布式锁来搞定。
同理,只要解决上述需求,就是分布式锁方案,有以下几种实现方案:
-
基于数据库锁定实现
看上面的描述,我们应该知道,要想达到数据的同步,就是让另一个线程知道你当前是锁定的状态。那么即使两条线程处于不同的进程,但是对于数据库的锁来说,这个锁是数据库的,已经脱离了程序,不是通过程序使用sync上的锁,而是自己的锁。
缺点:操作io,性能肯定差。 -
基于redis实现分布式锁
请看另一篇文章
缺点:首先过期时间不好控制,其次通过redis实现细节太多,但是有个专门的redission包简化了实现方式。 -
基于zookeeper实现分布式锁
基于zk实现分布式锁,是因为zk节点创建的特性,zk中的节点不能重复创建,通过创建临时节点实现分布式锁,临时节点就是当前zk会话不结束,该节点会一直存在,什么时候结束,就什么时候删除,中途有其他节点要创建的时候,只能进入阻塞。
缺点:性能不如redis实现,主要原因是写操作(获取锁释放锁)都需要在Leader上执行,然后同步到follower。所以除非你对性能有非常苛刻的要求,否则使用ZooKeeper足以,操作简单并且有较好的性能和可靠性。
基于redis或者zk两种方案在企业中,都有大量使用,要说优先那个,那就zk好了