深度学习 Dubbo

灵动的艺术

向作者提问

CSDN博客专家:https://summer.blog.csdn.net/
GitHub开源博主:https://github.com/Jaysong2012 欢迎大家围观。

查看本场Chat

Apache Dubbo (incubating) |ˈdʌbəʊ| 是一款高性能、轻量级的开源 Java RPC
框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。

Apache 如是评价这个由阿里巴巴捐赠给 Apache 并成为 Apache 顶级项目的 Java 高性能 RPC 服务框架。

如果到目前为止,你还不知道或者不了解 Dubbo ,请移步百度百科或者查看 Dubbo 官网 http://dubbo.apache.org ,Dubbo
的介绍说明,不是本课题的重点。

Java RMI 入门

Java RMI (Remote Method Invocation)- 远程方法调用。它的核心思想就是让你的客户端像使用本地调用一样调用服务端 Java
虚拟机中的对象方法。RMI 是面向对象语言领域对 RPC (Remote Procedure Call)的完善,它让我们无需依靠 IDL
的帮助来完成分布式调用,而通过依赖接口这种更简单自然的方式。

Java RMI 是 Java 领域创建分布式应用的技术基石。后续的 EJB 技术,以及现代的分布式服务框架,其中的基本理念依旧是 Java RMI
的延续。

一个典型的 RMI 调用将有以下几个角色组成:

  • *注册服务(registry) *: 提供注册表的创建以及查找和命名远程对象的类、接口和异常;
  • 客户端(Client) : 远程服务调用方;
  • 服务端(Server) : 远程服务提供方;
  • 本地存根对象(Stub) : 服务端远程对象的代理对象 stub;
  • 服务端的骨架对象(Skeleton) : 服务端远程对象的辅助对象 skeleton。

一个典型的 RMI 调用将会经历如下几个步骤:

  1. 服务端向 RMI 注册服务绑定自己的地址;
  2. 客户端通过 RMI 注册服务获取目标地址;
  3. 客户端调用本地的 Stub 对象上的方法,和调用本地对象上的方法一致;
  4. 本地存根对象将调用信息打包,通过网络发送到服务端;
  5. 服务端的 Skeleton 对象收到网络请求之后,将调用信息解包;
  6. 然后找到真正的服务对象发起调用,并将返回结果打包通过网络发送回客户端。

完整流程如下图所示: ![RMI 构建图 ](https://www.cs.rutgers.edu/~pxk/417/notes/images/rpc-
rmi_flow.png) 图片来源:https://www.cs.rutgers.edu/~pxk/417/notes/images/rpc-
rmi_flow.png

下面我们通过示例代码来看看 RMI 中的服务注册和发现。

  • 定义一个远程服务接口

    public interface Service extends Remote {
    
    void sayHello(String name) throws RemoteException;

} `

  • 远程服务接口实现

    public class ServiceImpl implements Service{
    
    @Override

    public void sayHello(String name) {

    System.out.println("hello "+name);

    }

} `

  • 服务端的服务注册

        public static void main(String[] args) throws RemoteException{
        Service service = new ServiceImpl(); // 初始化服务对象实例
        // 通过 UnicastRemoteObject.exportObject 生成可以与服务端通讯的 Stub 对象
        Service stub = (Service) UnicastRemoteObject.exportObject(service, 19898); 
        //创建一个本地的 RMI 注册服务,监听端口为 1099。该注册服务运行在服务端,也可以单独启动一个注册服务的进程
        Registry registry = LocateRegistry.createRegistry(1099); 
        //将 Stub 对象绑定到注册服务上,这样,客户端可以通过 service 这个名字查找到该远程对象。
        registry.rebind("service", stub); // #4
    }
  • 客户端的服务发现

    public static void main(String[] args) throws RemoteException, NotBoundException {
    //在 1099 端口上获取注册服务实例
    Registry registry = LocateRegistry.getRegistry(1099);
    从注册服务中查找服务名为 Service 的远程对象
    Service stub = (Service) registry.lookup("service");
    //通过获取的 Stub 对象发起一次 RMI 调用
    stub.sayHello("jaysong");

    }

分别先后启动服务端客户端进程,我们将在客户端成功调用远程服务端提供的远程方法。

Dubbo 基础

Dubbo 的分布式服务框架的基本概念与 RMI 是类似的,同样是使用 Java 的 Interface
作为服务契约,通过注册中心来完成服务的注册和发现,远程通讯的细节也是通过代理类来屏蔽。具体来说,Dubbo 在工作时有以下四个角色参与:

角色 说明
Provider 暴露服务的服务提供方
Consumer 调用远程服务的服务消费方
Registry 服务注册与发现的注册中心
Monitor 统计服务的调用次数和调用时间的监控中心
Container 服务运行容器

调用关系如下:

  1. 服务容器负责启动,加载,运行服务提供者;
  2. 服务提供者在启动时,向注册中心注册自己提供的服务;
  3. 服务消费者在启动时,向注册中心订阅自己所需的服务;
  4. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者;
  5. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用;
  6. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

具体系统架构图如下:
dubbo
图片来源:http://dubbo.apache.org/docs/zh-cn/user/sources/images/dubbo-
architecture.jpg

Dubbo实战

Dubbo 应用一般依托于 Spring 容器(也可以是其他容器),如果我们希望深度学习
Dubbo,自己动手实践是必要的,为了降低大家的学习成本,我这边将以 SpringBoot 为例,Dubbo 的 SpringBoot 集成方案欢迎访问
https://github.com/apache/incubator-dubbo-spring-boot-project
,上面有详细的构建说明,我这里将不赘述了。如果实在不会自己构建,欢迎使用我的 Dubbo
案例项目dubbo(传送门),上面有你想要的全部高级案例。

Dubbo 集群容错

在集群调用失败时,Dubbo 提供了多种容错方案,缺省为 failover 重试。

![Dubbo 集群容错](http://dubbo.apache.org/docs/zh-
cn/user/sources/images/cluster.jpg) 图片来源: http://dubbo.apache.org/docs/zh-
cn/user/sources/images/cluster.jpg

  • Failover Cluster 失败自动切换,当出现失败,重试其它服务器 。通常用于读操作,但重试会带来更长延迟。可通过 retries=”2” 来设置重试次数(不含第一次)。

    @Service(version = "1.0.0",protocol = {"dubbo"},registry = {"zk","redis"},retries = 3,owner = "jaysong")
  • Failfast Cluster 快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。

    @Service(version = "1.0.0",protocol = {"dubbo"},registry = {"zk"},cluster = "failfast",owner = "jaysong")
  • Failsafe Cluster 失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。

  • Failback Cluster 失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。

  • Forking Cluster 并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks=”2” 来设置最大并行数。

  • Broadcast Cluster 广播调用所有提供者,逐个调用,任意一台报错则报错 [2]。通常用于通知所有提供者更新缓存或日志等本地资源信息。

负载均衡

在集群负载均衡时,Dubbo 提供了多种均衡负载均衡策略,缺省为 random 随机调用。

  • Random LoadBalance 随机,按权重设置随机概率。 在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。

    @Service(version = "1.0.0",protocol = {"dubbo"},registry = {"zk","redis"},retries = 3,owner = "jaysong",loadbalance = "roundrobin")
    //配置每一个method的信息
MethodConfig methodConfig = new MethodConfig();
methodConfig.setName("errorTest");
methodConfig.setTimeout(1000);
methodConfig.setLoadbalance("random");
methodConfig.setRetries(1);
  • RoundRobin LoadBalance 轮询,按公约后的权重设置轮询比率。 存在慢的提供者累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。

    //配置每一个method的信息

    MethodConfig methodConfig = new MethodConfig();
    methodConfig.setName(“errorTest”);
    methodConfig.setTimeout(1000);
    methodConfig.setLoadbalance(“roundrobin”);
    methodConfig.setRetries(1);

  • LeastActive LoadBalance 最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。 使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。

  • ConsistentHash LoadBalance 一致性 Hash,相同参数的请求总是发到同一提供者。 当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。 算法参见:http://en.wikipedia.org/wiki/Consistent_hashing

Dubbo 多协议

Dubbo 允许配置多协议,在不同服务上支持不同协议或者同一服务上同时支持多种协议。

  • dubbo:// Dubbo 缺省协议采用单一长连接和 NIO 异步通讯,适合于小数据量大并发的服务调用,以及服务消费者机器数远大于服务提供者机器数的情况。

反之,Dubbo 缺省协议不适合传送大数据量的服务,比如传文件,传视频等,除非请求量很低。

![dubbo protocol ](http://dubbo.apache.org/docs/zh-
cn/user/sources/images/dubbo-protocol.jpg) 图片来源
http://dubbo.apache.org/docs/zh-cn/user/sources/images/dubbo-protocol.jpg

  • rmi:// RMI 协议采用 JDK 标准的 java.rmi.* 实现,采用阻塞式短连接和 JDK 标准序列化方式。适用于传入传出参数数据包大小混合,消费者与提供者个数差不多,可用于传文件。

  • hessian:// Hessian 协议用于集成 Hessian 的服务,Hessian 底层采用 Http 通讯,采用 Servlet 暴露服务,Dubbo 缺省内嵌 Jetty 作为服务器实现。适用于传入传出参数数据包较大,提供者比消费者个数多,提供者压力较大,可用于传文件。 Dubbo 的 Hessian 协议可以和原生 Hessian 服务互操作,即:

    • 提供者用 Dubbo 的 Hessian 协议暴露服务,消费者直接用标准 Hessian 接口调用
    • 或者提供方用标准 Hessian 暴露服务,消费方用 Dubbo 的 Hessian 协议调用。

Dubbo 其他可用的协议包括 http://
、webservice://、thrift://、memcached://、redis://、rest://。如果有兴趣了解,请移步
http://dubbo.apache.org/zh-cn/docs/user/references/protocol/introduction.html
这里不在赘述。

我们是实际使用中,考虑到性能的需要经常需要不同的服务使用不同的协议,当然也有可能不同服务不同注册中心,这里我给大家做了详细演示。


# Dubbo Application
## The default value of dubbo.application.name is ${spring.application.name}
dubbo:
application:
name: dubbo-provider
scan:
base-packages: com.example.dubbo.provider.serviceImpl
protocols:
rmi:
name: rmi
port: 1088
serialization: hessian2
dubbo:
name: dubbo
port: 20880
server: netty
client: netty
codec: dubbo
serialization: hessian2
charset: UTF-8
threadpool: fixed
threads: 100
queues: 0
iothreads: 9
buffer: 8192
accepts: 1000
payload: 1048576
hessian:
name: hessian
port: 18899
serialization: hessian2
payload: 10485760
charset: UTF-8
server: jetty
registries:
zk:
address: zookeeper://192.168.199.8:2181
default: true
redis:
address: redis://192.168.199.7:6379

如上的配置中,我们配置了 3 种不同的协议和 2 个注册中心应对不同的场景需要。

对应服务使用对应协议的配置如下:


@Service(version = “1.0.0”,protocol = {“dubbo”},registry = {“zk”,”redis”},retries = 3,owner = “jaysong”,loadbalance = “roundrobin”)



@Service(version = “1.0.0”,protocol = {“hessian”},registry = {“zk”})

Dubbo Admin控制台

Dubbo 在阿里巴巴时代的时候有一个 dubbo-admin 的监控管理工具,Apache 时代在 Dubbo 2.6.0 版本以前都用的是 dubbo-
admin,可以前往 GitHub 上下载 dubbo-admin:https://github.com/apache/incubator-
dubbo/tree/dubbo-2.6.0 ,或者直接下载一个 dubbo-admin.war 包,修改配置 dubbo.properties。


# 保持心跳的注册中心
dubbo.registry.address=zookeeper://127.0.0.1:2181
# 用户名
dubbo.admin.root.password=root
# 密码
dubbo.admin.guest.password=guest

然后直接在 Tomcat 等 Web 容器中运行,运行效果如下: dubbo-
admin

Dubbo 2.6.0 版本以后,Apache 升级了dubbo-amdin 提供了 incubator-dubbo-ops 管理控制台运维工具使用。

当然很多功能都还在不断的版本迭代升级中(需要优化的点还很多)。可以到 https://github.com/apache/incubator-dubbo-
ops
这里下载最新的,当然我也集成到我的项目里了([传送门](https://github.com/Jaysong2012/dubbo/tree/master/dubbo-
admin))。

运行步骤如下:

  • 修改 application.properties 中的心跳注册中心地址为你自己使用的注册中心地址;

    admin.registry.address=zookeeper://127.0.0.1:2181

    admin.config-center=zookeeper://127.0.0.1:2181
    admin.metadata.address=zookeeper://127.0.0.1:2181

  • 运行 dubbo-admin-backend 项目(spring boot 工程),默认使用 8080 端口,如果端口冲突,可以自行修改;

  • 启动 dubbo-admin-frontend 项目(Node.js Vue 工程,需要安装Node.js),启动步骤如下:

    # 安装依赖

    npm install

    启动项目,默认运行在 8081 端口

    npm run dev

此时访问 http://localhost:8081 ,你将看到如下管理控制台运维页面。 dubbo-
ops

例如,我们查看一个服务的明细: ![detail](https://images.gitbook.cn/cec6b0a0-221b-11e9-b5ff-
bf211fdb8da1)

其他,它可以提供的功能包括:
fun

这里我就不一一演示了,都很简单,大家自己摸索。


本文首发于 GitChat,未经授权不得转载,转载需与 GitChat 联系。

12

写评论

向作者提问

更多资源下载交流请加微信:Morstrong

本资源由微信公众号:光明顶一号,分享,一个用技术共享精品付费资源的公众号!