Dubbo介绍
Dubbo是阿里巴巴在2011年开源的分布式服务框架,是SOA(Service-Oriented Architecture 面向服务的架构)服务化治理方案的核心框架。Dubbo主要提供三方面的功能:远程接口调用;负载均衡和容错;自动服务注册和发现。官方曾停止维护Dubbo很长一段时间,如今又开始维护,并将它贡献Apache开源基金会。也有很多其他第三方组织在更新和维护它,如当当在Dubbo的基础上开源了Dubbox。
Dubbo架构
节点角色说明:
Provider
暴露服务的服务提供方。
Consumer
调用远程服务的服务消费方。
Registry
服务注册与发现的注册中心。
Monitor
统计服务的调用次调和调用时间的监控中心。
Container
服务运行容器。
调用关系说明:
服务容器负责启动,加载,运行服务提供者。
服务提供者在启动时,向注册中心注册自己提供的服务。
服务消费者在启动时,向注册中心订阅自己所需的服务。
注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
Hello World!示例
项目依赖
<!-- https://mvnrepository.com/artifact/org.apache.zookeeper/zookeeper -->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.10</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
<exclusion>
<groupId>io.netty</groupId>
<artifactId>netty</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- https://mvnrepository.com/artifact/com.101tec/zkclient -->
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.0.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/dubbo -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.3</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.curator/curator-framework -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.0.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.curator/curator-recipes -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.0.1</version>
</dependency>
接口类
package com.dubbo.api;
public interface IHelloService {
String sayHello(String name);
}
服务类
package com.dubbo;
import com.dubbo.api.IHelloService;
public class HelloServiceImpl implements IHelloService{
public String sayHello(String name) {
// TODO Auto-generated method stub
return name;
}
}
服务端配置文件(暴露服务)
<!-- 提供者的应用名 -->
<dubbo:application name="dubbo-server" />
<!-- 使用ZooKeeper注册中心暴露发现服务地址 -->
<dubbo:registry address="zookeeper://192.168.25.128:2181" />
<!-- 用Dubbo协议在20880端口暴露服务 -->
<dubbo:protocol name="dubbo" port="20880" />
<!-- 声明需要暴露的服务接口 -->
<dubbo:service interface="com.dubbo.api.IHelloService"
ref="helloService" />
<!-- 和本地Bean一样实现服务 -->
<bean id="helloService" class="com.dubbo.HelloServiceImpl" />
服务启动类
package com.dubbo;
import java.io.IOException;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Server {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
AbstractApplicationContext context = new ClassPathXmlApplicationContext("classpath:provider.xml");
System.in.read();
context.close();
}
}
消费端配置文件(引用远程服务)
<!-- 消费方的应用名,用于计算依赖关系,不是匹配条件,不要与提供方一样 -->
<dubbo:application name="dubbo-client" />
<!-- 使用ZooKeeper注册中心的地址 -->
<dubbo:registry address="zookeeper://192.168.25.128:2181" />
<!-- 生成远程服务代理,可以和本地bean一样使用helloService -->
<dubbo:reference id="helloService" interface="com.dubbo.api.IHelloService" />
消费端启动类
package com.dubbo;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.dubbo.api.IHelloService;
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:consumer.xml");
IHelloService iHelloService = (IHelloService) context.getBean("helloService"); // 获取远程服务代理
String hello = iHelloService.sayHello("Hello World!"); // 执行远程方法
System.out.println(hello);
context.close();
}
}
注册中心ZooKeeper
官方推荐使用 ZooKeeper 注册中心。注册中心负责服务地址的注册与查找,相当于目录服务,服务提供者和消费者只在启动时与注册中心交互,注册中心不转发请求,压力较小。
ZooKeeper介绍
ZooKeeper是一个开源的分布式协调服务,是 Apacahe Hadoop 的子项目,是一个树型的目录服务,支持变更推送,适合作为Dubbo服务的注册中心,工业强度较高,可用于生产环境。
Zookeeper 在Linux系统的安装
ZooKeeper是用Java编写的,运行在Java环境上,因此在部署ZooKeeper的机器上需要安装Java运行环境。
1.从官网下载JDK安装包https://www.oracle.com/technetwork/java/javase/downloads/jdk10-downloads-4416644.html
2.解压JDK压缩包
tar -zxvf jdk-10.0.2_linux-x64_bin.tar.gz -C /usr/local/java/
3.修改环境变量
vim /etc/profile
在文件末尾添加环境变量
export JAVA_HOME=/usr/local/java/jdk-10.0.2
export PATH=
P
A
T
H
:
PATH:
PATH:JAVA_HOME/bin
4.重启配置文件使修改立即生效
source /etc/profile
5.从官网下载ZooKeeper安装包https://zookeeper.apache.org/releases.html
6.解压ZooKeeper压缩包
tar -zxvf zookeeper-3.4.6.tar.gz -C /usr/local/ZooKeeper/
7.进入 ZooKeeper 目录,创建 data 文件夹。
mkdir data
8.进入conf目录 ,把 zoo_sample.cfg 改名为 zoo.cfg
cd conf
mv zoo_sample.cfg zoo.cfg
9.打开zoo.cfg , 修改 dataDir 属性
dataDir=/usr/local/ZooKeeper/data
10.配置环境变量
export ZOOKEEPER_HOME=/usr/local/ZooKeeper
export PATH=
P
A
T
H
:
PATH:
PATH:ZOOKEEPER_HOME/bin
11.进入bin目录,启动服务
./zkServer.sh start
Dubbo对ZooKeeper的使用
Dubbo支持zkclient和curator这两种ZooKeeper客户端实现,默认使用zkclient。若使用curator,按如下配置
<dubbo:registry address=”zookeeper://127.0.0.1:2181” client=”curator” />
将同一ZooKeeper分成多组注册中心
<dubbo:registry id=”beijingRegistry” protocol=”zookeeper”
address=”127.0.0.1:2181” group=”beijing” />
<dubbo:registry id=”shanghaiRegistry” protocol=”zookeeper”
address=”127.0.0.1:2181” group=”shanghai” />
连接ZooKeeper集群
<dubbo:registry protocol=”zookeeper” address=”192.168.1.10:2181,192.168.1.11:2181,192.168.1.12:2181” />
向多个ZooKeeper注册中心注册
<dubbo:registry id=”hangzhouRegistry” address=”127.0.0.1:2181” />
<dubbo:registry id=”shanghaiRegistry” address=”127.0.0.1:2182” default=”false" />
<dubbo:service interface=“com.alibaba.hello.api.HelloService” version-“1.0.0” ref=“helloService” registry=“hangzhouRegistry, shanghaiRegistry” />
服务暴露
<dubbo:service delay=“5000” interface=”com.dubbo.api.IHelloService” ref=”helloService” executes=”10” />
<dubbo:provider protocol=“dubbo” accepts=“10” />
引用服务
<dubbo:reference id="helloService” interface=“com.dubbo.IHelloService” actives=“10” connections=“10”>
<dubbo:method name=”sayHello” async=”true” />
</dubbo:reference>
通过一下方式进行异步调用
Future helloFuture = RpcContext.getContext().getFuture();
服务隔离(分组隔离)
<dubbo:service group=“login_wx” interface-“com.dubbo.login” />
<dubbo:service group=“login_fb” interfaces"com.dubbo.login" />
或者将服务消费者分组
<dubbo:reference id=“wxlogin” group=“login_wx” interface=“com.dubbo.login” />
<dubbo:reference id=“fblogin” group=“login_fb” interface=“com.dubbo.login” />
Dubbo的四种配置方式
Dubbo的配置有三大类服务发现、服务治理、性能调优
XML配置
Dubbo使用Spring的Schema进行扩展标签和解析配置,所以可以Spring的XML配置方式来配置。
<!-- 提供者的应用名 -->
<dubbo:application name="dubbo-server" />
<!-- 使用ZooKeeper注册中心暴露发现服务地址 -->
<dubbo:registry address="zookeeper://192.168.25.128:2181" />
<!-- 用Dubbo协议在20880端口暴露服务 -->
<dubbo:protocol name="dubbo" port="20880" />
<!-- 声明需要暴露的服务接口 -->
<dubbo:service interface="com.dubbo.api.IHelloService"
ref="helloService" />
<!-- 和本地Bean一样实现服务 -->
<bean id="helloService" class="com.dubbo.HelloServiceImpl" />
标签优先级
方法级 > 接口级 > 全局配置
消费者 > 提供者
属性配置
Dubbo支持使用properties文件配置,它会自动加载classpath根目录下的dubbo.properties文件
dubbo.application.name=dubbo-server
dubbo.application.owner=test
dubbo.registry.address=zookeeper://127.0.0.1:2181
各配置优先级策略
JVM启动-D参数 > XML > Properties
API配置
API属性与XML配置项是一一对应的,如:ApplicationConfig.setName(“dubbo-server”)对应<dubbo:application name = “dubbo-server” />
服务提供者示例
//当前应用的配置
ApplicationConfig application = new ApplicationConfig();
application.setName(“dubbo-server”);
//连接注册中心的配置
Registryconfig registry = new Registryconfig();
registry.setAddress(“zookeeper://127.0.0.1:2181”);
registry.setUsername(“test”);
registry,setPassword(“123456”);
//服务提供者协议的配置
ProtocolConfig protocol - new ProtocolConfig();
protocol.setName(“dubbo”);
protocol.setPort(20880);
protocol.setThreads(200);
//下面为服务提供者暴露服务配置
IHelloservice helloservice = new HelloServiceImpl();//服务实现
//注意:Serviceconfig为重对象,内部封装了与注册中心的连接和开启服务端口。
//请务必自行缓存,否则可能造成内存和连接泄露
Serviceconfig service = new ServiceConfig();
service.setApplication(application);
service.setRegistry(registry); /多个注册中心可以用setRegistries()
service.setProtocol(protocol); //多个协议可以用setProtocols()
service.setInterface(IHelloService.Class);
service.setRef(helloService);
service.setVersion(“1.0.0”);
//暴露及注册服务
service.export();
服务消费者示例
//当前应用的配置
ApplicationConfig application = new ApplicationConfig();
application.setName(“dubbo-client”);
//连接注册中心的配置
Registryconfig registry = new Registryconfig();
registry.setAddress(“zookeeper://127.0.0.1:2181”);
registry.setUsername(“test”);
registry,setPassword(“123456”);
//引用远程服务
//注意:ReferenceConfig为重对象,内部封装了与注册中心的连接,以及与服务提供者的连接
//请务必自行缓存,否则可能造成内存和连接泄露
ReferenceConfig reference = new ReferenceConfig();
reference.setApplication(application);
reference.setRegistry(registry); //多个注册中心可以用setregistries()
reference.setInterface(IHelloservice.class);
reference.setVersion(“1.0.0”) ;
//和本地Bean一样使用IHelloService
注意:此代理对象内部封装了所有通信细节,对象较重,请缓存复用
IHelloService helloService reference.get();
注解配置
将Hello World!改为注解方式,SpringBoot作为启动类
服务端配置类
@Configuration
public class DubboConfiguration {
@Bean
public ApplicationConfig applicationConfig() {
ApplicationConfig applicationConfig = new ApplicationConfig();
applicationConfig.setName(“dubbo-server”);
return applicationConfig;
}
@Bean
public RegistryConfig registryConfig() {
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setAddress("zookeeper://127.0.0.1:2181");
registryConfig.setClient("curator");
return registryConfig;
}
}
服务类
@Service(timeout = 5000)
public class HelloServiceImpl implements IHelloService{
public String sayHello(String name) {
// TODO Auto-generated method stub
return name;
}
}
服务端启动类
@SpringBootApplication
DubboComponentScan(basePackages = “com.dubbo”)
public class Server {
public static void main(String[] args) {
// TODO Auto-generated method stub
SpringApplication.run(Server , args);
}
}
消费端配置类
@Configuration
public class DubboConfiguration {
@Bean
public ApplicationConfig applicationConfig() {
ApplicationConfig applicationConfig = new ApplicationConfig();
applicationConfig.setName(“dubbo-client”);
return applicationConfig;
}
@Bean
public ConsumerConfig consumerConfig() {
ConsumerConfig consumerConfig = new ConsumerConfig();
consumerConfig.setTimeout(3000);
return consumerConfig;
}
@Bean
public RegistryConfig registryConfig() {
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setAddress("zookeeper://127.0.0.1:2181");
registryConfig.setClient("curator");
return registryConfig;
}
}
消费类
public class Client {
@Reference
public IHelloService helloServiceimpl;
public void doSomething() {
helloServiceimpl.sayHello("hello world");
}
}
消费端启动类
@SpringBootApplication
DubboComponentScan(basePackages = “com.dubbo”)
public class ClientApp {
public static void main(String[] args) {
// TODO Auto-generated method stub
SpringApplication.run(ClientApp , args);
}
}
集群容错机制
集群容错机制是为了提高服务的可用性,如果单个服务节点因故障无法提供服务,可以根据配置好的集群容错模式,调用其它可用的节点。
配置方法
服务提供者配置
<dubbo:service cluster=“failfast” />
服务消费者配置
<dubbo:reference cluster=”failfast” />
六种容错模式
(1)Failover Cluster
Dubbo集群容错默认模式,调用失败时会自动切换,重新尝试调用其它节点上可用的服务。可通过retries属性设置重试次数(不含第一次)
<dubbo:reference retries=“2” />
(2)Failfast Cluster模式
快速失败模式。调用只执行一次,失败立即报错。
(3)Failsafe Cluster模式
失败安全模式,调用失败,直接忽略失败的调用,记录失败的调用到日志文件,以便后续审计。
(4)Failback Cluster
失败自动恢复,后台记录失败的请求,定时重发。适用于消息通知操作。
(5)forking Cluster模式
并行调用多个服务器,只要有一个成功便返回。可通过forks属性(forks=“2”)来设置最大的并行数。
(6)Broadcast Cluster模式
广播调用所有提供者,逐个调用,任意一台报错则报错。
集群负载均衡
Dubbo内置4种负载均衡策略
(1)随机模式(Random):按权重设置随机概率
(2)轮询模式(RoundRobin):按公约后的权重设置轮询概率。
(3)最少活跃调用数(LeastActive):响应慢的提供者收到更少的请求。活跃数相同 则随机。
(4)一致性Hash(ConsistentHash):相同参数的请求总是发给同一提供者。提供者挂掉时,请求会基于虚拟节点平摊到其它提供者上。
配置方法
服务端配置
<dubbo:service interface=“helloService” loadbalance=“roundrobin” />
也可以在客户端配置
<dubbo:reference interface=“helloService” loadbalance=“roundrobin” />
日志适配
Dubbo内置了log4j、slf4j、jcl、jdk四种日志框架
配置方法
<dubbo:application logger=”log4j” />
<dubbo:protocol accesslog=”true” />
<dubbo:protocol accesslog=”http://12.168.25.128/log/accesslog.log” />
监控管理后台
一、使用官方开源管理后台
(1)下载Tomcat安装包并解压
(2)将dubbo-admin.war包解压至webapps/ROOT目录
(3)编辑dubbo.properties配置文件
vi webapps/ROOT/WEB-INF/dubbo.properties
dubbo.properties
dubbo.registry.address=zookeeper://127.0.0.1:2181
dubbo.admin.root.password=root
dubbo.admin.guest.password=guest
(4)启动Tomcat访问http://127.0.0.1:8080/
二、dubbo-monitor开源管理后台
Dubbo Monitor是针对Dubbo开发的监控系统,,使用关系型数据库方式记录日志。官网地址https://github.com/handuyishe/dubbo-monitor
(1)创建数据库:首先创建名称为monitor数据库,编码格式UTF-8。然后将项目sql文件夹下面的create.sql导入到数据库,生成dubbo_invoke表代表成功导入。
(2)编辑项目中application.properties,配置如下:
####Dubbo Settings
dubbo.application.name=dubbo-monitor
dubbo.application.owner=handu.com
dubbo.registry.address=zookeeper://127.0.0.1:2181
dubbo.protocol.port=6060
####Database Settings
db.url=jdbc:mysql://<database_host>:<database_port>/monitor?prepStmtCacheSize=517&cachePrepStmts=true&autoReconnect=true&characterEncoding=utf-8
db.username=root
db.password=root
db.maxActive=500
####System Manager
manager.username=admin
manager.password=admin
(3)打包运行项目 执行maven命令:mvn clean package target文件夹下生成的dubbo-monitor.war即为项目部署文件,将其放置到对应服务器目录下,启动服务器即可。例如:tomcat的webapps文件夹下。
mvn clean package target
(4)访问项目 启动web服务器后,访问地址:http://IP:[port]/dubbo-moniotor,采用配置文件中manager.username和manager.password设置值进行登录。
三、DubboKeeper开源管理后台
(1)官网下载源码https://github.com/dubboclub/dubbokeeper
(2)编译打包:由于监控数据的存储和展示显示进行了分离,那么打包有所变动。在下载源码的根目录会发现install-xxx.bat(sh),这个可以根据你想要的不同存储执行对应的脚本。执行完之后在target目录下面会发现xxx-dubbokeeper-ui,xxx-dubbokeeper-server以及xxx-dubbokeeper-server.tar.gz。其中xxx-dubbokeeper-ui下会有一个war包,将该war包部署到tomcat或者jetty里面(或者其他servlet容器),那么就部署好了监控展示应用了。
(3)监控数据暂时端调整:将上面的war包解压出来后对其中WEB-INF/classes/dubbo.properties文件中的配置项进行调整。
#monitor的应用名,可根据自己情况自定义
dubbo.application.name=monitor-ui
#应用的拥有者
dubbo.application.owner=bieber
#连接的dubbo注册中心地址,保持部署监控数据存储的zk地址一样
dubbo.registry.address=zookeeper://localhost:2181
#use netty4
dubbo.reference.client=netty4
#peeper config
#监控的zookeeper连接列表,多个通过‘,’(英文逗号)隔开。
peeper.zookeepers=localhost:2181
#监控的zookeeper连接会话超时时间
peeper.zookeeper.session.timeout=60000
#被监控端同步监控数据周期时间,可不配置,默认是一分钟同步一次
monitor.collect.interval=60000
#logger
#dubbokeeper的日志目录
monitor.log.home=/usr/dev/op_disk/monitor-log
重启Tomcat,访问http://127.0.0.1:8080/dubbokeeper-ui-1.0.1
(4)监控数据存储端配置调整以及启动:通过上面编译后会得到xxx-dubbokeeper-server目录,在改名了的xxx-server下面包含三个子目录:bin,conf以及lib。
bin:启动存储端的脚本,实行start-xx.sh(bat)则启动该应用
conf:存储端的相关配置,具体配置下面会介绍
lib:应用依赖的相关jar包
启动服务之前需先初始化数据库:创建一个数据库,数据库名可以自定义一个,编码采用utf-8。初始化脚本如下
CREATE TABLE application
(
id
int(11) NOT NULL AUTO_INCREMENT,
name
varchar(100) NOT NULL DEFAULT ‘’,
type
varchar(50) NOT NULL DEFAULT ‘’,
PRIMARY KEY (id
),
UNIQUE KEY 应用名词索引
(name
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
监控服务的配置参数如下
#dubbo应用名称
dubbo.application.name=mysql-monitor
#dubbo应用所有者
dubbo.application.owner=bieber
#dubbo的注册中心地址,保存和被监控应用一个注册中心
dubbo.registry.address=zookeeper://localhost:2181
#监控数据收集协议
dubbo.protocol.name=dubbo
#监控数据收集协议端口
dubbo.protocol.port=20884
#被监控端同步监控数据周期时间,可不配置,默认是一分钟同步一次
monitor.collect.interval=100
#use netty4
dubbo.provider.transporter=netty4
#监控数据持久化周期,默认是一分钟,单位是秒
monitor.write.interval=6000
#mysql相关信息
#mysql数据库地址
dubbo.monitor.mysql.url=jdbc:mysql://localhost:3306/dubbokeeper
#mysql数据库用户名
dubbo.monitor.mysql.username=root
#mysql数据库用户密码
dubbo.monitor.mysql.password=root
#mysql数据库链接池最大连接数
dubbo.monitor.mysql.pool.max=10
#mysql数据库链接池最小连接数
dubbo.monitor.mysql.pool.min=10
(5)执行start-xx.sh(bat)启动DubboKeeper监控服务程序。
服务降级
服务降级是在服务器压力剧增时,根据实时的业务情况及流量对一些服务和页面有策略地进行降级,以释放服务器资源并保证核心任务的正常运行。
Dubbo使用mock配置来实现服务降级。mock支持两种配置:
(1)配置Boolean值。默认为false,如果配置为true,则默认使用mock的类名,即类名+Mock后缀
<dubbo:service interface=“com.dubbo.IHelloService” mock=“true” />
然后在项目中提供Mock实现类
public class HelloServiceMock implements IHelloService {
public String sayHello(String name) {
// TODO Auto-generated method stub
return "容错数据";
}
}
(2)配置为return null,忽略异常
<dubbo:service interface=“com.dubbo.BarService” mock=“return null” />