1.分布式session问题:
因为在分布式系统中,服务器集群,同一服务通常会放在几台不同的服务器中,当浏览器第一次发来请求或原session已经失效时,会在服务器端创建session,并将sessionId放在响应头中返回浏览器保存在cookie。当浏览器第二次访问时,会带着sessionId在服务器中查找session,虽然两次访问的网址相同,但是请求可能打到两个不同的tomcat上,这样第二次请求找不到之前的session。这个问题有以下5种解决方法:
使用数据库进行session共享
使用redis进行session,k,v分别是sessionId,session,该方法已经集成在springboot中,在redis配置类上加@EnableRedisHttpSession
使用token加session,token和session都是临时且唯一的,redis的k,v分别是token,session
使用tomcat自带的session同步工具,但是效果不好有延时
在网关层做ip hash操作,确保相同ip的请求可以打到相同的tocmat
2.分布式跨域问题:
前端页面的ajax请求在访问当前页面所在的系统的服务接口时,不会发生任何问题,但是在访问系统的页面时,可以将请求成功发出去,也可以成功返回,但浏览器不会允许展示,这个问题有4种解决办法:
在响应头中加“access-control-allow-origin”
用nginx或zuul反向代理,请求全都打到反向代理服务器,在通过反向代理服务器发请求,并返回给ajax,在浏览器看来都是同一个系统
用jsonp,将ajax的type设置jsonp,但是jsonp只能支持get请求
ajax打到本系统的某接口,在通过这个接口封装httpclient或其他rpc框架发请求
3.分布式任务调度:
系统中都会有定时任务,当同一服务被部署到多台不同服务器后,同一定时任务就会被被执行多次,比如定时进行redis备份,那么redis就会被备份多份,这显然是不对的。
通过使用xxl-job调度中心进行统一调度,保证同一时间相同任务只有一个被执行。
4.分步式事物:
一个方法A改了自己的数据库,成功后,又通过rpc发请求给另一个服务B改B的数据库,也成功,返回true,结果网断了,A没收到B的响应,超时之后,A数据库回滚,B不动,这样就违反一致性。
用lcn框架解决,lcn是国人开发,核心思想是“不生产事物,只做本地事物搬运工”,采用2pc协议,也就是当两个数据库都操作完成并成功后,都会给lcn发信号,这时lcn在同一commit,否则lcn统一rollback
5.分布式幂等性:
例如表单重提交问题,应该提交多次只有一次起作用,在传统系统中,多次提交会打到统一接口,可以再接口内部进行请求去重,但是在分布式系统中,多次提交可能打到不同服务器上,不能再按照之前的方法去重
解决方法:用aop做请求拦截,在前置通知中,判断过来的请求头中是否有token,如果有放行,如果没有,采用uuid+时间戳的方式,基于分布式锁生成全局唯一token,加到请求头中,在将token存放到redis,放行。请求到达环绕通知,首先判断请求头中的
token在redis能否查到,如果能,删除redis的token,执行请求接口。如果redis中没有对应的token,说明请求是第二次或多次调用,拦截。
6.分布式锁:
当多个线程同时对一个变量进行读写操作,就会产生线程安全问题,但是传统的synchronized对其他系统的线程是不可见的,所以需要一个对所有服务所有线程都可见的锁。
三中解决方法:基于数据库,基于redission,基于zookeeper。在zookeeper约定好的路径下建临时节点,同一时间只有一个线程能建立成功,并且在删除之前都不能创建相同路径的节点,定义watch可监听节点的删除操作,删除后其他节点能及时得到通知
而不用轮巡的尝试创建锁。在这提一下java的一个基础知识,synchronized和lock的区别,lock有tryLock方法,可以尝试创建锁,并拿到返回值,lock能够知道当前有没有锁,并进行处理,而synchronized在不能加锁的时候阻塞住,直到能加锁为止。zookeeper
分布式锁类似lock,在创建临时节点的时候,创建成功和失败都会有返回值。
redission方式:redission和ReentantLock是唯二的两个实现了lock接口的类,reentantlock是重入锁,redission是分布式锁,用法和lock相同,是基于redis实现的。
网友评论