转自:http://shiyanjun.cn/archives/341.html
使用Dubbo进行远程调用实现服务交互,它支持多种协议,如Hessian、HTTP、RMI、Memcached、Redis、Thrift等等。由于Dubbo将这些协议的实现进行了封装了,无论是服务端(开发服务)还是客户端(调用服务),都不需要关心协议的细节,只需要在配置中指定使用的协议即可,从而保证了服务提供方与服务消费方之间的透明。
另外,如果我们使用Dubbo的服务注册中心组件,这样服务提供方将服务发布到注册的中心,只是将服务的名称暴露给外部,而服务消费方只需要知道注册中心和服务提供方提供的服务名称,就能够透明地调用服务,后面我们会看到具体提供服务和消费服务的配置内容,使得双方之间交互的透明化。
示例场景
我们给出一个示例的应用场景:
服务方提供一个搜索服务,对服务方来说,它基于SolrCloud构建了搜索服务,包含两个集群,ZooKeeper集群和Solr集群,然后在前端通过Nginx来进行反向代理,达到负载均衡的目的。
服务消费方就是调用服务进行查询,给出查询条件(满足Solr的REST-like接口)。
应用设计
基于上面的示例场景,我们打算使用ZooKeeper集群作为服务注册中心。注册中心会暴露给服务提供方和服务消费方,所以注册服务的时候,服务先提供方只需要提供Nginx的地址给注册中心,但是注册中心并不会把这个地址暴露给服务消费方,如图所示:
我们先定义一下,通信双方需要使用的接口,如下所示:
01 |
package org.shirdrn.platform.dubbo.service.rpc.api;
|
03 |
public interface SolrSearchService {
|
05 |
String search(String collection, String q, ResponseType type, int start, int rows);
|
07 |
public enum ResponseType {
|
基于上图中的设计,下面我们分别详细说明Provider和Consumer的设计及实现。
Provider所发布的服务组件,包含了一个SolrCloud集群,在SolrCloud集群前端又加了一个反向代理层,使用Nginx来均衡负载。Provider的搜索服务系统,设计如下图所示:
上图中,实际Nginx中将请求直接转发内部的Web Servers上,在这个过程中,使用ZooKeeper来进行协调:从多个分片(Shard)服务器上并行搜索,最后合并结果。我们看一下Nginx配置的内容片段:
04 |
error_log /var/log/nginx/error.log warn; |
05 |
pid /var/run/nginx.pid; |
09 |
worker_connections 1024;
|
14 |
include /etc/nginx/mime.types;
|
15 |
default_type application/octet-stream;
|
17 |
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
18 |
'$status $body_bytes_sent "$http_referer" '
|
19 |
'"$http_user_agent" "$http_x_forwarded_for"';
|
21 |
access_log /var/log/nginx/access.log main;
|
31 |
server slave1:8888 weight=1;
|
32 |
server slave4:8888 weight=1;
|
33 |
server slave6:8888 weight=1;
|
40 |
root /usr/share/nginx/html/solr-cloud;
|
41 |
index index.html index.htm;
|
43 |
include /home/hadoop/servers/nginx/conf/proxy.conf;
|
一共配置了3台Solr服务器,因为SolrCloud集群中每一个节点都可以接收搜索请求,然后由整个集群去并行搜索。最后,我们要通过Dubbo服务框架来基于已有的系统来开发搜索服务,并通过Dubbo的注册中心来发布服务。
首先需要实现服务接口,实现代码如下所示:
01 |
package org.shirdrn.platform.dubbo.service.rpc.server;
|
03 |
import java.io.IOException;
|
04 |
import java.util.HashMap;
|
07 |
import org.apache.commons.logging.Log;
|
08 |
import org.apache.commons.logging.LogFactory;
|
09 |
import org.shirdrn.platform.dubbo.service.rpc.api.SolrSearchService;
|
10 |
import org.shirdrn.platform.dubbo.service.rpc.utils.QueryPostClient;
|
11 |
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
13 |
public class SolrSearchServer implements SolrSearchService {
|
15 |
private static final Log LOG = LogFactory.getLog(SolrSearchServer. class );
|
16 |
private String baseUrl;
|
17 |
private final QueryPostClient postClient;
|
18 |
private static final Map<ResponseType, FormatHandler> handlers = new HashMap<ResponseType, FormatHandler>( 0 );
|
20 |
handlers.put(ResponseType.XML, new FormatHandler() {
|
21 |
public String format() {
|
25 |
handlers.put(ResponseType.JSON, new FormatHandler() {
|
26 |
public String format() {
|
32 |
public SolrSearchServer() {
|
34 |
postClient = QueryPostClient.newIndexingClient( null );
|
37 |
public void setBaseUrl(String baseUrl) {
|
38 |
this .baseUrl = baseUrl;
|
41 |
public String search(String collection, String q, ResponseType type,
|
42 |
int start, int rows) {
|
43 |
StringBuffer url = new StringBuffer();
|
44 |
url.append(baseUrl).append(collection).append( "/select?" ).append(q);
|
45 |
url.append( "&start=" ).append(start).append( "&rows=" ).append(rows);
|
46 |
url.append(handlers.get(type).format());
|
47 |
LOG.info( "[REQ] " + url.toString());
|
48 |
return postClient.request(url.toString());
|
51 |
interface FormatHandler {
|
55 |
public static void main(String[] args) throws IOException {
|
56 |
String config = SolrSearchServer. class .getPackage().getName().replace( '.' , '/' ) + "/search-provider.xml" ;
|
57 |
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(config);
|
对应的Dubbo配置文件为search-provider.xml,内容如下所示:
01 |
<? xml version = "1.0" encoding = "UTF-8" ?>
|
08 |
< dubbo:application name = "search-provider" />
|
10 |
< dubbo:protocol name = "dubbo" port = "20880" />
|
11 |
< bean id = "searchService" class = "org.shirdrn.platform.dubbo.service.rpc.server.SolrSearchServer" >
|
14 |
< dubbo:service interface = "org.shirdrn.platform.dubbo.service.rpc.api.SolrSearchService" ref = "searchService" />
|
上面,Dubbo服务注册中心指定ZooKeeper的地址:zookeeper://slave1:2188?backup=slave3:2188,slave4:2188,使用Dubbo协议。配置服务接口的时候,可以按照Spring的Bean的配置方式来配置,注入需要的内容,我们这里指定了搜索集群的Nginx反向代理地址http://nginx-lbserver/solr-cloud/。
这个就比较简单了,拷贝服务接口,同时要配置一下Dubbo的配置文件,写个简单的客户端调用就可以实现。客户端实现的Java代码如下所示:
01 |
package org.shirdrn.platform.dubbo.service.rpc.client;
|
03 |
import java.util.concurrent.Callable;
|
04 |
import java.util.concurrent.Future;
|
06 |
import org.shirdrn.platform.dubbo.service.rpc.api.SolrSearchService;
|
07 |
import org.shirdrn.platform.dubbo.service.rpc.api.SolrSearchService.ResponseType;
|
08 |
import org.springframework.beans.BeansException;
|
09 |
import org.springframework.context.support.AbstractXmlApplicationContext;
|
10 |
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
12 |
import com.alibaba.dubbo.rpc.RpcContext;
|
14 |
public class SearchConsumer {
|
16 |
private final String collection;
|
17 |
private AbstractXmlApplicationContext context;
|
18 |
private SolrSearchService searchService;
|
20 |
public SearchConsumer(String collection, Callable<AbstractXmlApplicationContext> call) {
|
22 |
this .collection = collection;
|
24 |
context = call.call();
|
26 |
searchService = (SolrSearchService) context.getBean( "searchService" );
|
27 |
} catch (BeansException e) {
|
29 |
} catch (Exception e) {
|
34 |
public Future<String> asyncCall( final String q, final ResponseType type, final int start, final int rows) {
|
35 |
Future<String> future = RpcContext.getContext().asyncCall( new Callable<String>() {
|
36 |
public String call() throws Exception {
|
37 |
return search(q, type, start, rows);
|
43 |
public String syncCall( final String q, final ResponseType type, final int start, final int rows) {
|
44 |
return search(q, type, start, rows);
|
47 |
private String search( final String q, final ResponseType type, final int start, final int rows) {
|
48 |
return searchService.search(collection, q, type, start, rows);
|
51 |
public static void main(String[] args) throws Exception {
|
52 |
final String collection = "tinycollection" ;
|
53 |
final String beanXML = "search-consumer.xml" ;
|
54 |
final String config = SearchConsumer. class .getPackage().getName().replace( '.' , '/' ) + "/" + beanXML;
|
55 |
SearchConsumer consumer = new SearchConsumer(collection, new Callable<AbstractXmlApplicationContext>() {
|
56 |
public AbstractXmlApplicationContext call() throws Exception {
|
57 |
final AbstractXmlApplicationContext context = new ClassPathXmlApplicationContext(config);
|
62 |
String q = "q=上海&fl=*&fq=building_type:1" ;
|
65 |
ResponseType type = ResponseType.XML;
|
66 |
for ( int k = 0 ; k < 10 ; k++) {
|
67 |
for ( int i = 0 ; i < 10 ; i++) {
|
70 |
type = ResponseType.XML;
|
72 |
type = ResponseType.JSON;
|
76 |
Future<String> future = consumer.asyncCall(q, type, start, rows);
|
查询的时候,需要提供查询字符串,符合Solr语法,例如“q=上海&fl=*&fq=building_type:1”。配置文件,我们使用search-consumer.xml,内容如下所示:
01 |
<? xml version = "1.0" encoding = "UTF-8" ?>
|
08 |
< dubbo:application name = "search-consumer" />
|
10 |
< dubbo:reference id = "searchService" interface = "org.shirdrn.platform.dubbo.service.rpc.api.SolrSearchService" />
|
运行说明
首先保证服务注册中心的ZooKeeper集群正常运行,然后启动SolrSearchServer,启动的时候直接将服务注册到ZooKeeper集群存储中,可以通过ZooKeeper的客户端脚本来查看注册的服务数据。一切正常以后,可以启动运行客户端SearchConsumer,调用SolrSearchServer所实现的远程搜索服务。
参考链接
分享到:
相关推荐
有关Dubbo服务框架的简单使用,可以参考我的其他两篇文章(《基于Dubbo的Hessian协议实现远程调用》,《Dubbo实现RPC调用使用入门》,后面参考链接中已给出链接),这里主要围绕Dubbo分布式服务相关配置的使用来说明...
Dubbo分布式服务框架入门2
Dubbo是一款高性能、轻量级的开源Java RPC框架,提供面向接口代理的高性能RPC调用、智能负载均衡、服务自动注册和发现、运行期流量调度、可视化服务治理和运维等功能。 本套课程中,第一阶段深入Zookeeper原理和源码...
Dubbo是 [1] 阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 [2] Spring框架无缝集成。 Dubbo是一款高性能、轻量级的开源Java RPC框架,它提供了三大...
课程目标:了解远程调用PRC的概念,分布式应用为什么使用RPC, 基于PRC协议的Dubbo的使用。Dubbo框架的特点,框架的组件;基于Dubbo服务提供者,消费者,注册中心Zookeeper的分布式应用的开发部署, Dubbo的负载均衡...
Dubbo ['dʌbəu] 是一个分布式服务治理框架,提供高性能的RPC远程服务调用及服务治理。 Dubbo是阿里巴巴开源的产品(2012),2018年捐献给了apache,现在是apache下的一个顶级开源项目,国内大量企业都在使用Dubbo...
demo使用java进行分模块方式,来展现dubbo的调用。 Dubbo是阿里巴巴开源的基于 Java 的高性能 RPC(一种远程调用) 分布式服务框架(SOA),致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。
###Dubbo背景和简介 Dubbo开始于电商系统,因此在这里先从电商系统的演变讲起。 单一应用框架(ORM) ...随着服务化的进一步发展,服务越来越多,服务之间的调用和依赖关系也越来越复杂,诞生了面向服务的架构体系
学习大纲1了解什么是dubbo?2我们使用dubbo能做什么?3Dubbo入门4Dubbo管理什么是dubbo?简介DUBBO是一个分布式服务框架致力于提供高性能和透明化的RPC远程服务调用方案是阿里
maven+spring+dubbo直连式。用于学习与理解dubbo RPC框架的朋友们,快速学习与理解消费者与提供者组件。以及dubbo调用方式。
简介DUBBO是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,是阿里巴巴SOA服务化治理方案的核心框架,每天为2,000+个服务提供3,
Dubbo是一个分布式的高性能RPC框架,可为应用程序提供服务导入/导出功能。 它包含三个关键部分,其中包括: 远程处理:提供异步同步和请求响应消息传递的网络通信框架。 群集:具有负载平衡/故障转移/群集功能的...
RPC等)支持跟踪(运行时信息,调用堆栈) 多个注册中心(Zookeeper,Nacos,Redis)支持或直接连接到服务可扩展性,灵感来自Koa中间件内置重新连接策略打字稿类型定义自动将Java接口转换为Typescript类型定义的工具...
同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...
同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...
同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...
同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...
同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...