Dubbo
分布式RPC框架Apache Dubbo
RPC全称为remote procedure call 远程过程调用
Dubbo提供了三大核心能力:
-
面向接口的远程方法调用,
-
智能容错和负载均衡,
-
服务自动注册和发现。
核心
- 通信效率
- 序列化和反序列化的效率
概念
- 服务提供者(Provider)
- 暴露服务的服务提供方,服务提供者在启动时,向注册中心注册自己提供的服务
- 服务消费者(Consumer)
- 调用远程服务的服务消费方,向注册中心订阅自己所需的服务
- 从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用
- 注册中心(Registry)
- 注册中心返回服务提供者地址列表给消费者,
- 如果有变更,注册中心将基于长连接推送变更数据给消费者
- 监控中心(Monitor)
- 服务消费者和提供者,在内存中累计调用次数和调用时间
- 定时每分钟发送一次统计数据到监控中心
init初始化,async异步,sync同步,container表示dubbo容器
依赖注意,必须使用5.0.5.RELEASE版本的spring,dubbo2.6.0
不然和新版spring有版本冲突
服务提供方
创建 applicationContext-service.xml
配置文件
<!-- 注册名称-->
<dubbo:application name="dubbo_provider"/>
<!-- 注册服务-->
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<!-- 注册协议-->
<dubbo:protocol name="dubbo" port="20881"/>
<!-- 包扫描-->
<dubbo:annotation package="com.stu.service"/>
web.xml
<!-- 初始化参数-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:application-service.xml</param-value>
</context-param>
<!-- 设置监听器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
服务消费方
导入的依赖和提供方一致
<!-- 注册应用名称-->
<dubbo:application name="dubbo_consumer"/>
<!-- 注册zookeeper-->
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<!-- 包扫描-->
<dubbo:annotation package="com.stu.controller"/>
<!-- 建议在开发阶段将check值设置为false,在生产环境下改为true-->
<dubbo:consumer check="false"/>
web.xml
<!-- 设置转发器-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:application-consumer.xml</param-value>
</init-param>
<!-- 启动优先级-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
相同接口抽取
建一个公共项目,消费者和提供者相同的接口抽出,放在第三个项目上
然后消费者和 提供者对这个公共项目进行依赖,
注意,需要重写打包
事务代理的Service问题
解决Dubbo无法发布被事务代理的Service问题
<!-- 数据源-->
<bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
<!-- 事务管理-->
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 开启事务注解,属性是使用cglib代理方式为Service类创建代理对象-->
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
proxy-target-class="true" 改为静态代理,默认为false
在Service注解中加入interfaceClass属性,指定服务的接口类型
服务提供方
service用的是dubbo的包,不是spring的
import com.alibaba.dubbo.config.annotation.Service;
//扫描进容器,指定服务的接口类型
@Service(interfaceClass = HelloService.class)
@Transactional //开启事务
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello(String name) {
return "hello!"+name;
}
}
消费者
@Controller
@RequestMapping("/demo")
public class HelloController {
@Reference //引入导入dubbo的包
private HelloService helloService;
@RequestMapping("/hello")
@ResponseBody //返回json
public String getName(String name){
String sayHello = helloService.sayHello(name);
return sayHello;
}
}
负载均衡
其实就是将请求分摊到多个操作单元上进行执行,从而共同完成工作任务。
一台服务器缺点
- 如果宕机,不能提供服务
- 可以容纳的并发数量比较少
负载均衡策略
- Random LoadBalance 比较多
- 随机,按权重设置随机概率。
- RoundRobin LoadBalance 比较多
- 轮循,按公约后的权重设置轮循比率。轮流处理
- LeastActive LoadBalance
- 最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。
- 使用响应毫米数最低的,延迟最低的服务器
- ConsistentHash LoadBalance
- 一致性 Hash,相同参数的请求总是发到同一提供者。
既可以在服务提供者一方配置,也可以在服务消费者一方配置
//在服务消费者一方配置负载均衡策略
@Reference(check = false,loadbalance = "random")
//在服务提供者一方配置负载均衡
@Service(loadbalance = "random")