Dubbo从拜师到入坟
第一个Dubbo程序:Hello world
创建业务接口工程
我们将这个接口单独抽取出来,打成jar包被多个服务锁依赖
创建服务提供者Provider
Provider工程的pom文件如下:
<properties>
<!--2.6.4版本的duboo依赖的Spring的版本-->
<spring-version>4.3.16.RELEASE</spring-version>
</properties> <dependencies>
<dependency>
<groupId>com.dubbo.test</groupId>
<artifactId>00-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--dubbo的依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.4</version>
</dependency>
<!--Spring的依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring-version}</version>
</dependency>
</dependencies>
spring-dubbo-provider.xml的配置如下所示:
这里需要注意的是xml文件头的问题,一定要注意,否则启动会报异常:
Exception:通配符的匹配很全面, 但无法找到元素 'dubbo:application' 的声明;
<?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:application name="01-first-provider"/>
<!--注册service ,其就是真正的服务提供者-->
<bean id="service" class="com.test.service.someServiceImpl"/>
<!--将service的服务暴露 确定接口,确定实现,使用点对点的方式连接,暂时不是用Zookeeper-->
<dubbo:service interface="com.test.service.someService"
ref="service"
registry="N/A" />
</beans>
启动类 providerRun如下所示
/**
* 启动类
*/
public class providerRun {
public static void main(String[] args) throws IOException {
//在容器启动到时候,就把我们的服务注册到注册中心,或者称之为暴露
//创建Spring容器
ApplicationContext ac = new ClassPathXmlApplicationContext("spring-dubbo-provider.xml");
//Spring容器启动
((ClassPathXmlApplicationContext) ac).start();
//使当前主线程阻塞,以提供持续服务
System.in.read();
}
}
创建服务的消费者Consumer
pom.xml内容如下:
<properties>
<!--2.6.4版本的duboo依赖的Spring的版本-->
<spring-version>4.3.16.RELEASE</spring-version>
</properties>
<dependencies>
<dependency>
<groupId>com.dubbo.test</groupId>
<artifactId>00-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--dubbo的依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.4</version>
</dependency>
<!--Spring的依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring-version}</version>
</dependency>
</dependencies>
spring-dubbo-consumer.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:application name="01-first-consumer"/>
<!--确定服务接口,确定连接方式-->
<dubbo:reference id="someService"
interface="com.test.service.someService"
url="dubbo://localhost:20880"/>
</beans>
启动类如下所示:
/**
* consumer启动兼服务消费类
*/
public class consumerRun {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("sprin-dubbo-consumer.xml");
someService service = (someService) ac.getBean("someService");
service.hello("Toney");
}
}
运行测试
我们先启动服务提供者providerRun,再启动消费者consumerRun,观察到如下信息
我们通过消费者consumer在自己工程的Spring容器中获取到的someService引用,成功调用了provider工程的hello方法
至于中途是怎么调用的,就要着重关注我们的两个spring配置文件了
使用Zookeeper注册中心
在上一个案列中,我们使用的是直连的方式建立连接,现在我们采用ZK作为我们的注册中心
Dubbo的注册中心官方推荐的就是Zookeeper
工程的话,复制服务提供者和消费者,稍加改动即可
改造服务的提供者Provider
pom.xml文件 增添一个依赖即可:
<!-- ZK的客户端依赖:在进入到阿帕奇孵化器后由zkClient改为curator -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.12.0</version>
</dependency>
配置文件如下所示:增改
使用的是集群的方式,集群机器的先后顺序没有影响
<!--声明ZK服务中心 (单机)-->
<!--<dubbo:registry address="zookeeper://192.168.159.159:2181"/>-->
<!--第二中方式声明ZK服务中心 (单机)-->
<!--<dubbo:registry protocol="zookeeper" address="192.68.159.159:2181" />-->
<!--声明ZK服务中心,ZK集群的方式-->
<dubbo:registry address="zookeeper://192.168.159.159:2181?backup=192.168.159.169:2181,192.168.159.179:2181"/>
<!--指定实列名,指定服务接口,不指定url,默认为ZK-->
<dubbo:reference id="someService"
interface="com.test.service.someService"/>
改造服务消费者Consumer
pom.xml 添加一个依赖
<!-- ZK的客户端依赖:在进入到阿帕奇孵化器后由zkClient改为curator -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.12.0</version>
</dependency>
配置文件如下所示: 增改
<!--声明ZK服务中心 (单机)-->
<!--<dubbo:registry address="zookeeper://192.168.159.159:2181"/>-->
<!--第二中方式声明ZK服务中心 (单机)-->
<!--<dubbo:registry protocol="zookeeper" address="192.68.159.159:2181" />-->
<!--声明ZK服务中心,ZK集群的方式-->
<dubbo:registry address="zookeeper://192.168.159.159:2181?backup=192.168.159.169:2181,192.168.159.179:2181"/>
<!--指定实列名,指定服务接口,不指定url,默认为ZK--> <dubbo:reference id="someService" interface="com.test.service.someService"/>
启动Zookeeper的服务
我们指定了ip为192.168.159.159这台机器上的ZK,那我们就启动之,
详情翻阅:https://www.cnblogs.com/msi-chen/p/11068925.html(ZK的单机&集群环境搭建)
运行测试
首运行服务提供者。其次运行服务消费者,我们观察控制台输出
再观察消费者的控制台,我做了点修改,得到了返回值并打印:
连接单机ZK,集群ZK都已测试通过,暂时就写到这儿吧,我要做一个被写代码耽误的中华小当家(煮夫!!)
Dubbo的声明式缓存
缓存嘛?就是缓存嘛!为了减少服务提供者的压力,Dubbo提供了基于结果的声明式缓存,该缓存是基于消费者端的,只需要修改消费者配置文件即可,使用很简单。
修改消费者配置文件
我们就使用ZK的这个工程做演示
修改消费者的配置文件,添加如上属性即可
修改消费者的启动类
我们修改消费者的启动了,对同一个函数进行两次相同的访问,如下:
然后我们看服务的提供者,打印了几次,如果是一次的话,则 说明第二次函数的调用并没有经过服务的提供者的函数
查看运行结果
——
通过上面的两张图,就可以知道,我们的缓存起效果了,但在这里不得不了解了解Dubbo提供了三种结果缓存机制
当然下面三个就是cache属性的值,直接指定使用哪种缓存机制,默认是lru
lru:服务级别缓存的默认机制,该机制可以默认缓存1000个结果集,若超过,采用最近最少使用原则抛出删除缓存,以保证新的结果被缓存
threadlocal:当前线程缓存,当多个线程要对当前线程进行某一操作时首先需要查询当前线程的某个信息,通过线程缓存,可以有效减少缓存
jcache:可以桥接第三方缓存产品
结果缓存的运用场景
Dubbo的缓存是基于结果的,是在服务的消费方的主观能动控制的,一般用于查询结果不变的场景,因为他没有缓存失效时间控制这玩意儿,只有等缓存结果满了,pop出去最近最少使用的结果,如果一个数据是变动的,那么服务消费者获取到的永远都是没有更新的数据,除非该数据被POP
Dubbo的多版本控制
Dubbo的多版本控制指的是:服务名称(即接口名)相同的情况下提供不同的服务(实现类不同),为服务添加一个版本号,使用"服务名称"+"版本号"的方式来确定一个服务
多版本控制主要的应用场景:当一个接口的实现类需要升级时,我们可以是哟个版本号进行过渡,注意版本不同的服务之间是不能相互引用的,设想这样一个环境,一个服务的一个版本需要升级,在生产环境中一般不会一次性全部进行升级,而是在访问最少的时候先升级一部分,然后下一次访问最少的时候再升级一部分,而这一部分又一部分就可以使用版本号来进行过渡
添油加醋提供者
之前someService的实现类只有一个,现在我们增加一个,用作版本演示
我们的服务提供者由一个实现类变为了两个实现类,各自都有不同的实现,我们首先对其进行注册,其次在暴露服务时,指定自己的版本号
添油加醋消费者
而消费者在远程调用服务的时候,指定服务的版本即可调用指定了版本号的服务
运行测试
——
直接在消费端修改版本号即可消费消费相同接口下不同的服务实现
Dubbo的服务分组
简单阐述,不做测试
服务分组和多版本控制的使用方式基本都是一样的,知识将version改成group就好了,但是各自适用的环境有点不同,使用版本控制是为了升级,新版本替代老版本,老版本不再提供服务 : version="1.0.0" 、 version="2.0.0";
分组也是相同接口给出了不同的实现类,但是这些实现类并没有谁要替换掉谁的意思,针对不同的需求调用不同的服务接口,他们是并存的,就像支付服务的实现,可以有微信支付,可以有支付宝支付,还可以银联,服务并存想用那个服务消费者就指定该服务所对应的分组即可 :group="pay.weixin" 、 group="pay.zhifubao"
Dubbo的服务延迟暴露
如果我们的服务启动过程中需要预热事件(再启动一段时间后性能才能到达最佳状态)比如初始化缓存,等待相关资源就位等,可以使用deplay进行延迟暴露
如上所示:我们只需要在服务的提供方的<dubbo:service />标签中添加delay属性,单位毫秒
若值为正数,则表示延迟暴露多少毫秒,在指定时间后再发布服务,
若值为-1,则表示在spring初始化完成后暴露服务
Dubbo的多注册中心
很多时候一个项目会有多个注册中心
同一个服务注册到多个注册中心_[一对多]
同一个服务可以注册到多个不同地域的注册中心,为多个不同地域的服务提供服务
修改服务提供者的配置文件,多个注册中心之间使用逗号分割,如下:
当然第二个集群是假的,知道牛啃南瓜怎么下嘴就行?当然你也可以使用ZK单机模式演示
不同的服务注册到不同的注册中心_[一对一]
一个项目中,不同的服务可以注册不同的注册中心:如下
同一个服务引用自不同的注册中心_[多对一]
同一个消费者需要调用两个注册中心的服务,而被调用的服务的接口名,版本号,分组等是相同的,不同中心的这个相同名称的服务CURD的是不同的数据库,即服务名相同,但是实现是不同的,修改服务消费者如下:
Dubbo的多协议支持
服务暴露协议
在我们前面的Demo中,服务提供者和服务的消费者是通过zookeepeer连接协议连接上Zookeeper注册中心的
为什么服务的提供者和消费者连接上Zookeeper,消费者就可以消费服务了呢?
zookeeper协议:是提供者/消费者连接注册中心的连接协议,并不是提供者和消费者之间的连接协议
当消费者连接上注册中心后,在消费服务之前,首先需要连接上这个服务的提供者,虽然服务的消费者可以通过注册中心获取到服务提供者,但提供者对于消费者来说确实透明的,消费者并不知道真正的服务提供者是谁,不过无论服务的提供者是谁,消费者都需要连接上服务的提供者才可以获取到真正的服务,而这个连接也是需要专门的链接协议的,这个协议被称为服务的暴露协议
在我们之前的Demo中并没有看到服务暴露协议的相关配置,项目也是可以运行,因为Dubbo采用了默认的暴露协议,Dubbo服务暴露协议
Dubbo服务暴露协议,适用于小数据量大并发的服务调用,以及服务消费者主机数远远大于服务提供者主机的情况,服务提供少,需求多,单个主机应对高并发。
了解内容:除了Dubbo服务暴露协议,Dubbo框架还支持另外七种服务暴露协议,Hessian协议,Http协议,RMI协议,WebService协议,THrift协议,Memcached协议,Redis协议,在实际中使用最多的就是Dubbo服务暴露协议
服务暴露协议用法
下面我们以Dubbo服务暴露协议作为列子来说明服务暴露协议的用法
在服务的提供者的Spring配置文件中注册服务暴露协议,
然后在暴露服务时具体指定所使用的已经被注册的暴露协议
二、同一服务支持多种协议(修改服务提供者的配置文件)
三、不同服务使用不同的协议(修改服务提供者的配置文件)
牛啃南瓜知道怎么啃就行,这里我就没做过多的演示
Dubbo的高级设置以及使用建议
在Provider上尽量多的配置Consumer端的属性
使得Provider实现着一开始就考虑到Provider的服务特点、服务质量等问题,因为作为服务的提供者比服务的消费者更加清楚服务的性能参数,如调用的超时时间,合理的重试次数等,在Provider配置后,Consumer不配置则会默认使用Provider端的配置值,如果Consumer没有配置,Provider也没有配置,就会使用Consumer端的全局设置,这对于Provider而言是不可控的,也是不合理的
粒度到可以针对某一个服务也可以针对服务的同时针对某一个方法(hello方法)
timeout:远程服务调用超时的时限
retries:失败重试次数,默认为2
loadbalance:负载均衡算法,默认是随机random,还可以选择轮询(roundrobin)、最不活跃优先(leastactive)等
actives:消费者最大并发调用限制,达到上限后,新的调用会被阻塞直到超时,0表示不限制
Provider端配置合理的Provider端属性
threads:用于指定服务的线程池大小
executes:一个服务并行执行的请求上限,超过上限,新请求肯定被阻塞,可能阻塞到超时,该属性在<dubbo:method/>则是针对指定的方法,配置在<dubbo:service />上则是针对整个服务
常用性能调优参数(来自网络)
参数名 | 作用范围 | 默认值 | 说明 | 备注 |
threads | provider | 200 | 业务处理线程池大小 | |
iothreads | provider | CPU+1 | io线程池大小 | |
queues | provider | 0 |
线程池队列大小,当线程池满时,排队等待执行的队列大小, 建议不要设置,当线程程池时应立即失败, 重试其它服务提供机器,而不是排队,除非有特殊需求 |
|
connections | consumer | 0 |
对每个提供者的最大连接数, rmi、http、hessian等短连接协议表示限制连接数, Dubbo等长连接协表示建立的长连接个数 |
Dubbo协议默认共享一个长连接 |
actives | consumer | 0 | 每服务消费者每服务每方法最大并发调用数 | 0表示不限制 |
acceptes | provider | 0 | 服务提供方最大可接受连接数 | 0表示不限制 |
executes | provider | 0 | 服务提供者每服务每方法最大可并行执行请求数 | 0表示不限制 |
Dubbo从拜师到入坟的更多相关文章
- 深度分析ReentrantLock源码及AQS源码,从入门到入坟,建议先收藏!
一.ReentrantLock与AQS简介 在Java5.0之前,在协调对共享对象的访问时可以使用的机制只有synchronized和volatile.Java5.0增加了一种新的机制:Reentra ...
- testlib.h从入门到入坟
学了这么久OI连个spj都不会写真是惭愧啊... 趁着没退役赶紧学一波吧 配置 github下载地址 我是直接暴力复制粘贴的.. 然后扔到MingW的目录里 直接引用就好啦 基本语法 引用testli ...
- SpringBoot整合SpringData JPA入门到入坟
首先创建一个SpringBoot项目,目录结构如下: 在pom.xml中添加jpa依赖,其它所需依赖自行添加 <dependency> <groupId>org.springf ...
- SrpingBoot入门到入坟04-配置文件
SpringBoot使用一个全局的配置文件,名称是固定,作用就是修改SpringBoot自动配置的默认值. *application.properties *application.yml 先看看两者 ...
- SrpingBoot入门到入坟03-基于idea快速创建SpringBoot应用
先前先创建Maven项目然后依照官方文档再然后编写主程序写业务逻辑代码才建立好SpringBoot项目,这样太过麻烦,IDE都支持快速创建,下面基于idea: 使用Spring Initializer ...
- SrpingBoot入门到入坟02-HelloWorld的细节和初始自动配置
关于SpringBoot的第一个HelloWorld的一些细节: 1.父项目 首先查看项目中的pom.xml文件 文件中有个父项目,点进去则: 它里面也有一个父项目,再点进去: 可以发现有很多的依赖版 ...
- SrpingBoot入门到入坟01-HelloWorld和SpringBoot打Jar包
第一个SpringBoot: 建立一个maven项目: 再pom.xml里面增加依赖: <?xml version="1.0" encoding="UTF-8&qu ...
- nginx从入门到入坟
目录 1.nginx下载安装 2.启动命令 3.服务脚本 4.nginx目录说明 5.nginx配置文件 6.虚拟主机与域名配置和站点配置 6.1server_name配置规则 7.反向代理负载均衡配 ...
- dubbo接口方法重载且入参未显式指定序列化id导致ClassCastException分析
问题描述&模拟 线上登录接口,通过监控查看,有类型转换异常,具体报错如下图 此报错信息是dubbo consumer端显示,且登录大部分是正常,有少量部分会报类型转换异常,同事通过更换方法名+ ...
随机推荐
- Codeforces 19E&BZOJ 4424 Fairy(好题)
日常自闭(菜鸡qaq).不过开心的是看了题解之后1A了.感觉这道题非常好,必须记录一下,一方面理清下思路,一方面感觉自己还没有完全领会到这道题的精髓先记下来以后回想. 题意:给定 n 个点,m 条边的 ...
- ubuntu安装及破解WebStorm11
ubuntu安装及破解WebStorm11 下载地址:http://www.jetbrains.com/webstorm/download/#section=linux-version 1.qingy ...
- 转帖 maven(一) maven到底是个啥玩意~
转载自:https://www.cnblogs.com/whgk/p/7112560.html 我记得在搞懂maven之前看了几次重复的maven的教学视频.不知道是自己悟性太低还是怎么滴,就是搞不清 ...
- kNN算法和决策树
的整数. 下面看书上给出的实例: from numpy import * import operator def createdataset(): group=array([[1.0,1.1],[1. ...
- 管理mysql
要管理MySQL,可以使用可视化图形界面MySQL Workbench. MySQL Workbench可以用可视化的方式查询.创建和修改数据库表,但是,归根到底,MySQL Workbench是一个 ...
- 创建一个apk:按钮-click-文字display,测试apk;安装在真机进行调试的方法
问题引入: 怎么样在一个app做event事件?例如touch操作,滑动操作,和按键事件(back,home等) 回答1:device.touch(x,y) ---获取device对象,然后touch ...
- Python的从头再来
虽然各种视频,文档看了不少.但是都没有系统的总结.现在要把Python从最基础开始总结,回归.也当作自己的复习.
- 关于RF中元素定位问题
今天碰到一个定位元素的问题,用CLASS定位. 调试后是这样的情况: 显示定位正确,字体被覆盖了.完了,在RF中跑脚本的时候,报错,说没有找到元素 . 郁闷,各种试,还是没有定位到. 最好问前端,教我 ...
- python Pool并行执行
# -*- coding: utf-8 -*- import time from multiprocessing import Pool def run(fn): #fn: 函数参数是数据列表的一个元 ...
- 【转】手机web页面制作时的注意事项
一.手机页面的标准头规范 字符编码使用utf-8:指定页面手机内存缓存中的存储时间段 device-width:通知浏览器使用设备的宽度作为可视区的宽度 initial-scale - 初始的缩放比例 ...