分布式RPC框架

dubbo常见问题:

1. 问dubbo的工作原理:服务注册,注册中心,服务生产者,消费者,代理通信,负载均衡

2. 问网络通信,序列化: dubbo协议,长连接,NIO,hessian序列化协议

3. 问负载均衡策略,集群容错策略,动态策略:dubbo跑起来后一些功能是如何运转,怎么做复制均衡,怎么做容错,怎么生成动态代理?

4. 问dubbo SPI机制:是否了解SPI机制?如何基于SPI机制对dubbo进行扩展?

5. dubbo服务治理,超时,降级,重试等。

1. 为什么要进行系统拆分?

项目大了,代码多了,很多代码冲突,代码合并维护困难。改一个地方,回归测试工作量很大。

大项目发布上线依赖很多外部东西,发布特别麻烦。

2. 如何进行拆分?

系统拆分需要经过多轮拆分,不可能一次就拆分好了。考虑多少个人维护多少个服务。

3.拆分后为什么要用Dubbo, 不用Dubbo可以吗?DubboThrift有什么区别?

可以不用。可以用纯基于Spring MVC,纯http接口相互通信,但是维护成本很高。

Dubbo已经在RPC做得很好了,成熟的RPC框架,本地就是进行接口调用,Dubbo代理调用请求,跟远程网络通信,处理负载均衡,超时重试等等功能。

4. 说一下的Dubbo 的工作原理?注册中心挂了可以继续通信吗?说说发起一次RPC请求的流程?

4.1. dubbo工作原理

第一层: service层/接口层: provider和consumer接口,留给你来实现服务的生产者和消费者

第二层:config层:提供配置文件,对dubbo进行各种配置

第三层:proxy层:dubbo为provider和consumer生成代理,代理之间进行网络通信

第四层:registry层:负责服务的注册与发现

第五层:cluster层:provider可以部署在多台机器,组成集群

第六层:monitor层:对RPC接口调用次数和调用时间进行监控

第七层:protocol层:远程调用层,封装RPC调用

第八层:exchange层:进行信息交换,封装请求响应,同步转异步

第九层:transport层:网络传输

第十层:serialize层:数据序列化

工作流程:

第一步:provider 向注册中心去注册

第二步:consumer 从注册中心订阅服务,注册中心会通知 consumer 注册好的服务

第三步:consumer 调用 provider

第四步:consumer 和 provider 都异步通知监控中心

  4.2. 注册中心挂了可以继续通信吗?

可以。刚开始初始化的时候,消费者会将生产者的地址信息拉取到本地缓存,所以注册中心挂了可以继续通信。

5. dubbo支持哪些通信协议?支持哪些序列化协议?

1. dubbo支持不同的通信协议

1). dubbo协议

dubbo://192.168.0.1:20188

默认dubbo协议,单一长连接,NIO异步通信,Hessian二进制序列化。

适用场景:传输数据量小(每次请求100KB内),消费者比提供者个数多, 适合于小数据量大并发的服务调用。

  • 为什么要消费者比提供者个数多?

假设网络为千兆网卡(1024Mbit=128MByte),根据网络测试,每条连接最多只能压满7MByte,理论上1个服务提供者需要20个消费者才能压满网卡。

  • 为什么不能传大包?

假设网络为千兆网卡(1024Mbit=128MByte),每条连接最大7Mbyte,如果请求是大包(比如500KByte),

则单个服务提供者的TPS最大:128Mbyte / 500KByte = 262。
           单个消费者调用单个服务提供者TPS最大:7MByte / 500KByte = 14。
           所有单个请求包越大,消费者调用的TPS越低,网络成为瓶颈。

  • 为什么异步单一长连接?

大多数网络都是服务提供者少,消费者请求者多。通过单一连接,保证单一消费者不会压垮提供者,长连接可以减少握手次数,使用异步IO,复用线程池。

2)  Hessian协议。用于集成Hessian的服务,Hessian底层采用Http通讯,采用Servlet暴露服务。

适用范围:传入传出参数数据包较大,提供者比消费者个数多,提供者压力较大,可传文件。适用场景:页面传输,文件传输,或与原生hessian服务互操作.

因此比较高效的做法是带上传下载文件的服务使用hessian协议,普通的服务使用dubbo协议。

其他协议, 如rmi协议(java序列化),http协议(JSON序列化),webservice(SOAP序列化)

为什么PB(protocol  buffer)效率最高?

         PB是google出品的轻量高效的结构化数据存储格式,性能比JSON,XML要高很多。

性能高原因:1. 使用proto编译器,自动序列化和反序列化,速度非常快。2.数据压缩效果好,序列化后数据体积小,传输带宽和速度有优势。

  

6. dubbo 负载均衡策略和集群容错策略都有哪些?动态代理策略呢?

  6.1 负载均衡策略:

1. Random loadbalance

dubbo默认是random load balance,随机负载均衡。可以对provider设置不同权重,按照权重来做负载均衡,权重越大分配到流量越高。

2. LeastActive loadbalance

自动感知,如果某机器性能越差,接收请求越少,越不活跃,就会给更少的请求。

3. Consistent hash loadbalance

一致性hash算法,相同参数请求分发到一个provider上,这个provider挂了的时候,会基于虚拟节点均匀分配剩余流量,减小抖动。

如果你需要是要某一类请求都到在某一个节点处理,那就选这个一致性 Hash 策略。

   6.2 集群容错策略:

failover cluster模式(默认):

如果某台机器宕机,请求失败几次后重试其他机器。

failfast cluster模式:

一次调用失败就立即失败。比如新增一条记录。

failsafe cluster模式:

出现异常忽略,适用于不重要的接口调用,比如记录日志。

failback cluster模式:

失败后记录请求,然后定时重发,适合于写消息队列。

forking cluster模式:

并行调用多个provider,只要一个成功就立即返回。适用于实时性比较要求比较高的读操作,但会浪费资源。通过forks=”2”来设置最大并行数。

    6.3 动态代理策略:

默认使用 javassist 动态字节码生成,创建代理类。但是可以通过 spi 扩展机制配置自己的动态代理策略。

7. SPI是什么?DubboSPI是什么?

SPI: Service Provider Interface。

比如有个接口A,有3个实现类,实现类A1/A2/A3。那么在系统运行时候对这个接口到底选择哪个实现类?

需要根据指定的配置,去找对应的实现类加载,用这个实现类实例对象。这个就是SPI。

比如通过jar包方式给某个接口提供实现,在自己jar包的META-INF/services/,放一个和接口同名的文件a,里面指定接口的实现就是jar包里某个类。

在调用时,通过jar的a文件找到这个接口应该用哪个实现类。

SPI 机制适用场景?

       适用插件扩展的场景,比如说你开发了一个给别人使用的开源框架,如果你想让别人自己写个插件,插到你的开源框架里面,从而扩展某个功能。

比如jdbc, java提供jdbc接口,没有提供实现类。实际根据具体适用的数据库,比如mysql的jar包,mysql-jdbc-connector.jar引入。

系统运行时,遇到jdbc接口,会在底层适用引入的jar提供的实现类。

dubbo的SPI思想:

Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();

Protocol 接口,在系统运行的时候,dubbo 会判断一下应该选用这个 Protocol 接口的哪个实现类来实例化对象来使用。

@SPI("dubbo")
public interface Protocol {
int getDefaultPort();
@Adaptive
<T> Exporter<T> export(Invoker<T> invoker) throws RpcException;
@Adaptive
<T> Invoker<T> refer(Class<T> type, URL url) throws RpcException;
void destroy();
}

在 dubbo 自己的 jar 里,在/META_INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol文件中:

dubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol
http=com.alibaba.dubbo.rpc.protocol.http.HttpProtocol
hessian=com.alibaba.dubbo.rpc.protocol.hessian.HessianProtocol

  如何自己扩展 dubbo 中的组件:

自己写个工程,要是那种可以打成 jar 包的,里面的 src/main/resources 目录下,搞一个 META-INF/services,

里面放个文件叫:com.alibaba.dubbo.rpc.Protocol,文件里搞一个my=com.bingo.MyProtocol。自己把 jar 弄到 nexus 私服里去。

然后自己搞一个 dubbo provider 工程,在这个工程里面依赖你自己搞的那个 jar,然后在 spring 配置文件里给个配置:

<dubbo:protocol name=”my” port=”20000” />

provider 启动的时候,就会加载到我们 jar 包里的my=com.bingo.MyProtocol 这行配置里,接着会根据你的配置使用你定义好的 MyProtocol 了,这个就是简单说明一下,你通过上述方式,可以替换掉大量的 dubbo 内部的组件,就是用你自己的 jar 包,然后配置一下即可。

8. 如何基于dubbo进行服务治理、服务降级、失败重试及超时重试?

  服务治理

1. 调用链路自动生成

基于dubbo做分布式系统中,对各个服务之间的调用自动记录下,然后自动将各个服务之间的依赖关系和调用链路生成出来。

服务分层,避免循环依赖。

调用链路失败监控和报警。

2. 服务访问压力以及时长统计

自动统计各个接口和服务之间的调用次数以及访问延时。后面才能看当前系统的压力在哪里,如何来扩容和优化。

3. 服务调用权限和可用性

只有某个服务有权利调用另外一个服务。

可用性监控,接口调用成功率,几个9? 99%, 99.9%,99.99%

  服务降级

服务A调用服务B , B挂了,服务A尝试几次都不行,就要服务降级,走备选逻辑,给用户返回响应。

我们调用接口失败的时候,直接通过mock统一返回null。

也可以设置mock=true,可以通过走mock Service进行降级逻辑处理。

  失败重试和超时重试

失败重试,就是 consumer 调用 provider 要是失败了,比如抛异常了,此时应该是可以重试的,或者调用超时了也可以重试。配置如下:

<dubbo:reference id="xxxx" interface="xx" check="true" async="false" retries="3" timeout="2000"/>

retries:失败重试次数

timeout:超过xxx秒超时返回

9. 分布式服务接口的幂等性如何设计(比如不能重复扣款)?

幂等性:同一个接口,多次发起同一个请求,保证接口结果正确,不能重复操作,多扣款或多插入数据等等。

单机:JVM内存用map或set保存orderid, 记录订单已经支付过。

分布式: 1. 设计一个标识来表示这个请求已经处理过。比如支付之前插入一条记录标识这个订单的支付流水。

重发请求,由于已经插入过这个orderid的流水,唯一键约束,插不进去。

2. 数据库里记录一个支付状态。比如未支付,已支付等等。

3. 利用Redis来保存一个是否处理过的标识。SETNX key。

PS:没有通用解决方案,需要结合业务来保证幂等性。

10. 分布式服务接口请求的顺序性如何保证?

解决方案:

1. 业务逻辑上的设计,最好不要设计这种需要保证顺序性的。

一旦引入,比如使用分布式锁(很重),会导致系统复杂度上升,效率降低,热点数据压力过大等问题。

2. 使用dubbo的一致性hash负载均衡策略。

将某个请求(某个订单id)对应的请求都要分发到同一个机器上,然后将对应的多个请求放入一个内存队列,强制排队,这样来保证顺序。

11. 如何自己设计一个类似 Dubbo RPC 框架?

考察点:有没有对某个RPC框架原理有深入理解。能不能从整体上来考虑,考察系统设计能力。

回答思路:

整体包括哪些模块:注册中心,消费者,生产者和想对应的接口,动态代理,负载均衡,底层网络通信协议,序列化协议。RPC框架扩展-SPI机制,超时,降级。

1. 设计注册中心。 保留各个服务的信息,可以用ZK。

2. 服务在注册中心注册,自动生成服务代理,动态代理,自动监听网络请求,

消费者的代理,调用别的服务,实现负载均衡算法,在部署服务的多台机器上,按负载均衡算法挑选服务,建立网络连接,发送网络请求。

3. 网球请求怎么发?可以用netty,NIO等等。

4.  请求中数据格式?序列化协议。可以用hessian序列化,或者别的,pb等等,通过字节流发送到服务端。

5. 服务接收端要反序列化,反序列化为对象,在本地调用服务接口,处理完结果后序列化返回给消费者。

6. RPC框架怎么扩展: SPI机制。

7.  怎么做超时,降级。

参考资料:

《互联网Java进阶面试训练营》的笔记 -- 中华石杉

[Java复习] 分布式PRC - Dubbo的更多相关文章

  1. [Java复习] 分布式锁 Zookeeper Redis

    一般实现分布式锁都有哪些方式? 使用 Redis 如何设计分布式锁?使用 Zookeeper 来设计分布式锁可以吗? 这两种分布式锁的实现方式哪种效率比较高? 1. Zookeeper 都有哪些使用场 ...

  2. [Java复习] 分布式事务 Part 2

    分布式事务了解吗?如果解决分布式事务问题的? 面试官心里: 只要聊到你做了分布式系统,必问分布式事务,起码得知道有哪些方案,一般怎么来做,每个方案的优缺点是什么. 为什么要有分布式事务? 分布式事务实 ...

  3. [Java复习] 分布式高可用-Hystrix

    什么是Hystrix? Hystrix 可以让我们在分布式系统中对服务间的调用进行控制,加入一些调用延迟或者依赖故障的容错机制. Hystrix 的设计原则 对依赖服务调用时出现的调用延迟和调用失败进 ...

  4. [Java复习] 分布式事务 Part 1

    1. CAP理论 C: Consistency 一致性 A: Availability 可用性 P: Partition tolerance 分区容错性 CAP定理:一个分布式系统不可能同时满足CAP ...

  5. Jmeter分布式测试dubbo接口2

    上次我们将dubbo接口与jmeter集成起来,但是jmeter是由java实现的,本身有很多限制,无法实现高并发,我们需要借助分布式来实现大压力测试. 在上次的例子中,我们只是实现了简单的dubbo ...

  6. java 复习003 之排序篇

    由java 复习003跳转过来的C语言实现版见some-sort-algorithms 快速排序(不稳定 O(n log n)) package vell.bibi.sort_algorithms; ...

  7. java 复习001

    java 复习001 比较随意的记录下我的java复习笔记 ArrayList 内存扩展方法 分配一片更大的内存空间,复制原有的数据到新的内存中,让引用指向新的内存地址 ArrayList在内存不够时 ...

  8. 分布式架构--Dubbo项目实战学习文档

    安装Dubbo注册中心(Zookeeper-3.4.6) 安装Dubbo管理控制台 Tomcat中部署web应用 ---- Dubbo服务消费者Web应用war包的部署 Dubbo监控中心的介绍与简易 ...

  9. java复习(1)---java与C++区别

    [系列说明]java复习系列适宜有过java学习或C++基础或了解java初步知识的人阅读,目的是为了帮助学习过java但是好久没用已经遗忘了的童鞋快速捡起来.或者教给想快速学习java的童鞋如何应用 ...

随机推荐

  1. 前端知识总结--html

    1.  doctype的作用是什么? <!DOCTYPE> 声明必须是 HTML 文档的第一行,位于 <html> 标签之前. <!DOCTYPE> 声明不是 HT ...

  2. centos 下 sphinx安装和配置

    一.安装前提必备先安装工具 yum -y install make gcc g++ gcc-c++ libtool autoconf automake imake mysql-devel libxml ...

  3. Selenium常用API的使用java语言之15-警告框处理

    在 WebDriver中处理JavaScript所生成的alert.confirm以及prompt十分简单,具体做法是使用switch_to_alert()方法定位到alert/confirm/pro ...

  4. Codeforces Round #597 (Div. 2) B. Restricted RPS

    链接: https://codeforces.com/contest/1245/problem/B 题意: Let n be a positive integer. Let a,b,c be nonn ...

  5. JavaScript-日常代码-时间

    取得今天0点: var start = new Date(new Date(new Date().toLocaleDateString()).getTime()); console.log(start ...

  6. Laravel 报 Nginx 502 : Bad Gateway 错误

    1 问题再现1.1 Laravel 6.1.0,在前端数据修改,标题中包含有中文符号:.或<>,Nginx 报502 错误. 1.2 在 TEXT 字段中保存则不存在此问题 2 排查过程 ...

  7. margin:auto你真的理解么

    含义 margin:auto是具有强烈计算意味的关键字,用来计算元素对应方向应该获得的剩余空间大小 填充规则 (1) 如果一侧定值,一侧auto,则auto为剩余空间大小 (2) 如果两侧均是auto ...

  8. [Zhx] 无题

    https://www.luogu.org/problemnew/show/T15368 区间修改,区间查询k(<= 10)大值 应该也可以用分块写 #include <cstdio> ...

  9. Cogs 461. [网络流24题] 餐巾(费用流)

    [网络流24题] 餐巾 ★★★ 输入文件:napkin.in 输出文件:napkin.out 简单对比 时间限制:5 s 内存限制:128 MB [问题描述] 一个餐厅在相继的N天里,第i天需要Ri块 ...

  10. python 根据时间戳获取秒🐱

    print("当前时间: ",time.strftime('%Y.%m.%d %H:%M:%S ',time.localtime(time.time()))) import tim ...