1、默认使用的是什么通信框架,还有别的选择吗?
Dubbo默认使用netty,还支持mina, grizzy
配置方式:
<dubbo:protocol name=“dubbo” port=“9090” server=“netty” client=“netty” codec=“dubbo” serialization=“hessian2”
charset=“UTF-8” threadpool=“fixed” threads=“100” queues=“0” iothreads=“9” buffer=“8192” accepts=“1000” payload=“8388608” />
- Transporter: mina, netty, grizzy
- Serialization: dubbo, hessian2, java, json
- Dispatcher: all, direct, message, execution, connection
- ThreadPool: fixed, cached
Dubbo缺省协议采用单一长连接和NIO异步通讯,适合于小数据量大并发的服务调用,以及服务消费者机器数远大于服务提供者机器数的情况。
Mina:
Mina(Multipurpose Infrastructure for Network Applications) 是 Apache 组织一个较新的项目,它为开发高性能和高可用性的网络应用程序提供了非常便利的框架。当前发行的 Mina 版本2.04支持基于 Java NIO 技术的 TCP/UDP 应用程序开发、串口通讯程序,Mina 所支持的功能也在进一步的扩展中。目前,正在使用 Mina的应用包括:Apache Directory Project、AsyncWeb、AMQP(Advanced Message Queuing Protocol)、RED5 Server(Macromedia Flash Media RTMP)、ObjectRADIUS、 Openfire等等。
Netty:
Netty是一款异步的事件驱动的网络应用框架和工具,用于快速开发可维护的高性能、高扩展性协议服务器和客户端。也就是说,Netty是一个NIO客户端/服务器框架,支持快速、简单地开发网络应用,如协议服务器和客户端。它极大简化了网络编程,如TCP和UDP套接字服务器。
Grizzly:
Grizzly是一种应用程序框架,专门解决编写成千上万用户访问服务器时候产生的各种问题。使用JAVA NIO作为基础,并隐藏其编程的复杂性。容易使用的高性能的API。带来非阻塞socketd到协议处理层。利用高性能的缓冲和缓冲管理使用高性能的线程池。
2、服务调用是阻塞的吗?
Dubbo默认为同步阻塞调用,但是也支持异步调用(有返回值、无返回值两种)
异步无返回值:
所谓“无返回值”异步调用是指服务消费方只管调用,但不关心调用结果,此时 Dubbo 会直接返回一个空的 RpcResult。若要使用异步特性,需要服务消费方手动进行配置。
异步有返回值:
返回一个Future
服务调用过程如下:
public class DubboInvoker<T> extends AbstractInvoker<T> {private final ExchangeClient[] clients;protected Result doInvoke(final Invocation invocation) throws Throwable {RpcInvocation inv = (RpcInvocation) invocation;final String methodName = RpcUtils.getMethodName(invocation);// 设置 path 和 version 到 attachment 中inv.setAttachment(Constants.PATH_KEY, getUrl().getPath());inv.setAttachment(Constants.VERSION_KEY, version);ExchangeClient currentClient;if (clients.length == 1) {// 从 clients 数组中获取 ExchangeClientcurrentClient = clients[0];} else {currentClient = clients[index.getAndIncrement() % clients.length];}try {// 获取异步配置boolean isAsync = RpcUtils.isAsync(getUrl(), invocation);// isOneway 为 true,表示“单向”通信boolean isOneway = RpcUtils.isOneway(getUrl(), invocation);int timeout = getUrl().getMethodParameter(methodName, Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT);// 异步无返回值if (isOneway) {boolean isSent = getUrl().getMethodParameter(methodName, Constants.SENT_KEY, false);// 发送请求currentClient.send(inv, isSent);// 设置上下文中的 future 字段为 nullRpcContext.getContext().setFuture(null);// 返回一个空的 RpcResultreturn new RpcResult();} // 异步有返回值else if (isAsync) {// 发送请求,并得到一个 ResponseFuture 实例ResponseFuture future = currentClient.request(inv, timeout);// 设置 future 到上下文中RpcContext.getContext().setFuture(new FutureAdapter<Object>(future));// 暂时返回一个空结果return new RpcResult();} // 同步调用else {RpcContext.getContext().setFuture(null);// 发送请求,得到一个 ResponseFuture 实例,并调用该实例的 get 方法进行等待return (Result) currentClient.request(inv, timeout).get();}} catch (TimeoutException e) {throw new RpcException(..., "Invoke remote method timeout....");} catch (RemotingException e) {throw new RpcException(..., "Failed to invoke remote method: ...");}}// 省略其他方法
}
3、一般使用什么注册中心?还有别的选择吗?
推荐使用zookeeper注册中心,还有Multicast、Redis和Simple等。
3.1 zookeeper 注册中心
Zookeeper 是 Apacahe Hadoop 的子项目,是一个树型的目录服务,支持变更推送,适合作为 Dubbo 服务的注册中心,工业强度较高,可用于生产环境,并推荐使用 [1]。
流程说明:
- 服务提供者启动时: 向 /dubbo/com.foo.BarService/providers 目录下写入自己的 URL 地址
- 服务消费者启动时: 订阅 /dubbo/com.foo.BarService/providers 目录下的提供者 URL 地址。并向 /dubbo/com.foo.BarService/consumers 目录下写入自己的 URL 地址
- 监控中心启动时: 订阅 /dubbo/com.foo.BarService 目录下的所有提供者和消费者 URL 地址。
支持以下功能:
- 当提供者出现断电等异常停机时,注册中心能自动删除提供者信息
- 当注册中心重启时,能自动恢复注册数据,以及订阅请求
- 当会话过期时,能自动恢复注册数据,以及订阅请求
- 当设置 <dubbo:registry check=“false” /> 时,记录失败注册和订阅请求,后台定时重试
- 可通过 <dubbo:registry username=“admin” password=“1234” /> 设置 zookeeper 登录信息
- 可通过 <dubbo:registry group=“dubbo” /> 设置 zookeeper 的根节点,不设置将使用无根树
- 支持 * 号通配符 <dubbo:reference group="" version="" />,可订阅服务的所有分组和所有版本的提供者
3.2 Multicast 注册中心:
Multicast 注册中心不需要启动任何中心节点,只要广播地址一样,就可以互相发现。
- 提供方启动时广播自己的地址
- 消费方启动时广播订阅请求
- 提供方收到订阅请求时,单播自己的地址给订阅者,如果设置了 unicast=false,则广播给订阅者
- 消费方收到提供方地址时,连接该地址进行 RPC 调用。
组播受网络结构限制,只适合小规模应用或开发阶段使用。组播地址段: 224.0.0.0 - 239.255.255.255
3.3 Redis 注册中心
基于 Redis 实现的注册中心。
使用 Redis 的 Key/Map 结构存储数据结构:
- 主 Key 为服务名和类型
- Map 中的 Key 为 URL 地址
- Map 中的 Value 为过期时间,用于判断脏数据,脏数据由监控中心删除 [3]
使用 Redis 的 Publish/Subscribe 事件通知数据变更:
- 通过事件的值区分事件类型:register, unregister, subscribe, unsubscribe
- 普通消费者直接订阅指定服务提供者的 Key,只会收到指定服务的 register, unregister 事件
- 监控中心通过 psubscribe 功能订阅 /dubbo/*,会收到所有服务的所有变更事件
调用过程:
-
服务提供方启动时,向 Key:/dubbo/com.foo.BarService/providers 下,添加当前提供者的地址
-
并向 Channel:/dubbo/com.foo.BarService/providers 发送 register 事件
-
服务消费方启动时,从 Channel:/dubbo/com.foo.BarService/providers 订阅 register 和 unregister 事件
-
并向 Key:/dubbo/com.foo.BarService/consumers 下,添加当前消费者的地址
-
服务消费方收到 register 和 unregister 事件后,从 Key:/dubbo/com.foo.BarService/providers 下获取提供者地址列表
-
服务监控中心启动时,从 Channel:/dubbo/* 订阅 register 和 unregister,以及 subscribe 和unsubsribe事件
-
服务监控中心收到 register 和 unregister 事件后,从 Key:/dubbo/com.foo.BarService/providers 下获取提供者地址列表
-
服务监控中心收到 subscribe 和 unsubsribe 事件后,从 Key:/dubbo/com.foo.BarService/consumers 下获取消费者地址列表
可靠性声明
阿里内部并没有采用 Redis 做为注册中心,而是使用自己实现的基于数据库的注册中心,即:Redis 注册中心并没有在阿里内部长时间运行的可靠性保障,此 Redis 桥接实现只为开源版本提供,其可靠性依赖于 Redis 本身的可靠性。
3.4 Simple 注册中心
Simple 注册中心本身就是一个普通的 Dubbo 服务,可以减少第三方依赖,使整体通讯方式一致。
配置
将 Simple 注册中心暴露成 Dubbo 服务:
<?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://dubbo.apache.org/schema/dubbo"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd"><!-- 当前应用信息配置 --><dubbo:application name="simple-registry" /><!-- 暴露服务协议配置 --><dubbo:protocol port="9090" /><!-- 暴露服务配置 --><dubbo:service interface="org.apache.dubbo.registry.RegistryService" ref="registryService" registry="N/A" ondisconnect="disconnect" callbacks="1000"><dubbo:method name="subscribe"><dubbo:argument index="1" callback="true" /></dubbo:method><dubbo:method name="unsubscribe"><dubbo:argument index="1" callback="false" /></dubbo:method></dubbo:service><!-- 简单注册中心实现,可自行扩展实现集群和状态同步 --><bean id="registryService" class="org.apache.dubbo.registry.simple.SimpleRegistryService" />
</beans>
引用 Simple Registry 服务:
<dubbo:registry address="127.0.0.1:9090" />
或者:
<dubbo:service interface="org.apache.dubbo.registry.RegistryService" group="simple" version="1.0.0" ... >
或者:
<dubbo:registry address="127.0.0.1:9090" group="simple" version="1.0.0" />