您的位置:首页 > 其它

RPC实践(五)Dubbo实践-服务集群

2016-12-27 22:08 519 查看
在上篇文章中描述了如何进行dubbo开发实践,但是有2个问题没有展开进一步的陈述

1) 没有描述将myeclipse环境的工程打包发布

2) 使用dubbo最终的目标是进行为了服务能集群提供服务的,即服务部署在多点同时提供服务

本篇就从这两点,来完善Dubbo的实践。

一、myeclipse环境下maven工程dubbo服务端的发布

1) 修改 pom.xml ,在build 节点添加如下内容

<build>
<!-- 打包插件的配置方法-->
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>com.study.app.ProviderMain</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
<!-- 指定jar版本,解决maven工程update object后自动采用jdk1.5-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
这两个plugin分别是打包和解决jdk变化的问题。com.study.app.ProviderMain是server工程的入口类, jar-with-dependencies 是将依赖的包也打到jar里面。不过这种打包会将依赖的jar包,以class的方式打包,如果想要以jar的方式,需要另外配置,这个等下描述解决的办法。

2) 用maven 打包

这样修改pom.xml后,在myeclipse里面,右键-》maven4eclipse-》update project 然后,切换到命令行,进入当前这个myeclipse目录,执行mvn
assembly:assembly命令,如果报版本错误,需要检查mvn的版本和jdk是否吻合,本例中是maven 3.3.9,对应jdk 是1.7以上。如果一些正常,执行后,命令cmd窗口显示如下:



在myeclipse_workspace\StudyDubboServer\target 目录下,会生成刚才打包的jar包



我们可以用解压缩工具打开看看:



这些依赖包都是以class方式解压存在的。

3)部署应用jar包

下面我们先将jar包传到 144服务器的部署目录,确保zookeeper和dubbo admin 都正常运行的情况下,用命令行方式:  java -jar  StudyDubboServer-0.1-jar-with-dependencies.jar 方式启动服务,发现启动失败,报错了,错误如下:



这种cev-etl.1错误是应为spring版本不一致或者xsd文件无法从网络上进行下载校验所致。解决办法如下:

首先确定pom.xml中的依赖sping jar包在正确,本例中修改去掉org.springframework的依赖,因为dubbo本身会将spring引入

<dependency>

       <groupId>org.springframework</groupId>

       <artifactId>spring-context</artifactId>

       <version>3.0.4.RELEASE</version>

    </dependency>

上面的依赖去掉。

      其次修改 applicationProvider.xml文件,将开头的内容修改为

<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 

    classpath:/org/springframework/beans/factory/xml/spring-beans-2.5.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

   注意其中红色的内容,修改完成后,重新update project,然后重新打包,并上传到144 centos虚拟机上,在确保zookeeper和dubbo admin都正常运行情况下,执行命令行启动,



  从dubbo admin的页面上,可以看到Provider是 20880 端口也就是我们在xml中配置的<dubbo:protocol name="dubbo" port="20880"></dubbo:protocol> 。

maven dubboserver工程的发布就写到这里了,对了,前面有提到打包的时候,依赖的jar包,是以class方式打包的,那么我们看下如何调整,似的依赖的jar不解压成class。

解决办法为,进入maven本地库目录,\repository\org\apache\maven\plugins\maven-assembly-plugin\2.2-beta-5,用压缩工具打开maven-assembly-plugin-2.2-beta-5.jar,在assemblies目录下,找到jar-with-dependencies.xml,
打开这个xml,修改如下内容


修改完成后,重新执行mvn assembly:assembly,这样就发现,新打的包里,依赖的jar包不被解压了。重新打包后的jar,用压缩软件打开看,是这样的:



不过这种方式的包,发布后执行会报找不到类错误,判断是因为寻找jar包路径的原因还没有找到合适的办法(先mark一下,以后解决了再来说明),在解决之前,还是先用解压的方式打包好了,关于发布和部署就写到这里,下面我们来看一下服务如何集群发布。

二、dubbo 服务的集群发布

首先将上面的jar包,我们发布到另外一台机器上,192.168.136.151,我们可以看到发布运行后,dubbo admin 已经看到2个相同的服务已经起来了。



   服务的集群实践,我想主要从以下几点来考虑:

   1) 服务的集群如何部署

   2)   服务的管理策略:服务调用如何管理或者失败如何管理

   为了实现上面的想法,在接口里,增加一个invokeid参数,这样就能知道服务端响应调用的是哪个服务了。

   1、接口的修改

1)修改接口api,  HelloServiceApi.java

package com.study.dubbo.demo;

public interface HelloServiceApi {

public  String  sayHello(String name, int invokeId);

public  String  getName ( int invokeId);
}
修改完成后,记住要重新打包       

2)修改服务端, HelloServiceApiImpl.java

package com.study.dubbo.demo;

import   com.study.dubbo.demo.HelloServiceApi;

public class HelloServiceApiImpl implements  HelloServiceApi {

String myName="";

public  String  sayHello(String name, int invokedId){

myName = name;

String ret="InvokeID:"+invokedId+"==>Hello, "+name+"!";

System.out.println(  ret );

return  ret;

}

public  String  getName ( int invokedId ){

System.out.println( "InvokeID:"+invokedId+"==>Now name is:"+ myName+";" );

return  myName;

}

}
           3) 修改客户端,ConsumerMain.java

package com.study.app;

import com.study.dubbo.demo.HelloServiceComsumer;

public class ConsumerMain {

public static void main(String[] args) throws Exception {

HelloServiceComsumer consumerService = new HelloServiceComsumer();

consumerService.getServiceObj();

String myFamily[] = { "Mom", "Daddy", "Honey", "Pretty Girl" };

//这里增加了循环j,用来测试服务集群情况下,分布式调用的情况,如负载均衡
for (int j = 0; j < 10000; j++) {
for (int i = 0; i < myFamily.length; i++) {
consumerService.sayHello(myFamily[i], j);
consumerService.getName(j);

}
}

System.out.println("按任意键退出");
System.in.read();

}

}
客户端还需要修改另外一个文件:HelloServiceComsumer.java

package com.study.dubbo.demo;

import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.study.dubbo.demo.HelloServiceApi;

public class HelloServiceComsumer {

HelloServiceApi demoService;

/*
* 获取服务的Provider对象
*/
public void getServiceObj(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
new String[] { "applicationConsumer.xml" });
context.start();

demoService = (HelloServiceApi) context
.getBean("HelloService");

}

/*
* 调用对象的sayHello 方法
*/
public void sayHello( String name, int invokedId) {

System.out.println(demoService.sayHello( name,  invokedId ));

}

/*
* 调用对象的getName 方法
*/
public String getName( int invokedId ){

String ret=demoService.getName( invokedId );
System.out.println("invokedId:"+invokedId+"==>Now Provider Name is:"+ ret);
return ret;

}

}


以上客户端和服务端修改完成后,都需要重新update project

2、服务集群策略的修改

接口完成了修改后,我们还需要调整服务集群的策略,Dubbo支持比较丰富的集群方式,我们在applicationProvider.xml里面可以这样配置:

<!-- 要暴露的服务接口 -->  

   <dubbo:service interface="com.study.dubbo.demo.HelloServiceApi" ref="HelloService"cluster="failsafe"  loadbalance="random"/>  

    红色是新增的内容,现在将服务端包,和xml重新打包,并发布到144和151上,我们看看调用的情况。

2个服务端启动后,我们可以在myeclipse的客户端工程里面把cli端运行起来,在2个服务端的命令行窗口,我们看到服务调用起来后的情况:

    


  两个服务端的窗口分别打印出客户端调用的情况,可以看到有时候是144主机上的服务被调用,有时候是151主机上的服务被调用。 上图中还有一个有意思的地方,调用id 96,97 圈红框处,可以看到因为服务进程的不同,所以调用结果 Now name是不同的。因为这里name变量进程内的一个局部变量,在不同进程空间里面。由此,分布式服务要特别注意这些细节,以免服务并非自己想要的结果。

回过来看一下cluster="failsafe"  loadbalance="random" ,这里loadbalance 是负载均衡的意思,取值含义说明如下:

        loadbalance="random"  意思是服务端采用随机,按权重设置随机概率。(所以上面截图看到基本上交替的调用)

loadbalance="roundrobin"  轮循,按公约后权重设置轮循比率。

        loadbalance="LeastActive"  最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差

        loadbalance="ConsistentHash"  一致性Hash,相同参数的请求总是发到同一提供者

        再看cluster选项(集群策略):

        Failover Cluster :失败自动切换,当出现失败,重试其它服务器,通常用于读操作(推荐使用)

        Failfast Cluster :快速失败,只发起一次调用,失败立即报错,通常用于非幂等性的写操作

        Failsafe Cluster : 失败安全,出现异常时,直接忽略,通常用于写入审计日志等操作

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

        Forking Cluster : 并行调用多个服务器,只要一个成功即返回,通常用于实时性要求较高的读操作

        Broadcast Cluster : 广播调用所有提供者,逐个调用,任意一台报错则报错,通常用于更新提供方本地状态

好了,服务集群基本上就实践到这里,需要说明的是,在我本机调用的情况看调用的效率并不是很高(循环10000次,每次调用8个接口)经历了好几十秒,也可能是我自己设置的问题,这个需要以后专门花些时间来测试一下调用效率。小伙伴如果有效率方面的经验,也可以留言告诉我,谢谢。

  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: