当前位置 博文首页 > 青春季风暴:Java面试题--dubbo&zookeeper

    青春季风暴:Java面试题--dubbo&zookeeper

    作者:[db:作者] 时间:2021-09-06 10:22

    dubbo是什么

    dubbo是一个分布式框架,远程服务调用的分布式框架,其核心部分包含:

    集群容错:提供基于接口方法的透明远程过程调用,包括多协议支持,以及软负载均衡,失败容错,地址路由,动态配置等集群支持。

    远程通讯: 提供对多种基于长连接的NIO框架抽象封装,包括多种线程模型,序列化,以及“请求-响应”模式的信息交换方式。

    自动发现:基于注册中心目录服务,使服务消费方能动态的查找服务提供方,使地址透明,使服务提供方可以平滑增加或减少机器。

    ?

    dubbo能做什么

    1.透明化的远程方法调用,就像调用本地方法一样调用远程方法,只需简单配置,没有任何API侵入。

    2.软负载均衡及容错机制,可在内网替代F5等硬件负载均衡器,降低成本,减少单点。

    3.服务自动注册与发现,不再需要写死服务提供方地址,注册中心基于接口名查询服务提供者的IP地址,并且能够平滑添加或删除服务提供者。

    ?

    在 Provider 上可以配置的 Consumer 端的属性有哪些?

    1)timeout:方法调用超时

    2)retries:失败重试次数,默认重试 2 次

    3)loadbalance:负载均衡算法,默认随机

    4)actives 消费者端,最大并发调用限制

    ?

    Dubbo支持服务多协议吗?

    Dubbo 允许配置多协议,在不同服务上支持不同协议或者同一服务上同时支持多种协议。

    ?

    当一个服务接口有多种实现时怎么做?

    当一个接口有多种实现时,可以用 group 属性来分组,服务提供方和消费方都指定同一个 group 即可。

    ?

    服务上线怎么兼容旧版本?

    可以用版本号(version)过渡,多个不同版本的服务注册到注册中心,版本号不同的服务相互间不引用。这个和服务分组的概念有一点类似。

    ?

    Dubbo可以对结果进行缓存吗?

    可以,Dubbo 提供了声明式缓存,用于加速热门数据的访问速度,以减少用户加缓存的工作量。

    ?

    Dubbo服务之间的调用是阻塞的吗?

    默认是同步等待结果阻塞的,支持异步调用。

    Dubbo 是基于 NIO 的非阻塞实现并行调用,客户端不需要启动多线程即可完成并行调用多个远程服务,相对多线程开销较小,异步调用会返回一个 Future 对象。

    ?

    Dubbo中zookeeper做注册中心,如果注册中心集群都挂掉,发布者和订阅者之间还能通信么?

    可以通信的,启动dubbo时,消费者会从zk拉取注册的生产者的地址接口等数据,缓存在本地。每次调用时,按照本地存储的地址进行调用;

    注册中心对等集群,任意一台宕机后,将会切换到另一台;注册中心全部宕机后,服务的提供者和消费者仍能通过本地缓存通讯。服务提供者无状态,任一台 宕机后,不影响使用;服务提供者全部宕机,服务消费者会无法使用,并无限次重连等待服务者恢复;

    挂掉是不要紧的,但前提是你没有增加新的服务,如果你要调用新的服务,则是不能办到的。

    ?

    dubbo服务负载均衡策略?

    l Random LoadBalance

    ????随机,按权重设置随机概率。在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。(权重可以在dubbo管控台配置)

    l RoundRobin LoadBalance

    ????轮循,按公约后的权重设置轮循比率。存在慢的提供者累积请求问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。

    ?

    l LeastActive LoadBalance

    ???最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。

    l ConsistentHash LoadBalance

    一致性Hash,相同参数的请求总是发到同一提供者。当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。缺省只对第一个参数Hash,如果要修改,请配置

    ?

    ?Dubbo在安全机制方面是如何解决的

    Dubbo通过Token令牌防止用户绕过注册中心直连,然后在注册中心上管理授权。Dubbo还提供服务黑白名单,来控制服务所允许的调用方。

    ?

    dubbo的调用流程

    Provider

    第 0 步,start 启动服务。

    第 1 步,register 注册服务到注册中心。

    Consumer

    第 2 步,subscribe 向注册中心订阅服务。

    注意,只订阅使用到的服务。

    再注意,首次会拉取订阅的服务列表,缓存在本地。

    【异步】第 3 步,notify 当服务发生变化时,获取最新的服务列表,更新本地缓存。

    invoke 调用

    Consumer 直接发起对 Provider 的调用,无需经过注册中心。而对多个 Provider 的负载均衡,Consumer 通过 cluster 组件实现。

    count 监控

    【异步】Consumer 和 Provider 都异步通知监控中心。

    ?

    Dubbo 可以对调用结果进行缓存吗?

    Dubbo 通过 CacheFilter 过滤器,提供结果缓存的功能,且既可以适用于 Consumer 也可以适用于 Provider 。

    通过结果缓存,用于加速热门数据的访问速度,Dubbo 提供声明式缓存,以减少用户加缓存的工作量。

    Dubbo 目前提供三种实现:

    lru :基于最近最少使用原则删除多余缓存,保持最热的数据被缓存。

    threadlocal :当前线程缓存,比如一个页面渲染,用到很多 portal,每个 portal 都要去查用户信息,通过线程缓存,可以减少这种多余访问。

    jcache :与 JSR107 集成,可以桥接各种缓存实现。

    ?

    服务提供方的优雅停机过程

    首先,从注册中心中取消注册自己,从而使消费者不要再拉取到它。

    然后,sleep 10 秒( 可配 ),等到服务消费,接收到注册中心通知到该服务提供者已经下线,加大了在不重试情况下优雅停机的成功率。

    之后,广播 READONLY 事件给所有 Consumer 们,告诉它们不要在调用我了!!!【很有趣的一个步骤】并且,如果此处注册中心挂掉的情况,依然能达到告诉 Consumer ,我要下线了的功能。

    再之后,sleep 10 毫秒,保证 Consumer 们,尽可能接收到该消息。

    再再之后,先标记为不接收新请求,新请求过来时直接报错,让客户端重试其它机器。

    再再再之后,关闭心跳线程。

    最后,检测线程池中的线程是否正在运行,如果有,等待所有线程执行完成,除非超时,则强制关闭。

    最最后,关闭服务器。

    ?

    Dubbo Consumer 只能调用从注册中心获取的 Provider 么?

    不是,Consumer 可以强制直连 Provider 。

    在开发及测试环境下,经常需要绕过注册中心,只测试指定服务提供者,这时候可能需要点对点直连,点对点直连方式,将以服务接口为单位,忽略注册中心的提供者列表,A 接口配置点对点,不影响 B 接口从注册中心获取列表。

    ?

    Dubbo 支持哪些通信协议?

    对应【protocol 远程调用层】。

    Dubbo 目前支持如下 9 种通信协议:

    【重要】dubbo:

    【重要】rest:

    webservice:

    redis:

    http:

    ?

    服务调用超时问题怎么解决

    dubbo在调用服务不成功时,默认是会重试两次的。这样在服务端的处理时间超过了设定的超时时间时,就会有重复请求,比如在发邮件时,可能就会发出多份重复邮件,执行注册请求时,就会插入多条重复的注册数据,那么怎么解决超时问题呢?如下

    1.对于核心的服务中心,去除dubbo超时重试机制,并重新评估设置超时时间。

    2.业务处理代码必须放在服务端,客户端只做参数验证和服务调用,不涉及业务流程处理

    全局配置实例

    <dubbo:provider delay="-1" timeout="6000" retries="0"/>??

    当然Dubbo的重试机制其实是非常好的QOS保证,它的路由机制,是会帮你把超时的请求路由到其他机器上,而不是本机尝试,所以 dubbo的重试机器也能一定程度的保证服务的质量。但是请一定要综合线上的访问情况,给出综合的评估。

    ?

    默认使用什么序列化框架,还有其他的吗?

    Dubbo默认使用的是Hessian序列化。hessian是一个采用二进制格式传输的服务框架,相对传统soap web service,更轻量,更快速。

    ?

    遇到的问题

    场景描述:客户端远程异步调用ServiceA,ServiceA在处理客户端请求的过程中需要远程同步调用ServiceB,ServiceA从ServiceB的响应中取数据时,得到的是null。

    对于上面的问题,解决办法有三个:

    1.方法调用两次

    ServiceA调用ServiceB的地方写两次一样的调用,这个方法原理就像ServiceB调用ServiceC一样,即清除attachements。

    这个方法最简单,但是可能对不了解的人来说,这块业务代码写重复了,会不小心删除掉,而且从写代码的角度来说,这个很鸡肋,所以不推荐。

    2.修改Dubbo源码

    ?

    修改AbstractInvoker第137行,改成每次都对async进行实际赋值,

    boolean isAsync = getUrl().getMethodParameter(invocation.getMethodName(), Constants.ASYNC_KEY, false);

    invocation.setAttachment(Constants.ASYNC_KEY, String.valueOf(isAsync));

    3.自定义Filter

    ?

    实现com.alibaba.dubbo.rpc.Filter,在RpcContext中清除这个async,

    @Activate(group = {Constants.PROVIDER})
    
    ??public class AsyncFilter implements Filter {
    
    @Override
    
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
    
    ?????RpcContext.getContext().getAttachments().remove(Constants.ASYNC_KEY);
    
    return invoker.invoke(invocation);
    
    }
    
    }

    同时在src/main/resources/META-INF/dubbo/下添加com.alibaba.dubbo.rpc.Filter文件,内容文件如下:

    asyncFilter=com.abc.filter.AsyncFilter

    ?

    Zookeeper是什么框架

    分布式开源框架,提供分布式协调服务,解决了分布式一致性问题。原本是Hadoop、HBase的一个重要组件。

    ?

    应用场景

    结合实际工作中,Zookeeper主要是用于dubbo框架的注册中心。Dubbo框架的提供者会向Zookeeper下的provider目录注册自己的URL。消费者订阅提供者的注册URL,并在consumer下注册自己的URL,以便在后续执行中调用提供者。消费者获取到URL之后,netty调用提供者提供的服务。提供者若发生了变化会主动通过zookeeper推送给消费者。

    ?

    Paxos算法&Zookeeper使用协议

    Paxos算法是分布式选举算法,Zookeeper使用的 ZAB协议(Zookeeper原子广播)

    相同点:

    比如都有一个Leader,用来协调N个Follower的运行;Leader要等待超半数的Follower做出正确反馈之后才进行提案

    ?

    ?

    Zookeeper有哪几种节点类型

    持久:创建之后一直存在,除非有删除操作,创建节点的客户端会话失效也不影响此节点。

    持久顺序:持久节点名后缀加上一个10位数字。

    临时:创建客户端会话失效(注意是会话失效,不是连接断了),节点也就没了。不能建子节点。

    临时顺序:临时节点名后缀加上一个10位数字。

    ?

    Zookeeper对节点的watch监听通知是永久的吗?

    不是。官方声明:一个Watch事件是一个一次性的触发器,当被设置了Watch的数据发生了改变的时候,则服务器将这个改变发送给设置了Watch的客户端,以便通知它们。

    ?

    为什么不是永久的,举个例子,

    如果服务端变动频繁,而监听的客户端很多情况下,每次变动都要通知到所有的客户端,这太消耗性能了。

    一般是客户端执行getData(“/节点A”,true),如果节点A发生了变更或删除,客户端会得到它的watch事件,但是在之后节点A又发生了变更,而客户端又没有设置watch事件,就不再给客户端发送。

    在实际应用中,很多情况下,我们的客户端不需要知道服务端的每一次变动,我只要最新的数据即可。

    ?

    部署方式?集群中的机器角色都有哪些?集群最少要几台机器

    单机,集群,伪集群。Leader、Follower、Observer。集群最低3(2N+1)台,保证奇数,主要是为了选举算法。

    集群如果有3台机器,挂掉一台集群还能工作吗?挂掉两台呢?

    过半存活即可用。

    集群支持动态添加机器吗?

    其实就是水平扩容了,Zookeeper在这方面不太好。两种方式:

    全部重启:关闭所有Zookeeper服务,修改配置之后启动。不影响之前客户端的会话。

    逐个重启:这是比较常用的方式。

    ?

    Zookeeper 具有如下特性:

    顺序一致性(有序性)

    从同一个客户端发起的事务请求,最终将会严格地按照其发起顺序被应用到 Zookeeper 中去。

    有序性是 Zookeeper 中非常重要的一个特性。

    单一视图

    无论客户端连接的是哪个 Zookeeper 服务器,其看到的服务端数据模型都是一致的。

    可靠性

    一旦服务端成功地应用了一个事务,并完成对客户端的响应,那么该事务所引起的服务端状态变更将会一直被保留,除非有另一个事务对其进行了变更。

    实时性

    Zookeeper 保证在一定的时间段内,客户端最终一定能够从服务端上读取到最新的数据状态。

    ?

    Zookeeper 的通知机制是什么?

    Zookeeper 允许客户端向服务端的某个 znode 注册一个 Watcher 监听,当服务端的一些指定事件触发了这个 Watcher ,服务端会向指定客户端发送一个事件通知来实现分布式的通知功能,然后客户端根据 Watcher 通知状态和事件类型做出业务上的改变。

    ?

    Zookeeper 的会话管理是怎么样的?

    ZooKeeper 的每个客户端都维护一组服务端信息,在创建连接时由应用指定,客户端随机选择一个服务端进行连接,连接成功后,服务端为每个连接分配一个唯一标识。

    ?

    集群如果有 3 台机器,挂掉 1 台集群还能工作吗?挂掉 2 台呢?

    记住一个原则:过半存活即可用。所以挂掉 1 台可以继续工作,挂掉 2 台不可以工作。

    ?

    ZooKeeper 的工作原理?

    ZooKeeper 的核心是原子广播,这个机制保证了各个 Server 之间的同步。实现这个机制的协议叫做 Zab 协议。Zab 协议有两种模式,它们分别是恢复模式(选主)和广播模式(同步):

    ?

    Zookeeper 的选举过程?

    当 Leader 崩溃,或者 Leader 失去大多数的 Follower,这时 Zookeeper 进入恢复模式,恢复模式需要重新选举出一个新的 Leader,让所有的 Server 都恢复到一个正确的状态。

    ?

    ?

    cs