1、促使dubbo产生原因
大规模服务中,服务出现故障或者动态扩容,都需要消费者更新本地配置URL,成本代价太高。需要能够动态感知服务上下线以及服务地址的动态维护
访问量过大,后端服务需要支持更多的访问量,需要扩容,而哪些服务需要扩容就显得格外重要,这就得进行服务监控,为扩容做参考指标,合理利用资源,提高资源利用率
而dubbo不止解决以上两方面,同时还支持降级、流量控制、集群容错、负载均衡等
2、集群容错
默认6种容错模式,还支持自行扩展,可插拔式的扩展
Failover Cluster 失败自动转换。 适用读操作,事务操作会带来数据重复问题
Failfast Cluster 快速失败。调用失败后,立即报错 。适用于一些幂等操作
Failsafe Cluster 失败安全。出现异常,忽略异常
Failback Cluster 失败后自动回复。服务调用异常,会记录以期定时重发。适合消息通知操作
Forking Cluster 并行多个服务,只要一个成功就返回,
Broadcast Cluster,广播调用所有的服务提供者,任意一个服务报错就表示服务调用失败,适合通知所有的服务提供者更新缓存或者本地资源信息。
配置方式:@Service(cluster="failfast")
注:@service是dubbo的注解
实际使用中 查询用容错,增删改用快速失败
3、负载均衡
在访问量大的情况下,通过水平扩容的方式增加多个节点来平衡请求流量,从而提升服务性能。具体如何平衡呢?这就需要用到对应的算法了。
同样,dubbo提供4中均衡策略,默认策略是随机(random),同时也支持扩展,使用SPI机制(又是另外知识了,大家可以深入了解下)
Random LoadBalance 随机算法。可以针对性能好的机器设置权重值,权重值越大,随机概率越大
RoundRobin LoadBalance 轮询。
LeastActive LoadBalance 最少活跃调用。处理较满的节点活得较少的请求
ConsistentHash LoadBalance 一致性Hash。相同参数的请求总是发送到同一个服务提供者。
配置方式:@Service(cluster = "failfast", loadbalance = "roundrobin")
3、服务降级
服务器访问压力较大时,可以根据当前业务情况对不重要的服务进行降级,保证核心服务正常进行。
降级分层:
自动化:人工和自动
功能:读服务和写服务
故障降级:远程服务“挂了”,网络异常或者rpc服务返回异常,这种情况可以给客户端兜底数据;
流量降级:每个微服务都有访问量的限制,超出限制就需要排队等待或者返回给客户端友好页面,提示”服务繁忙,请稍后再试“等信息。
而dubbo提供一种叫mock的配置来实现服务降级 可以通过@Reference(mock="xxx")
注:第一步:需要实现自动降级接口 第二步:在@Reference(mock="xxx")配置 其中xxx代表第一步的接口实现类
4、dubbo主机绑定规则
查找环境变量:DUBBO_IP_TO_BIND属性配置的IP地址
查找dubbo.protocol.host中配置的IP地址
通过LocalHost.getHostAddress获取本机的IP地址
如果配置了注册中心的地址,使用socket通信连接到注册中心的地址后,使用for循环通过socket.getLocalAddress().getHostAddress()扫描各个网卡获取网卡IP地址
问题:主机绑定自上而下寻IP,但获取的IP地址有可能不是写入注册中心的地址,默认是从环境变量中获取。
解决方案:
在hosts文件中填写对应正确的IP地址映射
在环境变量(DUBBO_IP_TO_BIND or DUBBO_IP_TO_REGISTRY)中填写正确的主机地址
通过dubbo.protocol.host 设置主机地址
5、端口
dubbo协议默认的端口号 20880
webservice协议默认端口80
在实际使用中,建议指定一个端口,避免端口产生冲突
6、 Dubbo核心之SPI
dubbo源码中,很多地方都用到了这三种代码。分别是自适应扩展点、指定名称的扩展点、激活扩展点
ExtensLoader.getExtensionLoader(xxx.class).getAdaptiveExtension();
ExtensLoader.getExtensionLoader(xxx.class).getExtension(name);
ExtensLoader.getExtensionLoader(xxx.class).getActivateWxtension(url, key);
SPI全称是Service Provider Interface,原本是JDK内置的一种服务提供发现机制,它主要用来做服务的扩展实现。SPI机制在很多场景中都有运用,比如数据库连接,JDK提供了java.sql.Driver接口,这个驱动类在JDK中并没有实现,而是由不同的数据库厂商来实现,比如Oracle、MySQL这些数据库驱动包都会实现这个接口,然后JDK利用SPI机制从classpath下找到相应的驱动来获得指定数据库的连接。这种插拔式的扩展加载方式,也同样遵循一定的协议约定。比如所有的扩展点必须要放在resources/META-INF/services目录下,SPI机制会默认扫描这个路径下的属性文件以完成加载。
Dubbo自定义协议扩展点 Dubbo或者SpringFactoriesLoader并没有使用 JDK内置的 SPI机制,只是利用了SPI的思想 根据实际情况做了一些优化和调整。Dubbo SPI的相关逻辑被封装在了 ExtensionLoader 类中,通 过 ExtensionLoader我们可以加载指定的实现类。 Dubbo 的 SPI扩展有两个规则: 和JDK内置的 SPI一样,需要在resources 目录下创建任一目录结构:META-INF/dubbo、 META-INF/dubbo/internal、META-INF/services,在对应的目录下创建以接口全路径名命名 的文件,Dubbo 会去这三个目录下加载相应扩展点。 文件内容和JDK内置的 SPI不一样,内容是一种Key 和 Value 形式的数据。Key是一个字 符串,Value 是一个对应扩展点的实现,这样的方式可以按照需要加载指定的实现类。
Dubbo自适应扩展点
通过@Adaptive注解来申明: 作用在类上或者作用在方法上
6、 Dubbo的IoC和AOP
Ioc:系统运行过程中,动态得向某个对象提供它所需要的其他的对象,这种机制是通过依赖注入(Dependency Injection)来实现的
在Dubbo的SPI机制中 injectExcepiton就是依赖注入的实现
简单来说就是如果当前加载扩展类中存在一个成员对象,并且它提供了set方法,那么就会通过自适应扩展点进行加载并赋值。例如 org.apache.dubbo.registry.integration.RegistryProtocol
可以跟踪这个方法,参看源码
其中resource/dubbo/xxx下的是自定义的扩展点,需要用到dubbo的@SPI注解
Aop:切面编程思想,主要是将业务逻辑与功能逻辑区分开来,然后在运行时或者类加载时进行织入。目的是降低代码耦合性,提供复用性
dubbo的SPI机制中 ,以下代码片段就用到了AOP思想,基于Wrapper装饰器类实现对原有的
扩展类instance进行包装7、dubbo与spring的友好集成
@DubboComponentScan、@Service、@Reference
其中@DubboComponentScan注解中引入@Import({DubboComponentScanRegistrar.class})
DubboComponentScanRegistrar.class会扫描@Service、@Reference
而具体的源码大家有兴趣可以跟踪看看这两个类,有时间再给大家说说
如有不对之处,请大家多多指教
参考链接
发表评论