1.dubbo工作原理
1)service层:接口层,给服务提供者和消费者来实现。
2)config层:配置层,主要是对dubbo进行配置的
3)proxy层:代理层,透明生成生成客户端的stub和服务单的skeleton
4)registry层:服务注册层,负责服务的注册和发现
5)cluster层:集群层,封装多个服务提供者的路由以及负载均衡,将多个实例组合成一个服务
6)monitor层:监控层,对rpc接口的调用次数和调用时间进行监控
7)protocol层:远程调用层,封装rpc调用
8)exchange层:信息交换层,封装请求相应模式,同步装异步
9)transport层:网络传输层,抽象mina和netty为统一接口
10)serialize层:数据序列化层
2.dubbo的工作流程
1)provider向注册中心去注册
2)consumer从注册中心订阅服务,注册中心会通知consumer注册好的服务
3)consumer调用provider
3.dubbo支持不同的通信协议
1)dubbo协议
默认协议,单一长连接,NIO异步通信,基于hessian作为序列化协议
适用的场景:传输数据量很小,但是并发量很高
2)rmi协议
走java二进制序列化,多个短链接,适合消费者和提供者差不多,适用于文件的传输,一般较少用。
3)hessian协议
走hessian序列化协议,多个短链接,适用于提供者数量比消费者数量还多,适用于文件传输
4)http协议
走json协议
5)webservice协议
走soap文本序列化
dubbo支持的序列化协议
支持hessian,Java二进制序列化,json,soap文本序列化多种序列化协议,但是hessian是默认的协议
4.dubbo的负载均衡策略和集群容错策略都有哪些?动态代理策略?
【dubbo的负载均衡策略】
1)随机调用实现负载均衡
2)均匀的打到各个机器
3)性能越差,接收的请求越少,越不活跃,此时给不活跃的,性能差的机器更少的请求
4)一致性hash请求,对于同一类请求打到一台服务器上。
【dubbo集群容错策略】
1).failover cluster模式 失败自动切换,自动重试其他机器,默认是这个,常见于读操作
2).failfast cluster模式 一次调用失败,就立即返回失败,常见于写操作
3)failsafe cluster模式 出现异常时忽略掉,常见于不重要的接口调用,比如记录日志
4)failback cluster模式 失败了后台自动记录请求,然后定向重发,比较适合于写消息队列
5)forking cluster模式 并行调用多个provider ,只要一个成功即返回
6)broadcast cluster模式 逐个调用所有的provider
【dubbo的动态代理策略】
默认使用javassist动态字节码生成,创建代理类
但是可以通过spi扩展机制配置自己的动态代理策略
【dubbo的spi机制】
首先搞一个jar包,写一个接口实现类,在META-INF/services文件路径下创建一个文件,指定一个key来去指引刚才接口实现类的位置。provider工程添加对jar包的依赖。,在xml配置文件写
protocol层 @Adaptive
【dubbo降级】
也可以定义一个带有mock后缀的类HelloServiceMock ,然后实现某一个接口。
【失败重试和超时重试】
5.分布式服务接口的幂等性如何设计?(比如不能重复扣款)
1)对于每一个请求有一个唯一标示,例如订单id
2)每个处理完成的请求,有一个状态来标示
3)处理请求之前先判断,如果之前已经请求了就不做处理了。可以在数据库添加唯一键
4)也可以用redis做唯一键约束
6.分布式系统的顺序性如何保证?
1.首先从业务上考虑,尽量不要有顺序性的问题。
2.首先用一致性hash的负载均衡策略,指定某一个服务器来解决订单问题,然后在这个服务器上创建一个队列,然后按顺序执行。
7.如何设计一个类似dubbo的rpc框架?
1)用zookeeper做注册中心
2)消费者拿服务列表
3)生成客户端的一个代理对象
4)做一个负载均衡算法,具体调用哪个服务
5)可以用netty或者nio的方式发送请求,发送hessian序列化的格式数据。
6)服务端的代理对象一直在监听某个端口,当客户端发送了请求之后,接收到请求之后进行处理
8.zk都有哪些使用场景?
1)分布式协调,a发送完了请求之后,注册一个监听,当b执行完之后,a就会收到消息
2)分布式锁,a和b请求同时请求,会有一个机器先创建一个znode节点,结果另一个去创建的时候就不能创建了,等第一个执行完了再执行。
3)元数据/配置信息:比如kafka,也可以做dubbo注册中心
4)ha高可用:hadoop、hdfs、yarn等很多大数据系统,都是基于zk做的高可用架构
9.实现分布式锁有哪些方案?redis和zk如何实现分布式锁?以及区别?
redis实现分布式锁
1)普通的方式,SET my:lock 随机值 NX PX 30000,只有key不存在才会设置成功。释放锁就是删除锁,用lua脚本。
if redis.call("get",KEYS[1]) == ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
end
如果单点的话,会出现单点故障,如果主从,如果主的宕了,key还没有同步,这时其他线程会拿到锁。
2)redlock算法
1)获取当前时间戳,单位为毫秒
2)跟上面类似,轮流尝试在每个节点上创建锁,过期时间较短,一般几十毫秒。
3)尝试在大多数节点上创建锁
4)计算创建锁的时间,小于超时时间,说明建锁成功。
5)要是建锁失败了。就删除
6)锁被别人创建了,就要不断轮训尝试获取锁。
3)zk创建分布式锁。利用临时节点,创建成功了,说明获取了锁,别的客户端创建失败,就会注册一个监视器。释放锁就是删除节点,删除之后会通知后面的节点。
4)redis分布式锁和zk的分布式锁的区别
redis分布式锁,其实需要自己不断去尝试获取锁,比较消耗性能
zk分布式锁,获取不到锁,注册个监听器即可,不需要不断主动尝试获取锁,性能开销较小
另外一点就是,如果是redis获取锁的那个客户端bug了或者挂了,那么只能等待超时时间之后才能释放锁;而zk的话,因为创建的是临时znode,只要客户端挂了,znode就没了,此时就自动释放锁
10.集群部署时的分布式session如何实现?
spring session + redis,添加依赖,再添加配置redis信息,然后通过写方法类,直接获取从request请求中存放以及获取。
11.分布式事务了解吗?你们如何解决分布式事务问题的?
1)两阶段提交方案
2)三阶段提交方案
给大家举个例子吧,比如说跨银行转账的时候,要涉及到两个银行的分布式事务,如果用TCC方案来实现,思路是这样的:
1)Try阶段:先把两个银行账户中的资金给它冻结住就不让操作了
2)Confirm阶段:执行实际的转账操作,A银行账户的资金扣减,B银行账户的资金增加
3)Cancel阶段:如果任何一个银行的操作执行失败,那么就需要回滚进行补偿,就是比如A银行账户如果已经扣减了,但是B银行账户资金增加失败了,那么就得把A银行账户资金给加回去
3)本地消息表
4)可靠消息最终一致性方案
5)最大努力通知方案