Dubbo相关知识点
Java PRC框架
RPC:远程服务调用
Dubbo 工作分为 4 个角色,分别是服务提供者、服务消费者、注册中心、和监控中心。
按照工作阶段又分为部署阶段和运行阶段。
部署阶段中服务提供方在启动时在指定的端口上暴露服务,并向注册中心汇报自己的地址。
服务调用方启动时向注册中心订阅自己感兴趣的服务。
运行阶段注册中心先将地址列表推送给服务消费者,服务消费者选取一个地址向对端发起调用。
在这个过程中,服务消费者和服务提供者的运行状态会上报给监控中心。
1 导入dubbo-starter,在application.properties配置属性,使用@Service暴露服务和@Reference引用服务
2 保留dubbo xml配置文件;导入dubbo-starter,使用@ImportResource导入dubbo的配置文件
3 只用注解API的机制,将每一个组件手动创建到容器中,手写配置类
负载均衡机制:
1.RandomLoadBalance:按权重随机调用,这种方式是dubbo默认的负载均衡策略
如果服务多实例权重相同,则进行随机调用;如果权重不同,按照总权重取随机数根据总权重数生成一个随机数,然后和具体服务实例的权重进行相减做偏移量,然后找出偏移量小于0的,比如随机数为10,某一个服务实例的权重为12,那么10-12=-2<0成立,则该服务被调用,这种策略在随机的情况下尽可能保证权重大的服务会被随机调用
2.RoundRobinLoadBalance:轮询,按公约后的权重设置轮询比率
首先计算出多服务实例的最大最小权重,如果权重都一样(maxWeight=minWeight),则直接取模轮询;如果权重不一样,每一轮调用,都计算出一个基础的权重值,然后筛选出权重值大于基础权重值得invoker进行取模随机调用
3.LeastActiveLoadBalance:最少活跃次数
首先查找最小活跃数的服务并统计权重和出现的频次,如果最小活跃次数只出现一次,直接使用该服务;如果出现多次且权重不相同,则按照总权重数随机;如果出现多次且权重相同,则随机调用。
4.ConsistentHashLoadBalance:一致性hash
当服务器压力剧增的情况下,根据实际业务情况和流量,对一些服务和页面有策略的不处理或换种简单的处理方式,从而释放服务器资源以保证核心交易正常运行或者高效运行。
1 消费方对该服务的方法调用返回null,不发起远程调用,用来屏蔽不重要服务不可用时对调用方的影响;
2 超时后返回为null,表示消费方对该服务的方法调用失败后,返回null,不抛异常,用来容忍不重要服务不稳定时对调用方的影响
dubbo 服务降级的真实含义:并不是对 provider 进行操作,而是告诉 consumer,调用服务时要做哪些动作。
Failover Cluster:失败重试
当服务消费方调用服务提供者失败后自动切换到其他服务提供者服务器进行重试。
Failfast Cluster:快速失败
当服务消费方调用服务提供者失败后,立即报错,也就是只调用一次。通常这种模式用于非幂等性的写操作。
Failsafe Cluster:失败安全
当服务消费者调用服务出现异常时,直接忽略异常。这种模式通常用于写入审计日志等操作。
Failback Cluster:失败自动恢复
当服务消费端用服务出现异常后,在后台记录失败的请求,并按照一定的策略后期再进行重试。这种模式通常用于消息通知操作。
Forking Cluster:并行调用
当消费方调用一个接口方法后,Dubbo Client会并行调用多个服务提供者的服务,只要一个成功即返回。这种模式通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks="2" 来设置最大并行数。
Broadcast Cluster:广播调用
当消费者调用一个接口方法后,Dubbo Client会逐个调用所有服务提供者,任意一台调用异常则这次调用就标志失败。
Dubbo 服务框架的 Schema 的解析通过 DubboNamespaceHandler 和 DubboBeanDefinitionParser 实现;
DubboNamespaceHandler 扩展了 Spring 的 NamespaceHandlerSupport,通过重写它的 init() 方法给各个标签注册对应的解析器:
public class DubboNamespaceHandler extends NamespaceHandlerSupport {
static {
Version.checkDuplicate(DubboNamespaceHandler.class);
}
public void init() {
registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
registerBeanDefinitionParser("annotation", new DubboBeanDefinitionParser(AnnotationBean.class, true));
}
}
DubboBeanDefinitionParser 实现了 Spring 的 BeanDefinitionParser,通过重写 parse() 方法实现将标签解析为对应的 JavaBean:
public class DubboBeanDefinitionParser implements BeanDefinitionParser {
public BeanDefinition parse(Element element, ParserContext parserContext) {
return parse(element, parserContext, beanClass, required);
}
@SuppressWarnings("unchecked")
private static BeanDefinition parse(Element element,ParserContext parserContext,Class> beanClass,boolean required) {
RootBeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClass(beanClass);
beanDefinition.setLazyInit(false);
//......省略
if (ProtocolConfig.class.equals(beanClass)) {
for (String name : parserContext.getRegistry().getBeanDefinitionNames()) {
BeanDefinition definition = parserContext.getRegistry().getBeanDefinition(name);
PropertyValue property = definition.getPropertyValues().getPropertyValue("protocol");
if (property != null) {
Object value = property.getValue();
if (value instanceof ProtocolConfig && id.equals(((ProtocolConfig) value).getName())) {
definition.getPropertyValues().addPropertyValue("protocol", new RuntimeBeanReference(id));
}
}
}
} else if (ServiceBean.class.equals(beanClass)) {
String className = element.getAttribute("class");
if(className != null && className.length() > 0) {
RootBeanDefinition classDefinition = new RootBeanDefinition();
classDefinition.setBeanClass(ReflectUtils.forName(className));
classDefinition.setLazyInit(false);
parseProperties(element.getChildNodes(), classDefinition);
beanDefinition.getPropertyValues().addPropertyValue("ref", new BeanDefinitionHolder(classDefinition, id + "Impl"));
}
} else if (ProviderConfig.class.equals(beanClass)) {
parseNested(element, parserContext, ServiceBean.class, true, "service", "provider", id, beanDefinition);
} else if (ConsumerConfig.class.equals(beanClass)) {
parseNested(element, parserContext, ReferenceBean.class, false, "reference", "consumer", id, beanDefinition);
}
//......省略
return beanDefinition;
}
}
通过编写 spring.handlers 文件,Spring 知道用 DubboNamespaceHandler 来解析 Dubbo 标签,
spring.handlers 内容如下:
http\://code.alibabatech.com/schema/dubbo=com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler
Spring 通过 spring.schemas 文件得知 Dubbo 标签的 Schema 是 dubbo.xsd,并以此校验应用 XML 配置文件的格式。
spring.schemas 文件内容如下:
http\://code.alibabatech.com/schema/dubbo/dubbo.xsd=META-INF/dubbo.xsd
参考链接:
https://www.cnblogs.com/chafe/p/5945209.html
https://baijiahao.baidu.com/s?id=1630695618508872194&wfr=spider&for=pc
https://blog.csdn.net/u010682330/article/details/79542665
https://www.cnblogs.com/xhj123/p/9087532.html
https://www.cnblogs.com/cyfonly/p/9091857.html
https://www.jianshu.com/p/1ff25f65587c