dubbo框架的搭建及各种功能的实现

之前项目中用过dubbo做分布式,最近想把这个框架的搭建及一些基本功能的使用记录下来。

注册中心用zookeeper

架构

Provider	暴露服务的服务提供⽅
Consumer	调⽤远程服务的服务消费⽅
Registry	服务注册与发现的注册中⼼
Monitor	统计服务的调⽤次调和调⽤时间的监控中⼼
Container	服务运⾏容器

Dubbo 架构具有以下⼏个特点,分别是连通性、健壮性、伸缩性、以及向未来架构的升级性

创建一个dubbo-parent的maven project, packaging类型设置为pom,
在dubbo-parent下创建3个maven module,分别是dubbo-consumer、dubbo-provider,和dubbo-api packaging类型设置为jar
dubbo-parent的pom依赖及插件如下

org.springframework.boot
spring-boot-starter-parent
1.5.2.RELEASE


<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
1.0.0

<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
	</dependency>
	<!-- Spring Boot Dubbo 依赖 -->
	<dependency>
		<groupId>io.dubbo.springboot</groupId>
		<artifactId>spring-boot-starter-dubbo</artifactId>
		<version>${dubbo-spring-boot}</version>
		<exclusions>
			<exclusion>
				<groupId>org.apache.zookeeper</groupId>
				<artifactId>zookeeper</artifactId>
			</exclusion>
		</exclusions>
	</dependency>
	<dependency>
		<groupId>ch.qos.logback</groupId>
		<artifactId>logback-classic</artifactId>
		<scope>compile</scope>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-test</artifactId>
	</dependency>
	<dependency>
		<groupId>com.alibaba</groupId>
		<artifactId>fastjson</artifactId>
		<version>1.2.46</version>
	</dependency>
	<!-- Junit -->
	<dependency>
		<groupId>junit</groupId>
		<artifactId>junit</artifactId>
	</dependency>
	<dependency>
		<groupId>org.apache.zookeeper</groupId>
		<artifactId>zookeeper</artifactId>
		<version>3.4.13</version>
	</dependency>
	<dependency>
		<groupId>javax.validation</groupId>
		<artifactId>validation-api</artifactId>
	</dependency>
	<dependency>
		<groupId>org.hibernate</groupId>
		<artifactId>hibernate-validator</artifactId>
	</dependency>

</dependencies>
<modules>
	<module>dubbo-api</module>
	<module>dubbo-provider</module>
	<module>dubbo-consumer</module>

dubbo-api项目创建一个接口
public interface DubboService {

public void sayHello(String str);

}

dubbo-provider项目
@Service(version = “1.0.0”)
public class DubboServiceImpl implements DubboService{

private static final Logger logger = LoggerFactory.getLogger(DubboServiceImpl.class);

@Override
public void sayHello(String str) {
	logger.info("打印信息:" + str);
}

}

pom中要依赖dubbo-api项目

<dependency>
	<groupId>com.zookeeper</groupId>
	<artifactId>dubbo-api</artifactId>
	<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
	<groupId>io.dubbo.springboot</groupId>
	<artifactId>spring-boot-starter-dubbo</artifactId>
	<version>${dubbo-spring-boot}</version>
	<exclusions>
		<exclusion>
			<groupId>org.apache.zookeeper</groupId>
			<artifactId>zookeeper</artifactId>
		</exclusion>
	</exclusions>
</dependency>
	<plugins>
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
			<configuration>
				<fork>true</fork>
			</configuration>
		</plugin>
	</plugins>
</build>

配置文件
server:
port: 8092
spring:
dubbo:
application:
name: dubbo-provider
registry:
protocol: zookeeper
address: 127.0.0.1:2181, 127.0.0.1:2182
protocol:
name: dubbo
port: 20880
scan: org.dubbo.provider.service.impl

dubbo-consumer项目 pom配置

	<dependency>
		<groupId>com.zookeeper</groupId>
		<artifactId>dubbo-api</artifactId>
		<version>0.0.1-SNAPSHOT</version>
	</dependency>
</dependencies>

<build>
	<plugins>
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
			<configuration>
				<fork>true</fork>
			</configuration>
		</plugin>
	</plugins>
</build>

代码调用接口
@RestController
public class DubboController {

@Reference(version = "1.0.0")
private DubboService dubboService;

@GetMapping("/sayHello")
public String sayHello() {
	dubboService.sayHello("consumer 请求dubbo服务");
	return "请求成功";
}

}

配置文件
server:
port: 8800
spring:
dubbo:
application:
name: dubbo-consumer
registry:
protocol: zookeeper
address: 127.0.0.1:2181, 127.0.0.1:2182
scan: org.dubbo.consumer.controller

启动zookeeper, 在启动dubbo-provider, 最后启动dubbo-consumer项目,打开浏览器,输入地址localhost:8800/sayHello
控制栏输出: 打印信息:consumer 请求dubbo服务

通过api调用服务
创建项目dubbo-generic-consumer
public class BaseInvoker2 {

private ReferenceConfig<GenericService> config = null;

public BaseInvoker2() {
	config = new ReferenceConfig<>();
	ApplicationConfig configApplication = new ApplicationConfig();
	configApplication.setName("dubbo-generic-consumer");
	configApplication.setVersion("1.0.0");
	config.setApplication(configApplication);
	RegistryConfig registryConfig = new RegistryConfig();
	registryConfig.setProtocol("zookeeper");
	registryConfig.setAddress("127.0.0.1:2181, 127.0.0.1:2182");
	config.setRegistry(registryConfig);
	config.setProtocol("dubbo");
	
}

public void setInterface(String interfaceName) {
	config.setInterface(interfaceName);
}

public void setVersion(String version) {
	config.setVersion(version);
}

public Object invokeMethod(String method, String[] parameterTypes, Object[] values) {
	ReferenceConfigCache cache = ReferenceConfigCache.getCache();
	GenericService service = cache.get(config);
	return service.$invoke(method, parameterTypes, values);
	
}

public void setGeneric(boolean flag) {
	config.setGeneric(flag);
}

public void setGroup(String group) {
	config.setGroup(group);
}

}

@RestController
public class GenericConsumerController {

private static final Logger logger = LoggerFactory.getLogger(GenericConsumerController.class);

@GetMapping("/infos")
public String getGeneric() {
	BaseInvoker2 baseInvoker2 = new BaseInvoker2();
	baseInvoker2.setInterface("org.dubbo.api02.DubboService");
	baseInvoker2.setVersion("1.0.0");
	baseInvoker2.setGeneric(true);
	String[] parameterTypes = { "java.lang.String", "java.lang.String", "java.lang.Integer" };
	Object[] values = { "王五", "男", 35 };
	Object result = baseInvoker2.invokeMethod("getInfo", parameterTypes, values);
	logger.info(result.toString());
	return null;
}

@GetMapping("/diff")
public String getDifferences() {
	BaseInvoker2 baseInvoker2 = new BaseInvoker2();
	baseInvoker2.setInterface("org.dubbo.api02.GroupService");
	baseInvoker2.setVersion("1.0.0");
	baseInvoker2.setGeneric(true);
	baseInvoker2.setGroup("a1");
	String[] parameterTypes = {};
	Object[] values = {};
	Object result = baseInvoker2.invokeMethod("groupInfo", parameterTypes, values);
	logger.info(result.toString());
	return (String) result;
}

@GetMapping("/diff2")
public String getDifference() {
	BaseInvoker2 baseInvoker2 = new BaseInvoker2();
	baseInvoker2.setInterface("org.dubbo.api02.GroupService");
	baseInvoker2.setVersion("1.0.0");
	baseInvoker2.setGeneric(true);
	baseInvoker2.setGroup("a2");
	String[] parameterTypes = {};
	Object[] values = {};
	Object result = baseInvoker2.invokeMethod("groupInfo", parameterTypes, values);
	logger.info(result.toString());
	return (String) result;
}

}

启动时检查
关闭某个服务的启动时检查 (没有提供者时报错):
<dubbo:reference interface=“com.foo.BarService” check=“false” />
关闭所有服务的启动时检查 (没有提供者时报错):
<dubbo:consumer check=“false” />
关闭注册中⼼启动时检查 (注册订阅失败时报错):
<dubbo:registry check=“false” />

集群容错
重试次数配置如下:
<dubbo:service retries=“2” />

<dubbo:reference retries=“2” />

dubbo:reference
<dubbo:method name=“findFoo” retries=“2” />
</dubbo:reference>

按照以下示例在服务提供⽅和消费⽅配置集群模式
<dubbo:service cluster=“failsafe” />

<dubbo:reference cluster=“failsafe” />

负载均衡
Dubbo 提供了多种均衡策略,缺省为 random 随机调⽤
Random LoadBalance
随机,按权重设置随机概率。
RoundRobin LoadBalance
轮循,按公约后的权重设置轮循⽐率
LeastActive LoadBalance
最少活跃调⽤数,相同活跃数的随机,活跃数指调⽤前后计数差。
ConsistentHash LoadBalance
⼀致性 Hash,相同参数的请求总是发到同⼀提供者

服务端服务级别
<dubbo:service interface="…" loadbalance=“roundrobin” />
客户端服务级别
<dubbo:reference interface="…" loadbalance=“roundrobin” />
服务端⽅法级别
<dubbo:service interface="…">
<dubbo:method name="…" loadbalance=“roundrobin”/>
</dubbo:service>
客户端⽅法级别
<dubbo:reference interface="…">
<dubbo:method name="…" loadbalance=“roundrobin”/>
</dubbo:reference>

线程模型
<dubbo:protocol name=“dubbo” dispatcher=“all” threadpool=“fixed” threads=“100” />
Dispatcher
all 所有消息都派发到线程池,包括请求,响应,连接事件,断开事件,⼼跳等。
direct 所有消息都不派发到线程池,全部在 IO 线程上直接执⾏。
message 只有请求响应消息派发到线程池,其它连接断开事件,⼼跳等消息,直接在 IO 线程上执⾏。
execution 只请求消息派发到线程池,不含响应,响应和其它连接断开事件,⼼跳等消息,直接在 IO 线程上执 ⾏。 connection 在 IO 线程上,将连接断开事件放⼊队列,有序逐个执⾏,其它消息派发到线程池。
ThreadPool
fixed 固定⼤⼩线程池,启动时建⽴线程,不关闭,⼀直持有。(缺省)
cached 缓存线程池,空闲⼀分钟⾃动删除,需要时重建。
limited 可伸缩线程池,但池中的线程数只会增⻓不会收缩。只增⻓不收缩的⽬的是为了避免收缩时突然来了⼤ 流量引起的性能问题。

服务分组
当⼀个接⼝有多种实现时,可以⽤ 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.IndewxService” />

任意组 :
<dubbo:reference id=“barService” interface=“com.foo.BarService” group="*" />

多版本
⽼版本服务提供者配置:
<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” />
如果不需要区分版本,可以按照以下的⽅式配置 :
<dubbo:reference id=“barService” interface=“com.foo.BarService” version="*" />

分组聚合
有多种实现,⽤group区分,现在消费⽅需从每种group中调⽤⼀次 返回结果,合并结果返回,这样就可以实现聚合菜单项
搜索所有分组
<dubbo:reference interface=“com.xxx.MenuService” group="" merger=“true” />
合并指定分组
<dubbo:reference interface=“com.xxx.MenuService” group=“aaa,bbb” merger=“true” />
指定⽅法合并结果,其它未指定的⽅法,将只调⽤⼀个 Group
<dubbo:reference interface=“com.xxx.MenuService” group="
">
<dubbo:method name=“getMenuItems” merger=“true” />
</dubbo:service>
某个⽅法不合并结果,其它都合并结果
<dubbo:reference interface=“com.xxx.MenuService” group="" merger=“true”>
<dubbo:method name=“getMenuItems” merger=“false” />
</dubbo:service>
指定合并策略,缺省根据返回值类型⾃动匹配,如果同⼀类型有两个合并器时,需指定合并器的名称
<dubbo:reference interface=“com.xxx.MenuService” group="
"> <dubbo:method name=“getMenuItems” merger=“mymerge” /> </dubbo:service>
指定合并⽅法,将调⽤返回结果的指定⽅法进⾏合并,合并⽅法的参数类型必须是返回结果类型本身
<dubbo:reference interface=“com.xxx.MenuService” group="*">
<dubbo:method name=“getMenuItems” merger=".addAll" />
</dubbo:service>

参数验证

<groupId>javax.validation</groupId>				
<artifactId>validation-api</artifactId>				
<version>1.0.0.GA</version> 
<groupId>org.hibernate</groupId>				
<artifactId>hibernate-validator</artifactId>				
<version>4.2.0.Final</version> 

结果缓存
lru 基于最近最少使⽤原则删除多余缓存,保持最热的数据被缓存。
threadlocal 当前线程缓存,⽐如⼀个⻚⾯渲染,⽤到很多 portal,每个 portal 都要去查⽤户信息,通过线程缓 存,可以减少这种多余访问。
jcache 与 JSR107 集成,可以桥接各种缓存实现
<dubbo:reference interface=“com.foo.BarService” cache=“lru” />
或:
<dubbo:reference interface=“com.foo.BarService”>
<dubbo:method name=“findBar” cache=“lru” />
</dubbo:reference>

泛化调⽤
通过 GenericService 调⽤所有服务实现,参数及返回值中的所有 POJO 均⽤ Map 表示,通 常⽤于框架集成
<dubbo:reference id=“barService” interface=“com.foo.BarService” generic=“true” />

api调用例子:
ReferenceConfig reference = new ReferenceConfig(); // 弱类型接⼝名 reference.setInterface(“com.xxx.XxxService”);
reference.setVersion(“1.0.0”); // 声明为泛化接⼝ reference.setGeneric(true);
// ⽤com.alibaba.dubbo.rpc.service.GenericService可以替代所有接⼝引⽤
GenericService genericService = reference.get();
// 基本类型以及Date,List,Map等不需要转换,直接调⽤
Object result = genericService. i n v o k e ( &quot; s a y H e l l o &quot; , n e w S t r i n g [ ] &quot; j a v a . l a n g . S t r i n g &quot; , n e w O b j e c t [ ] &quot; w o r l d &quot; ) ; / / M a p P O J O P O J O M a p M a p &lt; S t r i n g , O b j e c t &gt; p e r s o n = n e w H a s h M a p &lt; S t r i n g , O b j e c t &gt; ( ) ; p e r s o n . p u t ( &quot; n a m e &quot; , &quot; x x x &quot; ) ; p e r s o n . p u t ( &quot; p a s s w o r d &quot; , &quot; y y y &quot; ) ; / / P O J O M a p O b j e c t r e s u l t = g e n e r i c S e r v i c e . invoke(&quot;sayHello&quot;, new String[] {&quot;java.lang.String&quot;}, new Object[] {&quot;world&quot;}); // ⽤Map表示POJO参数,如果返回值为POJO也将⾃动转成Map Map&lt;String, Object&gt; person = new HashMap&lt;String, Object&gt;(); person.put(&quot;name&quot;, &quot;xxx&quot;); person.put(&quot;password&quot;, &quot;yyy&quot;); // 如果返回POJO将⾃动转成Map Object result = genericService. invoke(“findPerson”, new String[] {“com.xxx.Person”}, new Object[]{person});

回声测试
回声测试⽤于检测服务是否可⽤,回声测试按照正常请求流程执⾏,能够测试整个调⽤是否通畅,可⽤于监控。

上下⽂信息
RpcContext 是⼀个 ThreadLocal 的临时状态记录器,当接收到 RPC 请求,或发起 RPC 请求时,RpcContext 的状态 都会变化

异步调⽤
在 consumer.xml 中配置:
<dubbo:reference id=“fooService” interface=“com.alibaba.foo.FooService”>
<dubbo:method name=“findFoo” async=“true” />
</dubbo:reference>
<dubbo:reference id=“barService” interface=“com.alibaba.bar.BarService”>
<dubbo:method name=“findBar” async=“true” />
</dubbo:reference>

代码
// 此调⽤会⽴即返回null fooService.findFoo(fooId); // 拿到调⽤的Future引⽤,当结果返回后,会被通知和设置到此Future Future fooFuture = RpcContext.getContext().getFuture();
// 此调⽤会⽴即返回null barService.findBar(barId); // 拿到调⽤的Future引⽤,当结果返回后,会被通知和设置到此Future Future barFuture = RpcContext.getContext().getFuture();
// 此时findFoo和findBar的请求同时在执⾏,客户端不需要启动多线程来⽀持并⾏,⽽是借助NIO的⾮阻塞完成
// 如果foo已返回,直接拿到返回值,否则线程wait住,等待foo返回后,线程会被notify唤醒
Foo foo = fooFuture.get(); // 同理等待bar返回 Bar
bar = barFuture.get();

sent=“true” 等待消息发出,消息发送失败将抛出异常。 sent=“false” 不等待消息发出,将消息放⼊ IO 队列,即刻返回。
<dubbo:method name=“findFoo” async=“true” sent=“true” />
如果你只是想异步,完全忽略返回值,可以配置 return=“false” ,以减少 Future 对象的创建和管理成本:
<dubbo:method name=“findFoo” async=“true” return=“false” />

参数回调
服务接⼝示例
public interface CallbackService {
void addListener(String key, CallbackListener listener);
}

public interface CallbackListener {
void changed(String msg);
}

服务提供者接⼝实现示例
public class CallbackServiceImpl implements CallbackService {
private final Map<String, CallbackListener> listeners = new ConcurrentHashMap<String, CallbackListener>();
public CallbackServiceImpl() { Thread t = new Thread(new Runnable() { public void run() { while(true) { try { for(Map.Entry<String, CallbackListener> entry : listeners.entrySet()){ try { entry.getValue().changed(getChanged(entry.getKey())); } catch (Throwable t) { listeners.remove(entry.getKey()); } }
Thread.sleep(5000); // 定时触发变更通知
} catch (Throwable t) { // 防御容错
t.printStackTrace(); } } } });

							t.setDaemon(true);								t.start();				}

public void addListener(String key, CallbackListener listener) {
listeners.put(key, listener);
listener.changed(getChanged(key)); // 发送变更通知
}
private String getChanged(String key) {
return "Changed: " + new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”).format(new Date());
} }

服务提供者配置示例

<dubbo:service interface=“com.callback.CallbackService” ref=“callbackService” connections=“1” callbacks=“1000”> <dubbo:method name=“addListener”>
<dubbo:argument index=“1” callback=“true” />
</dubbo:method> </dubbo:service>

服务消费者配置示例
<dubbo:reference id=“callbackService” interface=“com.callback.CallbackService” />
服务消费者调⽤示例
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(“classpath:consumer.xml”); context.start();
CallbackService callbackService = (CallbackService) context.getBean(“callbackService”);
callbackService.addListener(“http://10.20.160.198/wiki/display/dubbo/foo.bar”, new CallbackListener(){
public void changed(String msg) { System.out.println(“callback1:” + msg); } });

事件通知
在调⽤之前、调⽤之后、出现异常时,会触发 oninvoke 、 onreturn 、 onthrow 三个事件,可以配置当事件发⽣时, 通知哪个类的哪个⽅法
服务提供者与消费者共享服务接⼝
interface IDemoService { public Person get(int id); }
服务提供者实现
class NormalDemoService implements IDemoService {
public Person get(int id) { return new Person(id, “charles`son”, 4); } }

服务提供者配置
<dubbo:application name=“rpc-callback-demo” />
<dubbo:registry address=“http://10.20.160.198/wiki/display/dubbo/10.20.153.186” />

<dubbo:service interface=“com.alibaba.dubbo.callback.implicit.IDemoService” ref=“demoService” version=“1.0.0” g roup=“cn”/>

服务消费者 Callback 接⼝
interface Notify {
public void onreturn(Person msg, Integer id); public void onthrow(Throwable ex, Integer id); }

服务消费者 Callback 实现
class NotifyImpl implements Notify {
public Map<Integer, Person> ret = new HashMap<Integer, Person>();
public Map<Integer, Throwable> errors = new HashMap<Integer, Throwable>();
public void onreturn(Person msg, Integer id) {
System.out.println(“onreturn:” + msg);
ret.put(id, msg); }
public void onthrow(Throwable ex, Integer id) {
errors.put(id, ex); } }

服务消费者 Callback 配置

<dubbo:reference id=“demoService” interface=“com.alibaba.dubbo.callback.implicit.IDemoService” version=“1.0.0” group=“cn” >
<dubbo:method name=“get” async=“true” onreturn = “demoCallback.onreturn” onthrow=“demoCallback.onthrow” />
</dubbo:reference>

callback 与 async 功能正交分解, async=true 表示结果是否⻢上返回, onreturn 表示是否需要回调。 两者叠加存在以下⼏种组合情况 :
异步回调模式: async=true onreturn=“xxx” 同步回调模式: async=false onreturn=“xxx” 异步⽆回调 : async=true 同步⽆回调 : async=false

本地存根
<dubbo:service interface=“com.foo.BarService” stub=“true” />

<dubbo:service interface=“com.foo.BarService” stub=“com.foo.BarServiceStub” />

本地伪装

本地伪装 通常⽤于服务降级,⽐如某验权服务,当服务提供⽅全部挂掉后,客户端不抛出异常,⽽是通过 Mock 数据 返回授权失败。

<dubbo:service interface=“com.foo.BarService” mock=“true” />

<dubbo:service interface=“com.foo.BarService” mock=“com.foo.BarServiceMock” />

如果服务的消费⽅经常需要 try-catch 捕获异常,请考虑改为 Mock 实现,并在 Mock 实现中 return null
<dubbo:service interface=“com.foo.BarService” mock=“return null” />

延迟暴露
你的服务需要预热时间,⽐如初始化缓存,等待相关资源就位等,可以使⽤ delay 进⾏延迟暴露
<dubbo:service delay=“5000” />

并发控制
限制 com.foo.BarService 的每个⽅法,服务器端并发执⾏(或占⽤线程池线程数)不能超过 10 个:
<dubbo:service interface=“com.foo.BarService” executes=“10” />

限制 com.foo.BarService 的 sayHello ⽅法,服务器端并发执⾏(或占⽤线程池线程数)不能超过 10 个:
<dubbo:service interface=“com.foo.BarService”>
<dubbo:method name=“sayHello” executes=“10” />
</dubbo:service>

限制 com.foo.BarService 的每个⽅法,每客户端并发执⾏(或占⽤连接的请求数)不能超过 10 个:
<dubbo:service interface=“com.foo.BarService” actives=“10” />

<dubbo:reference interface=“com.foo.BarService” actives=“10” />

限制 com.foo.BarService 的 sayHello ⽅法,每客户端并发执⾏(或占⽤连接的请求数)不能超过 10 个:
<dubbo:service interface=“com.foo.BarService”>
<dubbo:method name=“sayHello” actives=“10” />
</dubbo:service>

<dubbo:reference interface=“com.foo.BarService”>
<dubbo:method name=“sayHello” actives=“10” />
</dubbo:service>
如果 dubbo:servicedubbo:reference 都配了actives, dubbo:reference 优先

Load Balance 均衡
配置服务的客户端的 loadbalance 属性为 leastactive ,此 Loadbalance 会调⽤并发数最⼩的 Provider(Consumer 端并发数)。
<dubbo:reference interface=“com.foo.BarService” loadbalance=“leastactive” />

<dubbo:service interface=“com.foo.BarService” loadbalance=“leastactive” />

连接控制
服务端连接控制
限制服务器端接受的连接不能超过 10 个 :
<dubbo:provider protocol=“dubbo” accepts=“10” />

<dubbo:protocol name=“dubbo” accepts=“10” />

客户端连接控制
限制客户端服务使⽤连接不能超过 10 个 :
<dubbo:reference interface=“com.foo.BarService” connections=“10” />

<dubbo:service interface=“com.foo.BarService” connections=“10” />
如果 dubbo:servicedubbo:reference 都配了 connections, dubbo:reference 优先

延迟连接
延迟连接⽤于减少⻓连接数。当有调⽤发起时,再创建⻓连接。
<dubbo:protocol name=“dubbo” lazy=“true” />

粘滞连接
粘滞连接⽤于有状态服务,尽可能让客户端总是向同⼀提供者发起调⽤,除⾮该提供者挂了,再连另⼀台。
粘滞连接将⾃动开启延迟连接,以减少⻓连接数。
<dubbo:protocol name=“dubbo” sticky=“true” />

令牌验证
通过令牌验证在注册中⼼控制权限,以决定要不要下发令牌给消费者,可以防⽌消费者绕过注册中⼼访问提供者
可以全局设置开启令牌验证:

<dubbo:provider interface=“com.foo.BarService” token=“true” />

<dubbo:provider interface=“com.foo.BarService” token=“123456” />
也可在服务级别设置:

<dubbo:service interface=“com.foo.BarService” token=“true” />

<dubbo:service interface=“com.foo.BarService” token=“123456” />
还可在协议级别设置:

<dubbo:protocol name=“dubbo” token=“true” />

<dubbo:protocol name=“dubbo” token=“123456” />

路由规则
路由规则 决定⼀次 dubbo 服务调⽤的⽬标服务器,分为条件路由规则和脚本路由规则,并且⽀持可扩展
RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtensio n(); Registry registry = registryFactory.getRegistry(URL.valueOf(“zookeeper://10.20.153.10:2181”)); registry.register(URL.valueOf(“condition://0.0.0.0/com.foo.BarService?category=routers&dynamic=false&rule=” + U RL.encode(“host = 10.20.153.10 => host = 10.20.153.11”) + "));
其中: condition:// 表示路由规则的类型,⽀持条件路由规则和脚本路由规则,可扩展,必填。 0.0.0.0 表示对所有 IP 地址⽣效,如果只想对某个 IP 的⽣效,请填⼊具体 IP,必填。 com.foo.BarService 表示只对指定服务⽣效,必填。 category=routers 表示该数据为动态配置类型,必填。 dynamic=false 表示该数据为持久数据,当注册⽅退出时,数据依然保存在注册中⼼,必填。 enabled=true 覆盖规则是否⽣效,可不填,缺省⽣效。 force=false 当路由结果为空时,是否强制执⾏,如果不强制执⾏,路由结果为空的路由规则将⾃动失效,可不 填,缺省为 flase 。 runtime=false 是否在每次调⽤时执⾏路由规则,否则只在提供者地址列表变更时预先执⾏并缓存结果,调⽤时直 接从缓存中获取路由结果。如果⽤了参数路由,必须设为 true ,需要注意设置会影响调⽤的性能,可不填,缺省 为 flase 。 priority=1 路由规则的优先级,⽤于排序,优先级越⼤越靠前执⾏,可不填,缺省为 0 。 rule=URL.encode(“host = 10.20.153.10 => host = 10.20.153.11”) 表示路由规则的内容,必填

基于条件表达式的路由规则,如: host = 10.20.153.10 => host = 10.20.153.11
规则:
=> 之前的为消费者匹配条件,所有参数和消费者的 URL 进⾏对⽐,当消费者满⾜匹配条件时,对该消费者执⾏ 后⾯的过滤规则。 => 之后为提供者地址列表的过滤条件,所有参数和提供者的 URL 进⾏对⽐,消费者最终只拿到过滤后的地址列 表。 如果匹配条件为空,表示对所有消费⽅应⽤,如: => host != 10.20.153.11 如果过滤条件为空,表示禁⽌访问,如: host = 10.20.153.10 =>
表达式:
参数⽀持: 服务调⽤信息,如:method, argument 等,暂不⽀持参数路由 URL 本身的字段,如:protocol, host, port 等 以及 URL 上的所有参数,如:application, organization 等
条件⽀持: 等号 = 表示"匹配",如: host = 10.20.153.10 不等号 != 表示"不匹配",如: host != 10.20.153.10
值⽀持: 以逗号 , 分隔多个值,如: host != 10.20.153.10,10.20.153.11 以星号 * 结尾,表示通配,如: host != 10.20.* 以美元符 $ 开头,表示引⽤消费者参数,如: host = $host

脚本路由规则
脚本路由规则 ⽀持 JDK 脚本引擎的所有脚本,⽐如:javascript, jruby, groovy 等,通过 type=javascript 参数设置 脚本类型,缺省为 javascript。
“script://0.0.0.0/com.foo.BarService?category=routers&dynamic=false&rule=” + URL.encode(“function route(invoker s) { … } (invokers)”)
基于脚本引擎的路由规则,如:
function route(invokers) { var result = new java.util.ArrayList(invokers.size()); for (i = 0; i < invokers.size(); i ++) { if (“10.20.153.10”.equals(invokers.get(i).getUrl().getHost())) { result.add(invokers.get(i)); } } return result; } (invokers); // 表示⽴即执⾏⽅法

配置规则
向注册中⼼写⼊动态配置覆盖规则 。该功能通常由监控中⼼或治理中⼼的⻚⾯完成。
RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtensio n(); Registry registry = registryFactory.getRegistry(URL.valueOf(“zookeeper://10.20.153.10:2181”)); registry.register(URL.valueOf(“override://0.0.0.0/com.foo.BarService?category=configurators&dynamic=false&appli cation=foo&timeout=1000”));
其中: override:// 表示数据采⽤覆盖⽅式,⽀持 override 和 absent ,可扩展,必填。 0.0.0.0 表示对所有 IP 地址⽣效,如果只想覆盖某个 IP 的数据,请填⼊具体 IP,必填。 com.foo.BarService 表示只对指定服务⽣效,必填。 category=configurators 表示该数据为动态配置类型,必填。 dynamic=false 表示该数据为持久数据,当注册⽅退出时,数据依然保存在注册中⼼,必填。 enabled=true 覆盖规则是否⽣效,可不填,缺省⽣效。 application=foo 表示只对指定应⽤⽣效,可不填,表示对所有应⽤⽣效。 timeout=1000 表示将满⾜以上条件的 timeout 参数的值覆盖为 1000。如果想覆盖其它参数,直接加在 override 的 URL 参数上。
示例: 1. 禁⽤提供者:(通常⽤于临时踢除某台提供者机器,相似的,禁⽌消费者访问请使⽤路由规则)
override://10.20.153.10/com.foo.BarService?category=configurators&dynamic=false&disbaled=true
2. 调整权重:(通常⽤于容量评估,缺省权重为 100)
override://10.20.153.10/com.foo.BarService?category=configurators&dynamic=false&weight=200
3. 调整负载均衡策略:(缺省负载均衡策略为 random)
override://10.20.153.10/com.foo.BarService?category=configurators&dynamic=false&loadbalance=leastactive
4. 服务降级:(通常⽤于临时屏蔽某个出错的⾮关键服务)
override://0.0.0.0/com.foo.BarService?category=configurators&dynamic=false&application=foo&mock=force:retu rn+null

服务降级
可以通过服务降级功能 临时屏蔽某个出错的⾮关键服务,并定义降级后的返回策略。
RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtensio n(); Registry registry = registryFactory.getRegistry(URL.valueOf(“zookeeper://10.20.153.10:2181”)); registry.register(URL.valueOf(“override://0.0.0.0/com.foo.BarService?category=configurators&dynamic=false&appli cation=foo&mock=force:return+null”));
其中: mock=force:return+null 表示消费⽅对该服务的⽅法调⽤都直接返回 null 值,不发起远程调⽤。⽤来屏蔽不重要服 务不可⽤时对调⽤⽅的影响。 还可以改为 mock=fail:return+null 表示消费⽅对该服务的⽅法调⽤在失败后,再返回 null 值,不抛异常。⽤来容 忍不重要服务不稳定时对调⽤⽅的影响。

主机绑定
<dubbo:protocol host=“205.182.23.201”>

端⼝配置
dubbo 20880
rmi 1099
http 80
hessian 80
webservice 80
memcached 11211
redis 6379

⽇志适配

<dubbo:application logger=“log4j” />

dubbo.application.logger=log4j

API 汇总如下:
配置 API
com.alibaba.dubbo.config.ServiceConfig
com.alibaba.dubbo.config.ReferenceConfig
com.alibaba.dubbo.config.ProtocolConfig
com.alibaba.dubbo.config.RegistryConfig
com.alibaba.dubbo.config.MonitorConfig
com.alibaba.dubbo.config.ApplicationConfig
com.alibaba.dubbo.config.ModuleConfig
com.alibaba.dubbo.config.ProviderConfig
com.alibaba.dubbo.config.ConsumerConfig
com.alibaba.dubbo.config.MethodConfig
com.alibaba.dubbo.config.ArgumentConfig
注解 API
com.alibaba.dubbo.config.annotation.Service
com.alibaba.dubbo.config.annotation.Reference
模型 API

com.alibaba.dubbo.common.URL
com.alibaba.dubbo.rpc.RpcException
上下⽂ API
com.alibaba.dubbo.rpc.RpcContext
服务API

com.alibaba.dubbo.rpc.service.GenericService
com.alibaba.dubbo.rpc.service.GenericException
com.alibaba.dubbo.rpc.service.EchoService

功能使用

1)在泛化引用dubbo时,因为referencrConfig是一个很重的实例,所以需要使用到缓存
ReferenceConfigCache cache = ReferenceConfigCache.getCache();
GenericService service = cache.get(config);//config是ReferenceConfig实例

2)dubbo-admin管理平台搭建
通过dubbo-admin可以对消费者和提供者进行管理.可自行到官网下载:https://github.com/apache/incubator-dubbo-ops下载。

下载下来后,进入incubator-dubbo-ops文件夹,在此处打开命令行窗口;
执行 mvn package -Dmaven.test.skip=true 命令,打包该项目;
在生成的target文件夹中找到dubbo-admin的jar包,在命令行执行该项目就好了;
根据打印的日志找到 current host:yourip 和 Tomcat started on port(s): yourport
浏览器访问yourip:yourport;
用户名和密码都输入root或都输guest,即可登录成功

猜你喜欢

转载自blog.csdn.net/zhanglinlove/article/details/83757806