Dubbo基础知识
一:基本概念
软件架构的发展过程
单体架构-----垂直架构-----SOA架构-----微服务架构
- 单体架构:(All In One)所有的服务集中在一个应用,扩展时需要横向扩展整个系统(成本较高)。
- 优点:适用于小型项目,开发部署简单易用
- 缺点:大型项目不易开发与维护;只能使用一种开发语言;扩展成本高
- 垂直架构:根据业务进行整个应用的切割,拆成几个互不影响的应用。
- 举例说明下:一个系统包含用户管理,订单模块,物流模块,垂直架构就是,将系统根据业务分为用户管理和订单模块,用户管理和物流模块两个应用,分别部署,由于公用模块用户管理无法复用,这也是垂直架构的一个痛点。
- 优点:实现了系统的业务的分离,能够进行模块的单独部署
- 缺点:系统的切割粒度过大;扩展只能采用集群方式;公共模块无法复用,项目之间功能冗余。
- SOA架构(Service-Oriented Architecture):面向服务架构
- 定义:将重复的功能或模块抽取成组件的形式,对外服务;项目与服务之间使用ESB(企业服务总线)的形式作为通信的桥梁。
- 缺点:依赖于ESB(中央管理模式进行各应用之间的交互运作)。
- 微服务架构:单独部署,独立运行。
- 定义:将系统服务完全独立出来,抽取为一个个职责单一的服务,服务之间采用轻量级的框架协议(Http)进行交互。
- 优点:每个服务足够内聚,足够小,代码容易理解、开发效率提高;服务之间可以独立部署,微服务架构让持续部署成为可能;每个服务可以各自进行横向扩展和纵向扩展,而且,每个服务可以根据自己的需要部署到合适的硬件服务器上;容易扩大开发团队,可以针对每个服务(service)组件开发团队;提高容错性(fault isolation),一个服务的内存泄露并不会让整个系统瘫痪;系统不会被长期限制在某个技术栈上。
- 缺点:从优点中推其缺点
- 服务众多,难以维护与管理(Dubbo+ZK,SpringCloud)。
- 服务间交互通讯是不可靠的(RPC)
- 分布式事务处理(数据一致性)
- 单独部署就意味着每一个服务都拥有自己数据落地存储(MySQL),也就意味着微服务的扩展,只能采用集群方式。
SOA机构与微服务架构一脉相承,微服务架构做了更细致的处理(服务的颗粒度更小,去中心化,去ESB)。
功能 | SOA | 微服务 |
---|---|---|
组件大小 | 大块业务逻辑 | 单独任务或小块业务逻辑 |
耦合 | 通常松耦合 | 总是松耦合 |
公司架构 | 任何类型 | 小型、专注于功能交叉的团队 |
管理 | 着重中央管理 | 着重分散管理 |
目标 | 确保应用能够交互操作 | 执行新功能,快速拓展开发团队 |
Dubbo概念简介
以下内容摘自dubbo官网:
dubbo是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。
dubbo就是一款解决服务间通信的框架,它能让不在一台服务器的各个服务进行相互调用,对使用者来说就像调用本地方法一样,并为我们整合了智能容错和负载均衡,当某个服务不可用或是当某个服务新增时dubbo会自动发现并注册他们。dubbo还提供了管理控制台,我们可以很直观的看到当前注册中心的状态以及注册中心中注册的服务(包括服务的提供者和消费者;dubbo推荐ZK作为其注册中心),还可以对这些服务进行各种管理,包括服务动态配置,负载均衡,访问控制,权重管理等等
二:基本结构与流程
dubbo官网上的dubbo架构图:
Node | Role Spec | 翻译 |
---|---|---|
Provider | The provider exposes remote services | 服务提供者(生产远程调用的服务) |
Consumer | The consumer calls the remote services | 消费者(调用远程服务) |
Registry | The registry is responsible for service discovery and configuration | 注册中心(服务的注册与配置) |
Monitor | The monitor counts the number of service invocations and time-consuming | 监视器(统计并监听服务提供者、消费者的情况) |
Container | The container manages the services’s lifetime | 服务的容器(管理服务的生命周期) |
服务注册中心(dubbo推荐ZK)
(这里只做ZK的一些简单介绍与安装说明[单机版],后续博主会详细更新ZK的相关文章)
官方文档解释
它是一个分布式服务框架,是Apache Hadoop 的一个子项目,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。
简单点来讲zooKeeper就是一个树形目录服务(或者说文件系统+监听通知机制)。
1. 树形目录结构
ZK支持四种zNode
- PERSISTENT-持久化目录节点
客户端与zookeeper断开连接后,该节点依旧存在
- PERSISTENT_SEQUENTIAL-持久化顺序编号目录节点
客户端与zookeeper断开连接后,该节点依旧存在,只是Zookeeper给该节点名称进行顺序编号
- EPHEMERAL-临时目录节点
客户端与zookeeper断开连接后,该节点被删除
- EPHEMERAL_SEQUENTIAL-临时顺序编号目录节点
客户端与zookeeper断开连接后,该节点被删除,只是Zookeeper给该节点名称进行顺序编号
说明:子目录例如 NameService 都被称作为 znode(目录节点),和文件系统一样,我们能够自由的增加、删除znode,在一个znode下增加、删除子znode,同时znode可以存储数据。
2. 监听通知机制
客户端注册监听它关心的目录节点,当目录节点发生变化(数据改变、被删除、子目录节点增加删除)时,zookeeper会通知客户端。
3. zookeeper单机版安装
两种方式:一、docker部署;二、解压缩对应的压缩文件,并修改配置文件
docker部署
docker pull zookeeper
docker run -d -v /home/docker/zookeeperhost/zookeeperDataDir:/data -v /home/docker/zookeeperhost/zookeeperDataLogDir:/datalog -e ZOO_MY_ID=1 -e ZOO_SERVERS='server.1=192.168.32.134:2888:3888' -p 2181:2181 -p 2888:2888 -p 3888:3888 --name zookeeper --privileged zookeeper
非docker部署
Step1:配置JAVA环境,检验环境:
# java -version
Step2:下载并解压zookeeper
# cd /usr/local
# wget http://mirror.bit.edu.cn/apache/zookeeper/stable/zookeeper-3.4.12.tar.gz
# tar -zxvf zookeeper-3.4.12.tar.gz
# cd zookeeper-3.4.12
Step3:重命名配置文件zoo_sample.cfg
# cp conf/zoo_sample.cfg conf/zoo.cfg
Step4:启动zookeeper
# bin/zkServer.sh start
Step5:检测是否成功启动,用zookeeper客户端连接下服务端
# bin/zkCli.sh
配置zoo.cfg文件
- tickTime
基本事件单元,以毫秒为单位。它用来控制心跳和超时,默认情况下最小的会话超时时间为两倍的 tickTime。 - dataDir是存放内存数据库快照的位置;
- dataLogDir 是事务日志目录;
- clientPort是client连接的端口。
tickTime=2000
dataDir=/usr/zdatadir
dataLogDir=/usr/zlogdir
clientPort=2181
initLimit=5
syncLimit=2
三:项目中如何使用与注意事项
项目中简单实用可以概括为以下几点
- 服务提供者:service类使用Dubbo的@Service注解(表明该服务会注册到Dubbo的ZK注册中心)
- 配置文件(XML)或者SpringBoot集成Dubbo在application.yml配置文件中配置Dubbo的注册中心(ZK)
- 服务消费者:使用@Reference注解,标注到对应服务接口对象(服务消费者与提供者,实现的服务接口需一致)
- 项目中,为了避免提供者服务与消费者服务中接口冗余,会将接口放入统一的接口模块中(存放工程中所有Dubbo管理的服务接口)
Dubbo配置文件详解
配置文件主要配置以下内容
- 注册中心
- 协议配置(不同的传输协议,可以提高Dubbo对服务的高效调用)
- 服务发布(1.包扫描+注解;2.注册bean+<dubbo:service … /> 手动注册服务)
示例配置文件:
<?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:context="http://www.springframework.org/schema/context"
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://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd
">
<!-- 提供方应用信息,用于计算依赖关系 -->
<dubbo:application name="dubbo_provider" />
<!-- 使用zookeeper注册中心暴露服务地址() -->
<dubbo:registry address="zookeeper://192.168.32.135:2181" />
<!-- 用dubbo协议在20880端口暴露服务 -->
<dubbo:protocol name="dubbo" port="20880" />
<!-- 具体的实现bean
<bean id="demoService" class="com.floatcloud.provider.service.impl.ProviderServiceImpl" />
-->
<!-- 声明需要暴露的服务接口
<dubbo:service interface="com.floatcloud.provider.service.ProviderService" ref="demoService" />
-->
<!-- 使用注解方式暴露接口 -->
<dubbo:annotation package="com.floatcloud.provider.service" />
<!-- 加入spring注解扫描 -->
<context:component-scan base-package="com.floatcloud.provider"/>
</beans>
Dubbo常见的属性配置
1. <dubbo:application/> 应用配置,用于配置当前应用信息,不管该应用是提供者还是消费者。
2. <dubbo:registry/> 注册中心配置,用于配置连接注册中心相关信息。
<dubbo:protocol/> 协议配置,用于配置提供服务的协议信息,协议由提供方指定,消费方被动接受。
3.
// 服务提供者
<dubbo:service/> 服务配置,用于暴露一个服务,定义服务的元信息,一个服务可以用多个协议暴露,一个服务也可以注册到多个注册中心。
// 服务消费者
<dubbo:reference/> 引用服务配置,用于创建一个远程服务代理,一个引用可以指向多个注册中心。
4.
<dubbo:module/> 模块配置,用于配置当前模块信息,可选。
<dubbo:monitor/> 监控中心配置,用于配置连接监控中心相关信息,可选。
<dubbo:provider/> 提供方的缺省值,当ProtocolConfig和ServiceConfig某属性没有配置时,采用此缺省值,可选。
<dubbo:consumer/> 消费方缺省配置,当ReferenceConfig某属性没有配置时,采用此缺省值,可选。
<dubbo:method/> 方法配置,用于ServiceConfig和ReferenceConfig指定方法级的配置信息。
<dubbo:argument/> 用于指定方法参数配置。
详细参数分析:参见道人另一篇博文。
这里主要讲解SpringBoot与Dubbo集成的场景
项目结构如图:
1. pom.xml文件设置
api接口module
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
服务提供者module
<!--引入api模块-->
<dependency>
<groupId>com.floatcloud</groupId>
<artifactId>api</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<!--引入dubbo环境-->
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.2.0</version>
</dependency>
服务消费者module
<!--引入api模块-->
<dependency>
<groupId>com.floatcloud</groupId>
<artifactId>api</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<!--引入dubbo环境-->
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.2.0</version>
</dependency>
2. application.yml配置文件
服务提供者module
server:
port: 8081
dubbo:
application:
name: dubbo-provider
registry:
address: 192.168.32.135:2181
protocol: zookeeper
check: false
protocol:
name: dubbo
port: 30003
monitor:
protocol: register
consumer:
check: false
timeout: 3000
服务消费者module
server:
port: 8082
dubbo:
application:
name: dubbo-consumer
registry:
address: 192.168.32.135:2181
protocol: zookeeper
check: false
monitor:
protocol: register
consumer:
check: false
timeout: 3000
3. 接口业务逻辑代码
api接口module
/**
* OrderService
* 订单接口
* @auther FloatCloud
* @date 2020/5/16
*/
public interface OrderService {
/**
* 修改订单状态
* @param status 订单状态
* @return 修改是否成功
*/
boolean swapOrderStatus(int status);
}
服务提供者module
import com.alibaba.dubbo.config.annotation.Service;
import com.floatcloud.api.service.OrderService;
/**
* ProviderService
* 服务提供者
* @auther FloatCloud
* @date 2020/5/16
*/
@Service
public class ProviderService implements OrderService {
@Override
public boolean swapOrderStatus(int status) {
if(status > 0){
return true;
}
return false;
}
}
服务消费者module
import org.springframework.stereotype.Service;
import com.alibaba.dubbo.config.annotation.Reference;
import com.floatcloud.api.service.OrderService;
/**
* ConsumerService
* 服务的消费者
* @auther FloatCloud
* @date 2020/5/16
*/
@Service
public class ConsumerService {
@Reference
private OrderService orderService;
public boolean change(int status){
return orderService.swapOrderStatus(status);
}
}
四:Dubbo注意事项
负载均衡
将请求均匀分摊到多个操作单元上进行执行,从而共同完成工作,Dubbo提供的均衡策略有(随机、轮询、最少活跃调用数、一致性hash),缺省为Random(随机调用)。
项目中使用loadbalance指定相应的均衡策略
// 服务提供方
@Service(loadbalance = "random")
// 服务消费方
@Reference(loadbalance = "random")
服务被事务管理,Dubbo无法发布该Service
@Transactional 注解
原因:Spring的事务管理是基于JDK动态代理来实现,JDK动态代理针对的是接口,会代理生成实现该接口的代理类,而生成的代理类的包名不是固定的(com.sum.proxy.$Proxy11,最后两位数字不固定),导致Dubbo发布服务无法通过包匹配查找到对应服务,因此无法进行服务的发布。
解决方法:
- 服务提供方,@Service 通过interfaceClass参数来指定接口
@Service(loadbalance = "random", interfaceClass = OrderService.class)
- 事务代理方式由JDK动态代理转化为cglib动态代理(代理的是类)
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
若是springBoot项目,在AOP中进行设置
spring:
aop:
proxy-target-class: true