Dubbo学习
- 一、传统应用架构到分布式架构的演化
- 1、单体式应用架构
- 2、多个垂直应用架构
- 3、分布式服务架构
- 4、流动计算机架构(SOA服务化)
- 二、Dubbo技术架构
- 三、Dubbo的核心配置
- 1、映射规则
- 2、属性配置优先级
- 3、启动时检查
- 4、集群容错
- 5、负载均衡策略
- 6、多协议配置
- 7、多版本配置
- 8、服务分组
- 四、小例子
- 生产者代码
- 消费者代码
一、传统应用架构到分布式架构的演化
1、单体式应用架构
当网站流量很小时,只需要一个应用,将所有功能部署在一起。此时,用于简化增删改查工作量的数据库访问框架(ORM)是关键,例如SSM,Spring MVC,配合Nginx做负载均衡已足够使用。
2、多个垂直应用架构
当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆分成几个互不相干的应用。此时,用于加速前端页面开发的web框架(MVC)是关键。但是不同应用之间无法高效的利用。
3、分布式服务架构
当垂直架构越来越多,应用之间的交互不可避免。将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。此时,用于提高业务复合及整合的分布式服务框架(RPC)是关键,实现不同的应用之间的互相调用。
4、流动计算机架构(SOA服务化)
当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐出现,此时需要一个调度中心基于访问压力实时管理集群容量,动态更新调度策略,提高集群利用率。此时,用于提高机器利用率的资源调度和治理中心(SOA)是关键。
二、Dubbo技术架构
各个节点角色说明:
节点 | 角色说明 |
Provider | 暴露服务的提供方 |
Consumer | 调用远程服务的服务消费方 |
Registry | 服务注册与发现的注册中心 |
Monitor | 统计服务的调用次数和调用时间的监控中心 |
Container | 服务运行容器 |
上图可以看出,Dubbo的架构很像生产者-消费者模型,只是在这个模型上加了注册中心和监控中心。
那么,整个过程大概就分为以下几步:
- 1、启动容器,加载,运行服务提供方
- 2、服务提供方在启动时,在注册中心发布自己提供的服务
- 3、注册中心通知服务消费方可以进行消费了
- 4、服务消费方通过注册中心订阅自己所需要的服务
三、Dubbo的核心配置
标签 | 作用 | 延伸 |
dubbo:service | 服务配置 | 用于暴露一个服务,定义服务的元信息,一个服务可以用多个协议暴露,一个服务也可以注册到多个注册中心 |
dubbo:reference | 引用配置 | 用于创建一个远程服务代理,一个引用可以指向多个注册中心 |
dubbo:protocol | 协议配置 | 用于配置提供服务的协议信息,协议由提供方指定,消费方被动接受 |
dubbo:application | 应用配置 | 用于配置当前应用信息,不管该应用是提供者还是消费者 |
dubbo:module | 模块配置 | 用于配置当前模块信息,可选 |
dubbo:registry | 注册中心配置 | 用于配置连接注册中心相关信息 |
dubbo:monitor | 监控中心配置 | 用于配置连接监控中心相关信息,可选 |
dubbo:provider | 提供方配置 | 当 ProtocolConfig 和 ServiceConfig 某属性没有配置时,采用此缺省值,可选 |
dubbo:consumer | 消费方配置 | 当 ReferenceConfig 某属性没有配置时,采用此缺省值,可选 |
dubbo:method | 方法配置 | 用于 ServiceConfig 和 ReferenceConfig 指定方法级的配置信息 |
dubbo:argument | 参数配置 | 用于指定方法参数配置 |
Dubbo 将自动加载 classpath 根目录下的 dubbo.properties,可以通过JVM启动参数 -Ddubbo.properties.file=xxx.properties 改变缺省配置位置。
1、映射规则
将XML配置的标签名,加属性名,用点分割,多个属性拆成多行。
- 比如:dubbo.registry.address=10.20.153.10:9090等价于<dubbo:registry address=“10.20.153.10:9090” />
多协议配置示例:
#dubbo\u652F\u6301\u7684dubbo\u534F\u8BAE\u914D\u7F6E
dubbo.protocol.name=dubbo
dubbo.protocol.dubbo.port=20903
#dubbo\u652F\u6301\u7684http rest api\u7684\u914D\u7F6E
dubbo.protocol.name=rest
dubbo.protocol.rest.port=9013
dubbo.protocol.rest.server=tomcat
2、属性配置优先级
如果虚拟机传入参数优先级最高,如果虚拟机没有传入,Dubbo的XML和SpringBoot的Application.properties优先,如果上面两个都没有传,则dubbo.properties优先,dubbo.properties一般是公共的配置。
3、启动时检查
Dubbo默认会在启动时检查依赖的服务是否可用,不可用时会抛异常,阻止Spring初始化完成,以便上线时,能及早发现问题,默认check=“true”
可以通过设置check=“false”关闭检查,比如测试时,有些服务不关心,或者出现了循环依赖,必须有一方先启动。
如果设置check=“false”,总是会返回引用,当服务恢复时,会自动连接上。
问题:如果Dubbo的生产者端没有启动,消费者端能启动吗?
答案是可以的,可以关闭消费者端服务的启动检查:(没有提供者时也不报错)
<dubbo:reference interface="com.foo.BarService" check="false" />
关闭注册中心启动检查:(没有配置中心也不报错)
<dubbo:registry check="false" />
4、集群容错
失败自动切换,当出现失败,重试其他服务器。通常用来读操作,但重试会带来更长延迟,可以通过设置retries=“2”来设置重试次数(不包含第一次)。
配置如下:
<dubbo:service retries="2" />
或
<dubbo:reference retries="2" />
设置容错机制:
<dubbo:service cluster="failsafe" />
5、负载均衡策略
- Random LoadBalance :随机,按权重设置随机概率(默认)
- RoundRobin LoadBalance:轮询,按公约后的权重设置轮询比率。
- LeastActive LoadBalance :最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。
- ConsistentHash LoadBalance:一致性 Hash,相同参数的请求总是发到同一提供者。
可以在dubbo.properties中设置:
dubbo.service.loadbalance=roundrobin
6、多协议配置
<!-- 多协议配置 -->
<dubbo:protocol name="dubbo" port="20904" />
<dubbo:protocol name="rest" port="9014" />
或者
#dubbo\u652F\u6301\u7684dubbo\u534F\u8BAE\u914D\u7F6E
dubbo.protocol.name=dubbo
dubbo.protocol.dubbo.port=20904
#dubbo\u652F\u6301\u7684http rest api\u7684\u914D\u7F6E
dubbo.protocol.name=rest
dubbo.protocol.rest.port=9014
dubbo.protocol.rest.server=tomcat
7、多版本配置
当一个接口实现,出现不兼容升级时,可以用版本号过渡,版本号不同的服务之间相互不引用。
老版本服务提供者:
<dubbo:service interface="com.foo.BarService" version="1.0.0" />
新版本服务提供者:
<dubbo:service interface="com.foo.BarService" version="2.0.0" />
老版本服务消费者:
<dubbo:reference id="barService" interface="com.foo.BarService" version="1.0.0" />
新版本服务消费者:
<dubbo:reference id="barService" interface="com.foo.BarService" version="2.0.0" />
8、服务分组
当一个接口有多个实现时,可以用group名区分。
服务:
<dubbo:service group="feedback" interface="com.xxx.IndexService" />
<dubbo:service group="member" interface="com.xxx.IndexService" />
引用:
<dubbo:reference id="feedbackIndexService" group="feedback" interface="com.xxx.IndexService" />
<dubbo:reference id="memberIndexService" group="member" interface="com.xxx.IndexService" />
任意组:
<dubbo:reference id="barService" interface="com.foo.BarService" group="*" />
四、小例子
生产者代码
生产者配置Spring-dubbo.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<!--发布出去的dubbo服务类所在包的注解-->
<dubbo:annotation package="com.debug.mooc.dubbo.one.server.service.dubbo" />
<!--注册中心zookeeper配置信息-->
<dubbo:registry address="zookeeper://127.0.0.1:2181" />
<!--支持两种协议的调用:rpc-dubbo协议;http协议-rest api-url调用-->
<dubbo:protocol name="rest" threads="500" contextpath="v1" server="tomcat" accepts="500"/>
<dubbo:protocol name="dubbo" />
<!--消费方信息配置-->
<dubbo:application name="dubboOne-consume" owner="debug" organization="dubbox"/>
</beans>
生产者配置dubbo.properties:
##
dubbo.container=log4j,spring
dubbo.reference.check=false
dubbo.registry.client=curator
dubbo.application.name=dubboOne-provider
dubbo.application.owner=debug
#dubbo\u652F\u6301\u7684dubbo\u534F\u8BAE\u914D\u7F6E
dubbo.protocol.name=dubbo
dubbo.protocol.dubbo.port=20903
#dubbo\u652F\u6301\u7684http rest api\u7684\u914D\u7F6E
dubbo.protocol.name=rest
dubbo.protocol.rest.port=9013
dubbo.protocol.rest.server=tomcat
dubbo.service.loadbalance=roundrobin
生产者提供Service:
public interface IDubboItemService {
BaseResponse listItems();
}
生产者提供Service实现类:
// 支持Dubbo协议和HTTP协议
@Service(protocol = {"dubbo","rest"},validation = "true",version = "1.0",timeout = 3000)
@Path("moocOne")
public class DubboItemService implements IDubboItemService{
private static final Logger log= LoggerFactory.getLogger(DubboItemService.class);
@Autowired
private ItemInfoMapper itemInfoMapper;
/**
* 列表查询服务-实际的业务实现逻辑
* @return
*/
@Path("item/list")
public BaseResponse listItems() {
BaseResponse response=new BaseResponse(StatusCode.Success);
try {
List<ItemInfo> infos=itemInfoMapper.selectAll();
log.info("查询到的商品列表数据:{} ",infos);
response.setData(infos);
}catch (Exception e){
log.error("列表查询服务-实际的业务实现逻辑-发生异常:",e.fillInStackTrace());
response=new BaseResponse(StatusCode.Fail);
}
return response;
}
}
消费者代码
消费者配置Spring-dubbo.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<!--发布出去的dubbo服务类所在包的注解-->
<dubbo:annotation package="com.debug.mooc.dubbo.two.server.service.dubbo" />
<!--注册中心zookeeper配置信息-->
<dubbo:registry address="zookeeper://127.0.0.1:2181" />
<!--支持两种协议的调用:rpc-dubbo协议;http协议-rest api-url调用-->
<dubbo:protocol name="rest" threads="500" contextpath="v1" server="tomcat" accepts="500"/>
<dubbo:protocol name="dubbo" />
<!--消费方信息配置-->
<dubbo:application name="dubboTwo-consume" owner="debug" organization="dubbox"/>
<!--引入服务提供方提供的dubbo服务-url="dubbo://127.0.0.1:20903" -->
<dubbo:reference interface="com.debug.mooc.dubbo.one.api.service.IDubboItemService" id="dubboItemService"
url="dubbo://127.0.0.1:20903" protocol="dubbo" version="1.0" timeout="20000">
</dubbo:reference>
</beans>
消费者配置dubbo.properties:
##
dubbo.container=log4j,spring
dubbo.reference.check=false
dubbo.registry.client=curator
dubbo.application.name=dubboTwo-provider
dubbo.application.owner=debug
#dubbo\u652F\u6301\u7684dubbo\u534F\u8BAE\u914D\u7F6E
dubbo.protocol.name=dubbo
dubbo.protocol.dubbo.port=20904
#dubbo\u652F\u6301\u7684http rest api\u7684\u914D\u7F6E
dubbo.protocol.name=rest
dubbo.protocol.rest.port=9014
dubbo.protocol.rest.server=tomcat
dubbo.service.loadbalance=roundrobin
消费者调用:
/**
* @Author:debug (SteadyJack)
* @Date: 2019/1/13 15:35
**/
@RestController
public class ItemController {
private static final Logger log= LoggerFactory.getLogger(ItemController.class);
private static final String prefix="item";
@Autowired
private IDubboItemService dubboItemService;
/**
* 用户商城列表查询
* @return
*/
@RequestMapping(value = prefix+"/list",method = RequestMethod.GET)
public Map<String,Object> list(){
Map<String,Object> resMap= Maps.newHashMap();
resMap.put("code","0");
resMap.put("msg","成功");
//TODO:调用服务提供方dubboOne提供的列表查询功能
try {
BaseResponse response=dubboItemService.listItems();
if (response!=null && response.getCode().equals(0)){
resMap.put("data",response.getData());
}
}catch (Exception e){
e.printStackTrace();
resMap.put("code","-1");
resMap.put("msg","失败");
}
return resMap;
}
}