架构设计:系统间通信(15)——服务治理与Dubbo 上篇

1、上篇中“自定义服务治理框架”的问题

在之前的文章中(《架构设计:系统间通信(13)——RPC实例Apache Thrift 下篇(1)》、《架构设计:系统间通信(14)——RPC实例Apache Thrift 下篇(2)》),我们基于服务治理的基本原理,自己实现了一个基于zookeeper + thrift的服务治理框架。但实际上前文中我们自行设计的服务治理框架除了演示基本原理外,并没有多大的实际使用价值,因为还有很多硬性需求是没有实现的:

  • 访问权限:在整个系统生态环境中,不是任何用户都可以随意访问任何的接口。那么除了访问接口的用户组、用户和密码管理以外(或者是公私钥文件),还需要限制用户的访问权限。例如规定用户组A下所有的用户才能够访问接口X。
  • 版本控制:就像上篇文中描述的问题一样。在比较大的系统中,某一个子系统一般都是使用集群环境运行(有多个工作节点),且必须24小时连续工作不允许中断。那么要进行服务接口升级,一般是先升级一部分服务节点,其间让另一部分服务节点继续提供服务,造成了在一个时间段同一个子系统提供的某一个服务可能出现服务接口版本的不兼容。为了子系统能够保证24小时连续提供服务,就需要标注服务接口的版本号,让之前没有完成升级的服务节点提供/访问老版本的服务接口;已经完成升级的服务节点提供/访问新版本的服务接口。
  • 服务时效控制、次数控制:各个子系统提供的服务本身也是具有时效性的。比如某一个服务Y只在每天早上10:00——11:00才能提供访问服务,且对于某个用户来说每天只能调用100次。再比如说,

    · `

  • 性能措施:性能是评价一款服务治理框架是否优秀的重要标准。在服务治理框架的各层都应该有足够的性能优化措施。例如在服务注册层/服务仓库层,注册通知是如何实现的、“能够提供的”服务列表是否进行本地缓存、缓存何时更新、访问令牌如何实现、如何确定访问节点等等问题都直接影响性能;在RPC层/服务实现层,如何支持非阻塞异步网络IO、是采用现成的网络通信框架(Netty、MINA、Grizzly等等)还是自行编写网络通信框架、如何进行信息的序列化等等问题也会直接影响性能。
  • 其他细节问题:能够应用到生产环境的服务治理框架还需要关注很多细节问题,例如多个子系统所注册服务可能出现的服务名称重复的问题,类似的这种问题如何解决、服务治理框架本身的稳定性如何进行保证、是否需要支持跨语言通信的问题等等。

从这篇文章开始,我们详细介绍一款能够应用到生产环境的服务治理框架:由阿里巴巴开发团开源贡献的DUBBO服务治理框架。希望能够帮助各位读者优化自己的生产环境架构方案。

2、服务治理框架:DUBBO

DUBBO是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,是阿里巴巴SOA服务化治理方案的核心框架,每天为2,000+个服务提供3,000,000,000+次访问量支持,并被广泛应用于阿里巴巴集团的各成员站点。

——摘自DUBBO官网(http://dubbo.io/

在DUBBO的官网有详细的学习资料和实例代码。这里我们介绍DUBBO服务治理框架,是为了将我们这个系列文章的中心思想:系统间通信原理,讲清楚。那么为了讲清楚DUBBO服务治理框架的工作原理,首先我们就要演示一下它的基本使用方法。

3、基本使用

3-1、准备示例工程

您可以在以下站点下载后文中提到的各种组件:

3-1-1、示例工程基本环境

  • 请在工程中引入maven的支持。并且导入相关的依赖(如果您不知道maven为何物,请按这样的简单步骤做:下载一个纯净的eclipse->在市场搜索maven->安装maven插件->打开设置界面指定maven路径->创建maven工程->打开工程下的pom.xml文件):
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>yinwenjie.test</groupId>
    <artifactId>dubboService</artifactId>
    <version>0.0.1</version>
    <packaging>jar</packaging>

    <name>dubboService</name>
    <url>http://maven.apache.org</url>

    <properties>
        <version.log4j>1.2.14</version.log4j>
        <version.slf4j.api>1.7.5</version.slf4j.api>
        <version.slf4j.log4j12>1.7.5</version.slf4j.log4j12>
        <version.slf4j.jcl.over.slf4j>1.7.5</version.slf4j.jcl.over.slf4j>
        <!-- jackson -->
        <jackson.version>1.9.13</jackson.version>
    </properties>

    <dependencies>
        <!-- apache commons -->
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.5</version>
        </dependency>

        <!-- Logging -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${version.slf4j.api}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
            <version>${version.slf4j.jcl.over.slf4j}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>${version.slf4j.log4j12}</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>${version.log4j}</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.7.4</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.7.4</version>
        </dependency>

        <!-- dubbo -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.4.10</version>
        </dependency> 

        <!-- zookeeper -->
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.3.4</version>
        </dependency>
        <dependency>
            <groupId>com.101tec</groupId>
            <artifactId>zkclient</artifactId>
            <version>0.3</version>
        </dependency>
    </dependencies>
</project>

您已经注意到了我们使用的DUBBO的版本为2.4.10,并且准备使用zookeeper作为DUBBO服务管理仓库;zookeeper连接的版本使用3.3.4,还引入了一个0.3版本的zkclient组件。Log4j的支持是我自己的编码习惯,如果您不是用Log4j同样可以运行工程,但是您可以使用System.out的方式输出日志了。

3-1-2、安装并使用zookeeper

如果要使用zookeeper作为DUBBO服务管理仓库,那么您还应该安装zookeeper服务器(单点服务即可)。这篇文章主要讲解的是DUBBO的基本使用,如果您还不了解zookeeper服务的基本知识,可以参考我另外几篇文章《hadoop系列:zookeeper(1)——zookeeper单点和集群安装》、《hadoop系列:zookeeper(2)——zookeeper核心原理(选举)》、《hadoop系列:zookeeper(3)——zookeeper核心原理(事件)》。这里假定您用于测试的zookeeper服务器已经安装成功,并且能够正常使用。

这里要说明一下:在网上能够找到的很多文章中,都是介绍的DUBBO和zookeeper构建工作环境。这让很多读者误以为DUBBO只能和zookeeper联合工作,但实际情况并不是这样的。在DUBBO服务治理框架中,服务管理仓库的主要作用是记录服务状态,通知服务变化,管理服务信息,除了zookeeper以外实际上DUBBO服务治理框架还支持在Redis上实现注册管理仓库。另外还有一个Simple的用于在本地实现一个注册管理仓库,专门用于测试用。

3-3、定义和启动DUBBO-RPC服务器端

由于DUBBO和Spring是无缝集成的,所以当您通过maven引入DUBBO组件时,Spring的基础组件就会被自动引入。DUBBO V2.4.10 版本使用的是Spring 2.5.6的版本。

下面我们首先对DUBBO服务提供端的Spring进行配置:

<?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:context="http://www.springframework.org/schema/context"
    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://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
        http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

    <!-- 注解包扫描位置: -->
    <context:component-scan base-package="yinwenjie.test.dubboService.*" />

    <!-- 接入dubbo的应用程序名称 -->
    <dubbo:application name="ws-demo" />

    <!-- 注册仓库地址:zookeeper组件,192.168.61.128:2181 -->
    <dubbo:registry address="zookeeper://192.168.61.128:2181" />

    <!-- 用dubbo协议在20880端口暴露服务 -->
    <dubbo:protocol name="dubbo" port="20880" />

    <!--
        声明需要暴露的服务接口,
        请注意ref属性中指定的MyService接口实现类,它并没有在xml文件中定义,而是使用注解的方式在class中定义
     -->
    <dubbo:service interface="yinwenjie.test.dubboService.iface.MyService" ref="MyServiceImpl"/>
</beans>

下面是RPC服务接口和服务接口实现的代码:

package yinwenjie.test.dubboService.iface;

/**
 * 这是服务接口
 * @author yinwenjie
 */
public interface MyService {
    /**
     * 这是一个测试接口
     * @param field1 参数1
     * @param field2 参数2
     * @return 相加后返回
     */
    public String doMyTest(String field1 , String field2);
}

服务接口的实现:

package yinwenjie.test.dubboService.impl;

import org.springframework.stereotype.Component;

import yinwenjie.test.dubboService.iface.MyService;

@Component("MyServiceImpl")
public class MyServiceImpl implements MyService {

    /* (non-Javadoc)
     * @see yinwenjie.test.dubboService.iface.MyService#doMyTest(java.lang.String, java.lang.String)
     */
    @Override
    public String doMyTest(String field1, String field2) { 

        return field1 + field2;
    }
}

服务接口和服务接口的实现都是非常简单的JAVA代码了,应该不需要进行什么特别的说明了。只需要补充两个注意事项:

  • 可以看出服务接口和服务接口的实现本身并没有引入和RPC结束任何相关的类,也就是说服务接口和服务接口的实现甚至自己都不知道将被某个RPC框架所调用
  • dubbo:protocol标签中,我们指定的协议名称为dubbo(小写)。这里的bubbo是指的DUBBO服务治理框架中自带的一种RPC协议。就像前文说到的那样,从官网给出的资料来看,DUBBO服务治理框架还支持rmi、hessian、http、webService、Hessian等多种通信协议。

下面我们启动DUBBO-RPC服务器端:

package yinwenjie.test.dubboService;

import org.apache.log4j.BasicConfigurator;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ServiceMainProcessor {
    //Log4j的日志基本配置(要使用这种方式首先引入log4j的支持)
    static {
        BasicConfigurator.configure();
    }

    private static Object WAITOBJECT = new Object();

    public static void main(String[] args) throws Exception {
        new ClassPathXmlApplicationContext(new String[]{"application-service.xml"});

        /*
         * 这里锁定这个应用程序,和DUBBO框架本身的工作原理没有任何关系,只是为了让其不退出
         * 当然您也可以使用ClassPathXmlApplicationContext中的start方法,效果一样。
         *
         * 个人习惯
         * */
        synchronized (ServiceMainProcessor.WAITOBJECT) {
            ServiceMainProcessor.WAITOBJECT.wait();
        }
    }
}

3-4、定义和启动DUBBO-RPC客户端

以下是RPC服务消费方(RPC客户端)的xml配置。在我们的测试工程中,客户端和服务端是放在一个工程里面的。放在一个工程里面是为了节约演示程序在工程设置方面不必要的工作量,但是这不影响它们在两个独立的JVM上面运行,也不影响DUBBO服务治理框架工作原理的演示。下面的XML是DUBBO服务治理框架RPC客户端的spring配置演示:

<?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="ws-demo-client" />

    <!-- 注册仓库地址:zookeeper组件,192.168.61.128:2181 -->
    <dubbo:registry address="zookeeper://192.168.61.128:2181" />

    <!-- 引用的服务,那个interface一定是一个被引入到DUBBO仓库的接口定义 -->
    <dubbo:reference  id="myService" interface="yinwenjie.test.dubboService.iface.MyService"/>
</beans>

对于DUBBO-RPC框架来说,它其中的服务消费者并不需要进行多余的任何定义。只需要知道要访问的服务接口(和定义的服务版本,如果没有定义服务版本默认为0.0.0)。下面的代码将启动DUBBO-RPC客户端,并且完成RPC调用:

package yinwenjie.test.dubboClient;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.BasicConfigurator;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import yinwenjie.test.dubboService.iface.MyService;

public class ClientMainProcessor {
    //Log4j的日志基本配置(要使用这种方式首先引入log4j的支持)
    static {
        BasicConfigurator.configure();
    }

    /**
     * 日志
     */
    private static final Log LOGGER = LogFactory.getLog(ClientMainProcessor.class);

    /**
     * 锁定用
     */
    private static Object WAITOBJECT = new Object();

    public static void main(String[] args) throws Exception {
        ApplicationContext app = new ClassPathXmlApplicationContext(new String[]{"application-client.xml"});

        // 开始RPC调用
        MyService myService = (MyService)app.getBean("myService");
        LOGGER.info("myService = " + myService.doMyTest("1234", "abcde"));

        // 这里锁定这个应用程序,和DUBBO框架本身的工作原理没有任何关系,只是为了让其不退出
        synchronized (ClientMainProcessor.WAITOBJECT) {
            ClientMainProcessor.WAITOBJECT.wait();
        }
    }
}

3-5、运行效果

我们先来看看DUBBO服务治理框架中服务提供端的运行效果:

一定要注意运行效果是加上了Log4j的效果的,如果您没有加载Log4j的依赖,那么应该用System.out进行控制台输出。另外,zookeeper服务器一定要安装好,并且可以正常使用。

以下是DUBBO服务治理框架服务消费者(客户端)的运行效果:

上图红圈处Log4j所打印出来的调用内容,说明DUBBO服务治理框架已经完成了服务实现的调用。

在这个章节中,我们使用的DUBBO的配置文件都是最简化的配置信息。实际上包括service、reference、protocol、registry、application、monitor、module、provider、consumer等在内的DUBBO服务治理框架标签提供了丰富的配置属性。您可以参考官网http://dubbo.io/Configuration+Reference-zh.htm中的详细说明,在下篇文章我们对DUBBO运行原理的讲解中,还会提及其中常用的、比较重要的标签作用。

4、后文介绍

通过这篇文章的讲解,相信读者已经掌握了DUBBO服务治理框架的基本使用方式。下一篇文章开始,我们将介绍DUBBO服务治理框架的运行原理,从它的运行原理中重点窥探我们这个系列讨论中讨论的核心话题:网络IO模型、通信协议、消息封装格式以及这些元素对服务性能的影响。

时间: 2024-10-16 00:42:43

架构设计:系统间通信(15)——服务治理与Dubbo 上篇的相关文章

架构设计:系统间通信(16)——服务治理与Dubbo 中篇(预热)

1.前序 上篇文章中(<架构设计:系统间通信(15)--服务治理与Dubbo 上篇>),我们以示例的方式讲解了阿里DUBBO服务治理框架基本使用.从这节开始我们将对DUBBO的主要模块的设计原理进行讲解,从而帮助读者理解DUBBO是如何工作的.(由于这个章节的内容比较多,包括了知识准备.DUBBO框架概述.DUBBO各模块分析,所以我将把内容切割成多篇文章) 2.基础知识准备 为了让读者更好理解下文讲解的内容,在开始讲解DUBBO框架主要模块前,我们先要介绍一些基础知识.这些基础知识将帮助读者

架构设计:系统间通信(10)——RPC的基本概念

1.概述 经过了详细的信息格式.网络IO模型的讲解,并且通过JAVA RMI的讲解进行了预热.从这篇文章开始我们将进入这个系列博文的另一个重点知识体系的讲解:RPC.在后续的几篇文章中,我们首先讲解RPC的基本概念,一个具体的RPC实现会有哪些基本要素构成,然后我们详细介绍一款典型的RPC框架:Apache Thrift.接下来我们聊聊服务治理和DUBBO服务框架.最后总结一下如何在实际工作中选择合适的RPC框架. 2.RPC概述 2-1.什么是RPC RPC(Remote Procedure

架构设计:系统间通信(36)——Apache Camel快速入门(上)

1.本专题主旨 1-1.关于技术组件 在这个专题中,我们介绍了相当数量技术组件:Flume.Kafka.ActiveMQ.Rabbitmq.Zookeeper.Thrift .Netty.DUBBO等等,还包括本文要进行介绍的Apache Camel.有的技术组件讲得比较深入,有的技术组件则是点到为止.于是一些读者朋友发来信息向我提到,这个专题的文章感觉就像一个技术名词的大杂烩,并不清楚作者的想要通过这个专题表达什么思想. 提出这个质疑的朋友不在少数,所以我觉得有必要进行一个统一的说明.这个专题

架构设计:系统间通信(26)——ActiveMQ集群方案(下)

(接上文<架构设计:系统间通信(26)--ActiveMQ集群方案(上)>) 3.ActiveMQ热备方案 ActiveMQ热备方案,主要保证ActiveMQ的高可用性.这种方案并不像上节中我们主要讨论的ActiveMQ高性能方案那样,同时有多个节点都处于工作状态,也就是说这种方案并不提高ActiveMQ集群的性能:而是从集群中的多个节点选择一个,让其处于工作状态,集群中其它节点则处于待命状态.当主要的工作节点由于各种异常情况停止服务时,保证处于待命的节点能够无缝接替其工作. 3-1.Acti

架构设计:系统间通信(14)——RPC实例Apache Thrift 下篇(2)

(接上篇<架构设计:系统间通信(13)--RPC实例Apache Thrift 下篇(1)>) 3.正式开始编码 我已经在CSDN的资源区上传了这个示例工程的所有代码(http://download.csdn.net/detail/yinwenjie/9289999).读者可以直接到资源下载站进行下载(不收积分哦~~^_^).这篇文章将紧接上文,主要介绍这个工程几个主要的类代码. 3-1.编写服务端主程序 服务端主程序的类名:processor.MainProcessor,它负责在服务端启动A

架构设计:系统间通信(1)——概述从“聊天”开始上篇

从这篇博文开始,我们将进入一个新文章系列.这个文章系列专门整理总结了目前系统间通信的主要原理.手段和实现.我们将讲解典型的信息格式.讲解传统的RMI调用并延伸出来重点讲解RPC调用和使用案例:最后我们还会讲到SOA架构的实现,包括ESB实现和服务注册/治理的实现,同样包括原理.实现和使用案例. 系统间通信是架构师需要掌握的又一个关键技术领域,如果说理解和掌握负载均衡层技术需要您有一定的linux系统知识和操作系统知识的话,那么理解和掌握系统间通信层技术,需要您有一定的编程经验(最好是JAVA编程

架构设计:系统间通信(32)——其他消息中间件及场景应用(下2)

(接上文<架构设计:系统间通信(31)--其他消息中间件及场景应用(下1)>) 5-3.解决方案二:改进半侵入式方案 5-3-1.解决方法一的问题所在 方案一并不是最好的半侵入式方案,却容易理解架构师的设计意图:至少做到业务级隔离.方案一最大的优点在于日志采集逻辑和业务处理逻辑彼此隔离,当业务逻辑发生变化的时候,并不会影响日志采集逻辑. 但是我们能为方案一列举的问题却可以远远多于方案一的优点: 需要为不同开发语言分别提供客户端API包.上文中我们介绍的示例使用JAVA语言,于是 事件/日志采集

架构设计:系统间通信(33)——其他消息中间件及场景应用(下3)

=================================== (接上文:<架构设计:系统间通信(32)--其他消息中间件及场景应用(下2)>) 5-7.解决方案三:非侵入式方案 以上两种方案中为了让业务系统能够集成日志采集功能,我们或多或少需要在业务系统端编写一些代码.虽然通过一些代码结构的设计,可以减少甚至完全隔离这些代码和业务代码的耦合度,但是毕竟需要业务开发团队花费精力对这些代码进行维护,业务系统部署时业务对这些代码的配置信息做相应的调整. 这里我们再为读者介绍一种非侵入式的日

架构设计:系统间通信(22)——提高ActiveMQ工作性能(上)

接上文<架构设计:系统间通信(21)--ActiveMQ的安装与使用> 3.ActiveMQ性能优化思路 上篇文章中的两节内容,主要介绍消息中间件ActiveMQ的安装和基本使用.从上篇文章给出的安装配置和示例代码来看,我们既没有修改ActivieMQ服务节点的任何配置,也没有采用任何的集群方案.这种情况只适合各位读者熟悉ActiveMQ的工作原理和基本操作,但是如果要将ActivieMQ应用在生产环境下,上文中介绍的运行方式远远没有挖掘出它的潜在性能. 根据这个系列文章所陈述的中心思想,系统