注册中心
dubbo支持多注册中心,不仅支持多种形式的注册中心,还支持向多个注册中心注册。目前dubbo支持的注册中心有如下四种
Multicast注册中心
该注册中心不需要启动任何中心节点,只要广播地址一样,就可以互相发现。组播受网络结果影响,只适合小规模的应用或开发阶段使用。
ZooKeeper 注册中心
是一个树形的目录服务,为分布式应用提供一致性服务,还支持变更推送功能,推荐生产环境使用
Redis注册中心
基于redis实现的注册中心,使用key/value结构存储服务的url地址和过期时间,同时使用redis的publish/subscribe事件通知数据变更。
Simple注册中心
它本身就是一个dubbo服务,可以减少第三方的依赖,是整体通讯方式一致。
由于dubbo建议使用zk作为注册中心,所以本文主要介绍zk注册中心。
我们在服务提供者、消费者的配置文件使用了<dubbo:registry/>标签后指定zk的地址后,就可以使用zk注册中心了配置如下,两种方式
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<dubbo:registry protocol="zookeeper" address="127.0.0.1:2181"/>
dubbo目前支持zkclient和curator两种zk的客户端实现,默认是zkclient,如果想要使用curator,则可以定制client="curator"
<dubbo:registry address="zookeeper://127.0.0.1:2181" client="curator"/>
还可以使用group属性将同一个zk分成多组注册中心,代码如下
<dubbo:registry id="shanghairegistry" address="zookeeper://127.0.0.1:2181" group="shanghai"/>
<dubbo:registry id="beijingregistry" address="zookeeper://127.0.0.1:2181" group="beijing"/>
前面说的都是单机配置,那么zk的集群配置方式呢?两种方式如下
<dubbo:registry address="zookeeper://127.0.0.1:2181?backup=127.0.0.2:2181,127.0.0.3:2181" />
<dubbo:registry protocol="zookeeper" address="127.0.0.1:2181,127.0.0.2:2181,127.0.0.3:2181" />
除了可以向zk的集群模式注册中心注册,还可以向多个注册中心注册
<dubbo:registry id= "shanghairegistry" address="zookeeper://127.0.0.1:2181"/>
<dubbo:registry id= "beijingregistry" address="zookeeper://127.0.0.1:2182"/>
<dubbo:service interface="com.yang.test.api.TestService" ref="testServcie" registry="shanghairegistry,beijingregistry"/>
服务暴露
在通过注册中心注册后,是如何提供服务给消费者使用的呢?这就需要<dubbo:service/>标签进行服务暴露了,用法如下
<dubbo:service interface="com.yang.test.api.TestService" ref="testServcie"/>
其中,interface属性提供服务的接口,ref属性是该接口的具体实现类的引用。
如果服务需要预热的时间,比如初始化缓存,等待相关资源就位等,可以使用delay属性进行服务延迟暴露,用法如下
<dubbo:service interface="com.yang.test.api.TestService" ref="testServcie" delay="5000"/> //或者设置-1,表示延迟到spring初始化完成后暴露服务
如果一个服务的并发量过大,超出了服务器的承载能力,可以使用executes属性控制并发。
<dubbo:service interface="com.yang.test.api.TestService" ref="testServcie" executes="10"/>//并发执行(或占用的线程池的线程数)不能超过10个
除了限制接口,还可以具体到接口内的某一个方法,代码如下
<dubbo:service interface="com.yang.test.api.TestService" ref="testServcie">
<dubbo:method name="sayHello" executes="10"/>
</dubbo:service>
以上是从提供者实现的并发控制,客户端同样可以实现控制并发,即通过active属性限制代码如下
<dubbo:service interface="com.yang.test.api.TestService" ref="testServcie" actives="10" />//限制每个客户端的并发执行(占线程的请求数)不超过10个
同服务提供者一样,也可以限制到具体的方法
<dubbo:service interface="com.yang.test.api.TestService" ref="testServcie">
<dubbo:method name="sayHello" actives="10"/>
<!--不建议在客户端控制并发,应由服务提供者来控制-->
</dubbo:service>
如果线程超过了给定的值,就会报异常。
为了保障服务的 稳定性,除了限制并发线程,还可以限制服务端的链接数量。
<dubbo:protocol name="dubbo" port="20880" accepts="10"/>
<dubbo:provider protocol="dubbo" accepts="10"/>
同样,也可以限制客户端的使用连接数量
<dubbo:service interface="com.yang.test.api.TestService" ref="testServcie" connections="10"/>
<dubbo:reference id="testService" interface="com.yang.test.api.TestService" connections="10"/>
如果<dubbo:service/> <dubbo:reference/> 都配置了connections,则<dubbo:reference/>优先,由于服务提供者更了解自身的承载能力,建议服务提供者控制连接数。
在服务报暴露过程中,除了控制并发,控制连接数,服务隔离也是一项重要的措施,dubbo提供了分组隔离,即前面的group属性分组。
引用服务
在服务提供者暴露了服务后,消费者就可以使用如下方式引用服务了。
<dubbo:reference id="testService" interface="com.yang.test.api.TestService"/>
在默认情况下使用同步方式远程调用的,如果想使用异步方式,则可以设置async属性为true,并使用Future获取返回值,代码如下
<dubbo:reference id="testService" interface="com.yang.test.api.TestService">
<dubbo:method name="sayHello" async="true"/>
</dubbo:reference>
然后在代码中通过以下方式异步调用
@RestController
@RequestMapping("/")
public class TestController {
@Autowired
private TestService testService;
@RequestMapping("test")
public String hello() throws Exception{
testService.sayHello("Hello springboot-dubbo!");
//拿到future引用
Future<String> future = RpcContext.getContext().getFuture();
//如果已返回,则直接拿到返回值,否则线程等待(wait),直到拿到返回值,线程才会被唤醒(notify)
String result = future.get();
return result;
}
}
在异步调用中还可以设置是否需要等待发送和返回值,设置如下
sent = "true" ,等待消息发出,消息发送失败抛出异常。
sent = "false" 不等待消息发出,将消息放入I/O队列,即可返回。
return = "false" 只是想异步,完全忽略返回值 以减少Future对象的创建和管理
<dubbo:reference id="testService" interface="com.yang.test.api.TestService">
<dubbo:method name="sayHello" async="true" sent="true"/>
</dubbo:reference>
<dubbo:reference id="testService" interface="com.yang.test.api.TestService">
<dubbo:method name="sayHello" async="true" sent="false"/>
</dubbo:reference>
<dubbo:reference id="testService" interface="com.yang.test.api.TestService">
<dubbo:method name="sayHello" async="true" return="false"/>
</dubbo:reference>
Dubbo中的异步调用时基于N/O的非阻塞机制实现的,客户端不需要开始多线程即可实现,相对线程开销小。
Dubbo回调
Dubbo远程调用过程中如果出现了异常或着需要回调,则可以使用dubbo的事件通知机制,主要一下三总
oninvoke(原参数1,原参数2。。。) 为在发起远程调用之前触发的事件
onreturn(返回值,原参数1,原参数2。。。) 为在远程调用之后的回调事件
onthrow(Throwable ex原参数1,原参数2。。。,) 为出现异常时候触发的事件,可以在该事件实现服务降级。
在消费者实现事件通知时候,先定义一个INotify,并实现相关业务。
public interface INotify {
void onreturn(String resStr,String inSter);
void onthrow(Throwable ex,String resStr,String inSter);
void oninvoke(String resStr,String inSter);
}
实现接口
public class notiryImpl implements INotify{
@Override
public void onreturn(String resStr, String inSter) {
System.out.println("after");
}
@Override
public void onthrow(Throwable ex, String resStr, String inSter) {
System.out.println("yichang");
}
@Override
public void oninvoke(String resStr, String inSter) {
System.out.println("before");
}
}
然后就是在配置文件中配置
<dubbo:reference id="testService" interface="com.yang.test.api.TestService">
<dubbo:method name="sayHello" async="true" onreturn="notify.onreturn" onthrow="notify.onthrow"/>
</dubbo:reference>
Dubbo缓存
dubbo为了加速热门数据的访问速度,提供了声明式缓存,可以在消费方配置cache属性开始缓存功能.
<dubbo:reference id="testService" interface="com.yang.test.api.TestService" cache="lru" />
缓存类型:
lru 基于最近最少使用原则删除多余的缓存,保持最热的数据被缓存
Threadlocal:当前的线程缓存
jache :如jsr107继承,可以桥接各种缓存实现。