Dubbo

2020-04-25  本文已影响0人  技术灭霸

1、如何自己设计一个类似dubbo的rpc框架?

image.png

可以从几方面去思考:
1、服务订阅发布(注册中心)
2、服务路由
3、负载均衡(随机、轮询、最少活跃调用数、一致性哈希负载均衡)
4、集群容错(失败重试、限流降级)
5、服务调用(同步调用、异步调用、参数回调、事件通知)
6、多协议
7、序列化方式
8、统一配置
9、动态代理
10、限流降级

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

使用内存队列,强制排队来保证他们的顺序性

3、分布式服务接口的幂等性如何设计?

1、对于每个请求必须有一个唯一的标识
2、每次处理完请求之后,必须有一个记录标识这个请求处理过了。常见的方案是在 mysql 中记录个状态
3、每次接收请求需要进行判断,判断之前是否处理过。
4、插入一条支付流水,order_id 建一个唯一键 unique key。你在支付一个订单之前,先插入一条支付流水
5、写一个标识到 redis 里面,先查 redis有没有

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

服务治理

  1. 调用链路自动生成
  2. 服务访问压力以及时长统计
  3. 服务分层(避免循环依赖)
  4. 调用链路失败监控和报警
  5. 每个服务的可用性的监控

服务降级

失败重试和超时重试

5、 dubbo 的 spi 思想是什么?

spi 机制一般用在哪儿?插件扩展的场景,比如说你开发了一个给别人使用的开源框架,如果你想让别人自己写个插件,插到你的开源框架里面,从而扩展某个功能,这个时候 spi 思想就用上了。

上面那行代码就是 dubbo 里大量使用的,就是对很多组件,都是保留一个接口和多个实现,然后在系统运行的时候动态根据配置去找到对应的实现类。如果你没配置,那就走默认的实现好了,没问题。

@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 的 spi 机制默认是怎么玩儿的了,其实就是 Protocol 接口,@SPI(“dubbo”) 说的是,通过 SPI 机制来提供实现类,实现类是通过 dubbo 作为默认 key 去配置文件里找到的,配置文件名称与接口全限定名一样的,通过 dubbo 作为 key 可以找到默认的实现类就是

com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol。

如果想要动态替换掉默认的实现类,需要使用 @Adaptive 接口,Protocol 接口中,有两个方法加了 @Adaptive 注解,就是说那俩接口会被代理实现。

dubbo动态代理策略
默认使用 javassist 动态字节码生成,创建代理类。

但是可以通过 spi 扩展机制配置自己的动态代理策略。

6、ProtoBuf 和 XML的区别

  1. XML、JSON、ProtoBuf 都具有数据结构化和数据序列化的能力
  2. XML、JSON 更注重数据结构化,关注人类可读性和语义表达能力。ProtoBuf 更注重数据序列化,关注效率、空间、速度,人类可读性差,语义表达能力不足(为保证极致的效率,会舍弃一部分元信息)
  3. ProtoBuf 的应用场景更为明确,XML、JSON 的应用场景更为丰富。

7、Dubbo的上下文RpcContext

RpcContext 是一个 ThreadLocal 的临时状态记录器,当接收到 RPC 请求,或发起 RPC 请求时,RpcContext 的状态都会变化。如:方法名、参数类型、真实参数、本端/对端地址等。这些数据仅属于一次调用。
比如:A调B,B再调C,则B机器上,在B调C之前,RpcContext记录的是A调B的信息,在B调C之后,RpcContext记录的是B调C的信息。

消费端在执行Rpc调用之前,经过Filter处理, 会将信息写入RpcContext.见ConsumerContextFilter:
服务端在执行调用之前,也会经过Filter处理,将信息写入RpcContext. 见ContextFilter类

8、dubbo的限流与降级怎么实现的?

  1. dubbo的服务者与消费者 service的配置,最大连接数 与 请求数目配置
  2. dubbo的超时设置 + 配置mock 类。 请求超时后会执行mock,并返回
    3,dubbo可以通过扩展Filter的方式引入Hystrix,具体代码如下:https://github.com/yskgood/dubbo-hystrix-support

9、如何解决Dubbo中生产者未启动,消费者启动报错

在配置类中添加如下的信息就可以了,代码如下所示:

/**
 * 消费者配置不主动监督zookeeper服务
 *
 * @return
 */
@Bean
public ConsumerConfig consumerConfig() {
   ConsumerConfig consumerConfig = new ConsumerConfig();
   consumerConfig.setCheck(false);
   consumerConfig.setTimeout(20000);
   return consumerConfig;
}

这样就可以了,不管是服务提供者还是服务消费者谁先启动,都可以通过@Reference实例化的对象。加上这个之后,测试环境终于没有出现500的null指针错误了。这边还有一点需要注意的是:很多时候服务提供者既是服务消费者,所以都得加上上面给出的代码。

上一篇下一篇

猜你喜欢

热点阅读