Dubbo实现RPC调用使用入门

来源:互联网 发布:假丝绸出口数据 编辑:程序博客网 时间:2024/06/07 05:03

使用Dubbo进行远程调用实现服务交互,它支持多种协议,如Hessian、HTTP、RMI、Memcached、Redis、Thrift等等。由于Dubbo将这些协议的实现进行了封装了,无论是服务端(开发服务)还是客户端(调用服务),都不需要关心协议的细节,只需要在配置中指定使用的协议即可,从而保证了服务提供方与服务消费方之间的透明。
另外,如果我们使用Dubbo的服务注册中心组件,这样服务提供方将服务发布到注册的中心,只是将服务的名称暴露给外部,而服务消费方只需要知道注册中心和服务提供方提供的服务名称,就能够透明地调用服务,后面我们会看到具体提供服务和消费服务的配置内容,使得双方之间交互的透明化。

示例场景

我们给出一个示例的应用场景:
服务方提供一个搜索服务,对服务方来说,它基于SolrCloud构建了搜索服务,包含两个集群,ZooKeeper集群和Solr集群,然后在前端通过Nginx来进行反向代理,达到负载均衡的目的。
服务消费方就是调用服务进行查询,给出查询条件(满足Solr的REST-like接口)。

应用设计

基于上面的示例场景,我们打算使用ZooKeeper集群作为服务注册中心。注册中心会暴露给服务提供方和服务消费方,所以注册服务的时候,服务先提供方只需要提供Nginx的地址给注册中心,但是注册中心并不会把这个地址暴露给服务消费方,如图所示:
provider-registry-consumer
我们先定义一下,通信双方需要使用的接口,如下所示:

01package org.shirdrn.platform.dubbo.service.rpc.api;
02 
03public interface SolrSearchService {
04 
05    String search(String collection, String q, ResponseType type, int start, introws);
06     
07    public enum ResponseType {
08        JSON,
09        XML
10    }  
11}

基于上图中的设计,下面我们分别详细说明Provider和Consumer的设计及实现。

  • Provider服务设计

Provider所发布的服务组件,包含了一个SolrCloud集群,在SolrCloud集群前端又加了一个反向代理层,使用Nginx来均衡负载。Provider的搜索服务系统,设计如下图所示:
solrcloud-cluster
上图中,实际Nginx中将请求直接转发内部的Web Servers上,在这个过程中,使用ZooKeeper来进行协调:从多个分片(Shard)服务器上并行搜索,最后合并结果。我们看一下Nginx配置的内容片段:

01user  nginx;
02worker_processes  4;
03 
04error_log  /var/log/nginx/error.log warn;
05pid        /var/run/nginx.pid;
06 
07 
08events {
09    worker_connections  1024;
10}
11 
12 
13http {
14    include       /etc/nginx/mime.types;
15    default_type  application/octet-stream;
16 
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"';
20 
21    access_log  /var/log/nginx/access.log  main;
22 
23    sendfile        on;
24    #tcp_nopush     on;
25 
26    keepalive_timeout  65;
27 
28    #gzip  on;
29 
30    upstream master {
31        server slave1:8888 weight=1;
32        server slave4:8888 weight=1;
33        server slave6:8888 weight=1;
34    }
35 
36    server {
37        listen 80;
38        server_name master;
39        location / {
40            root /usr/share/nginx/html/solr-cloud;
41            index  index.html index.htm;
42            proxy_pass   http://master;
43            include /home/hadoop/servers/nginx/conf/proxy.conf;
44        }
45    }
46}

一共配置了3台Solr服务器,因为SolrCloud集群中每一个节点都可以接收搜索请求,然后由整个集群去并行搜索。最后,我们要通过Dubbo服务框架来基于已有的系统来开发搜索服务,并通过Dubbo的注册中心来发布服务。
首先需要实现服务接口,实现代码如下所示:

01package org.shirdrn.platform.dubbo.service.rpc.server;
02 
03import java.io.IOException;
04import java.util.HashMap;
05import java.util.Map;
06 
07import org.apache.commons.logging.Log;
08import org.apache.commons.logging.LogFactory;
09import org.shirdrn.platform.dubbo.service.rpc.api.SolrSearchService;
10import org.shirdrn.platform.dubbo.service.rpc.utils.QueryPostClient;
11import org.springframework.context.support.ClassPathXmlApplicationContext;
12 
13public class SolrSearchServer implements SolrSearchService {
14 
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 = newHashMap<ResponseType, FormatHandler>(0);
19    static {
20        handlers.put(ResponseType.XML, new FormatHandler() {
21            public String format() {
22                return "&wt=xml";
23            }
24        });
25        handlers.put(ResponseType.JSON, new FormatHandler() {
26            public String format() {
27                return "&wt=json";
28            }
29        });
30    }
31     
32    public SolrSearchServer() {
33        super();
34        postClient = QueryPostClient.newIndexingClient(null);
35    }
36     
37    public void setBaseUrl(String baseUrl) {
38        this.baseUrl = baseUrl;
39    }
40 
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());
49    }
50     
51    interface FormatHandler {
52        String format();
53    }
54     
55    public static void main(String[] args) throws IOException {
56        String config = SolrSearchServer.class.getPackage().getName().replace('.''/') + "/search-provider.xml";
57        ClassPathXmlApplicationContext context = newClassPathXmlApplicationContext(config);
58        context.start();
59        System.in.read();
60    }
61 
62}

对应的Dubbo配置文件为search-provider.xml,内容如下所示:

01<?xml version="1.0" encoding="UTF-8"?>
02 
03<beans xmlns="http://www.springframework.org/schema/beans"
04    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
05    xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd
06    http://code.alibabatech.com/schema/dubbohttp://code.alibabatech.com/schema/dubbo/dubbo.xsd">
07 
08    <dubbo:application name="search-provider" />
09    <dubbo:registry address="zookeeper://slave1:2188?backup=slave3:2188,slave4:2188" />
10    <dubbo:protocol name="dubbo" port="20880" />
11    <bean id="searchService"class="org.shirdrn.platform.dubbo.service.rpc.server.SolrSearchServer">
12        <property name="baseUrl" value="http://nginx-lbserver/solr-cloud/" />
13    </bean>
14    <dubbo:serviceinterface="org.shirdrn.platform.dubbo.service.rpc.api.SolrSearchService"ref="searchService" />
15 
16</beans>

上面,Dubbo服务注册中心指定ZooKeeper的地址:zookeeper://slave1:2188?backup=slave3:2188,slave4:2188,使用Dubbo协议。配置服务接口的时候,可以按照Spring的Bean的配置方式来配置,注入需要的内容,我们这里指定了搜索集群的Nginx反向代理地址http://nginx-lbserver/solr-cloud/。

  • Consumer调用服务设计

这个就比较简单了,拷贝服务接口,同时要配置一下Dubbo的配置文件,写个简单的客户端调用就可以实现。客户端实现的Java代码如下所示:

01package org.shirdrn.platform.dubbo.service.rpc.client;
02 
03import java.util.concurrent.Callable;
04import java.util.concurrent.Future;
05 
06import org.shirdrn.platform.dubbo.service.rpc.api.SolrSearchService;
07import org.shirdrn.platform.dubbo.service.rpc.api.SolrSearchService.ResponseType;
08import org.springframework.beans.BeansException;
09import org.springframework.context.support.AbstractXmlApplicationContext;
10import org.springframework.context.support.ClassPathXmlApplicationContext;
11 
12import com.alibaba.dubbo.rpc.RpcContext;
13 
14public class SearchConsumer {
15     
16    private final String collection;
17    private AbstractXmlApplicationContext context;
18    private SolrSearchService searchService;
19     
20    public SearchConsumer(String collection, Callable<AbstractXmlApplicationContext> call) {
21        super();
22        this.collection = collection;
23        try {
24            context = call.call();
25            context.start();
26            searchService = (SolrSearchService) context.getBean("searchService");
27        catch (BeansException e) {
28            e.printStackTrace();
29        catch (Exception e) {
30            e.printStackTrace();
31        }
32    }
33     
34    public Future<String> asyncCall(final String q, final ResponseType type, finalint start, final int rows) {
35        Future<String> future = RpcContext.getContext().asyncCall(newCallable<String>() {
36            public String call() throws Exception {
37                return search(q, type, start, rows);
38            }
39        });
40        return future;
41    }
42     
43    public String syncCall(final String q, final ResponseType type, final intstart, final int rows) {
44        return search(q, type, start, rows);
45    }
46 
47    private String search(final String q, final ResponseType type, final intstart, final int rows) {
48        return searchService.search(collection, q, type, start, rows);
49    }
50     
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, newCallable<AbstractXmlApplicationContext>() {
56            public AbstractXmlApplicationContext call() throws Exception {
57                final AbstractXmlApplicationContext context = newClassPathXmlApplicationContext(config);
58                return context;
59            }
60        });
61         
62        String q = "q=上海&fl=*&fq=building_type:1";
63        int start = 0;
64        int rows = 10;
65        ResponseType type  = ResponseType.XML;
66        for (int k = 0; k < 10; k++) {
67            for (int i = 0; i < 10; i++) {
68                start = 1 10 * i;
69                if(i % 2 == 0) {
70                    type = ResponseType.XML;
71                else {
72                    type = ResponseType.JSON;
73                }
74//              String result = consumer.syncCall(q, type, start, rows);
75//              System.out.println(result);
76                Future<String> future = consumer.asyncCall(q, type, start, rows);
77//              System.out.println(future.get());
78            }
79        }
80    }
81}

查询的时候,需要提供查询字符串,符合Solr语法,例如“q=上海&fl=*&fq=building_type:1”。配置文件,我们使用search-consumer.xml,内容如下所示:

01<?xml version="1.0" encoding="UTF-8"?>
02 
03<beans xmlns="http://www.springframework.org/schema/beans"
04    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
05    xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd
06    http://code.alibabatech.com/schema/dubbohttp://code.alibabatech.com/schema/dubbo/dubbo.xsd">
07 
08    <dubbo:application name="search-consumer" />
09    <dubbo:registry address="zookeeper://slave1:2188?backup=slave3:2188,slave4:2188" />
10    <dubbo:reference id="searchService"interface="org.shirdrn.platform.dubbo.service.rpc.api.SolrSearchService" />
11 
12</beans>

运行说明

首先保证服务注册中心的ZooKeeper集群正常运行,然后启动SolrSearchServer,启动的时候直接将服务注册到ZooKeeper集群存储中,可以通过ZooKeeper的客户端脚本来查看注册的服务数据。一切正常以后,可以启动运行客户端SearchConsumer,调用SolrSearchServer所实现的远程搜索服务。

参考链接

  • https://github.com/alibaba/dubbo
  • http://alibaba.github.io/dubbo-doc-static/Home-zh.htm
  • http://alibaba.github.io/dubbo-doc-static/User+Guide-zh.htm
  • http://alibaba.github.io/dubbo-doc-static/Developer+Guide-zh.htm
  • http://alibaba.github.io/dubbo-doc-static/Administrator+Guide-zh.htm
  • http://alibaba.github.io/dubbo-doc-static/FAQ-zh.htm
0 0
原创粉丝点击