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

可以从几方面去思考:
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 进行服务治理、服务降级、失败重试以及超时重试?
服务治理
- 调用链路自动生成
- 服务访问压力以及时长统计
- 服务分层(避免循环依赖)
- 调用链路失败监控和报警
- 每个服务的可用性的监控
服务降级
- 我们调用接口失败的时候,可以通过 mock 统一返回 null。
- mock 的值也可以修改为 true,然后再跟接口同一个路径下实现一个 Mock 类,命名规则是 接口名称+Mock 后缀。然后在 Mock 类里实现自己的降级逻辑。
失败重试和超时重试
- timeout:一般设置为 200ms,我们认为不能超过 200ms还没返回。
- retries:设置 retries,一般是在读请求的时候,比如你要查询个数据,你可以设置个 retries,如果第一次没读到,报错,重试指定的次数,尝试再次读取。
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的区别
- XML、JSON、ProtoBuf 都具有数据结构化和数据序列化的能力
- XML、JSON 更注重数据结构化,关注人类可读性和语义表达能力。ProtoBuf 更注重数据序列化,关注效率、空间、速度,人类可读性差,语义表达能力不足(为保证极致的效率,会舍弃一部分元信息)
- 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的限流与降级怎么实现的?
- dubbo的服务者与消费者 service的配置,最大连接数 与 请求数目配置
- 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指针错误了。这边还有一点需要注意的是:很多时候服务提供者既是服务消费者,所以都得加上上面给出的代码。
网友评论