Hadoop2源码分析-RPC机制初识

1.概述   上一篇博客,讲述Hadoop V2的序列化机制,这为我们学习Hadoop V2的RPC机制奠定了基础。RPC的内容涵盖的信息有点多,包含Hadoop的序列化机制,RPC,代理,NIO等。若对Hadoop序列化不了解的同学,可以参考《 Hadoop2源码分析-序列化篇 》。今天这篇博客为大家介绍的内容目录如下:
  • RPC概述
  • 第三方RPC
  • Hadoop V2的RPC简述
  那么,下面开始今天的学习之路。
2.RPC概述   首先,我们要弄明白,什么是RPC?RPC能用来做什么?
2.1什么是RPC   RPC的全程是Remote Procedure Call,中文释为远程过程调用。也就是说,调用的过程代码(业务服务代码)并不在调用者本地运行,而是要实现调用着和被调用着之间的连接通信,有同学可能已经发现,这个和C/S模式很像。没错,RPC的基础通信模式是基于C/S进程间相互通信的模式来实现的,它对Client端提供远程接口服务,其RPC原理图如下所示:
 
2.2RPC的功能   我们都知道,在过去的编程概念中,过程是由开发人员在本地编译完成的,并且只能局限在本地运行的某一段代码,即主程序和过程程序是一种本地调用关系。因此,这种结构在如今网络飞速发展的情况下已无法适应实际的业务需求。而且,传统过程调用模式无法充分利用网络上其他主机的资源,如CPU,内存等,也无法提高代码在Bean之间的共享,使得资源浪费较大。
  而RPC的出现,正好有效的解决了传统过程中存在的这些不足。通过RPC,我们可以充分利用非共享内存的机器,可以简便的将应用分布在多台机器上,类似集群分布。这样方便的实现过程代码共享,提高系统资源的利用率。较少单个集群的压力,实现负载均衡。
3.第三方RPC   在学习Hadoop V2的RPC机制之前,我们先来熟悉第三方的RPC机制是如何工作的,下面我以Thrift框架为例子。
  Thrift是一个软件框架,用来进行可扩展且跨语言的服务开发协议。它拥有强大的代码生成引擎,支持C++,Java,Python,PHP,Ruby等编程语言。Thrift允许定义一个简单的定义文件(以.thirft结尾),文件中包含数据类型和服务接口。用以作为输入文件,编译器生成代码用来方便的生成RPC客户端和服务端通信的编程语言。具体Thrift安装过程请参考《 Mac OS X 下搭建thrift环境 》。
3.1Thrift原理图   下面给出Thrift的原理图,如下所示:
 
  下面为大家解释一下上面的原理图,首先,我们编译完thrift定义文件后(这里我使用的是Java语言),会生成对应的Java类文件,该类的Iface接口定义了我们所规范的接口函数。在服务端,实现Iface接口,编写对应函数下的业务逻辑,启动服务。客户端同样需要生成的Java类文件,以供Client端调用相应的接口函数,监听服务端的IP和PORT来获取连接对象。
3.2代码示例
  • Server端代码:

  1. package cn.rpc.main;

  2. import org.apache.thrift.TProcessorFactory;
  3. import org.apache.thrift.protocol.TCompactProtocol;
  4. import org.apache.thrift.server.THsHaServer;
  5. import org.apache.thrift.server.TServer;
  6. import org.apache.thrift.transport.TFramedTransport;
  7. import org.apache.thrift.transport.TNonblockingServerSocket;
  8. import org.slf4j.Logger;
  9. import org.slf4j.LoggerFactory;

  10. import cn.rpc.service.StatQueryService;
  11. import cn.rpc.service.impl.StatQueryServiceImpl;

  12. /**
  13. * @Date Mar 23, 2015
  14. *
  15. * @Author dengjie
  16. */
  17. public class StatsServer {

  18.     private static Logger logger = LoggerFactory.getLogger(StatsServer.class);

  19.     private final int PORT = 9090;

  20.     @SuppressWarnings({ "rawtypes", "unchecked" })
  21.     private void start() {
  22.         try {
  23.             TNonblockingServerSocket socket = new TNonblockingServerSocket(PORT);
  24.             final StatQueryService.Processor processor = new StatQueryService.Processor(new StatQueryServiceImpl());
  25.             THsHaServer.Args arg = new THsHaServer.Args(socket);
  26.             /*
  27.              * Binary coded format efficient, intensive data transmission, The
  28.              * use of non blocking mode of transmission, according to the size
  29.              * of the block, similar to the Java of NIO
  30.              */
  31.             arg.protocolFactory(new TCompactProtocol.Factory());
  32.             arg.transportFactory(new TFramedTransport.Factory());
  33.             arg.processorFactory(new TProcessorFactory(processor));
  34.             TServer server = new THsHaServer(arg);
  35.             server.serve();
  36.         } catch (Exception ex) {
  37.             ex.printStackTrace();
  38.         }
  39.     }

  40.     public static void main(String[] args) {
  41.         try {
  42.             logger.info("start thrift server...");
  43.             StatsServer stats = new StatsServer();
  44.             stats.start();
  45.         } catch (Exception ex) {
  46.             ex.printStackTrace();
  47.             logger.error(String.format("run thrift server has error,msg is %s", ex.getMessage()));
  48.         }
  49.     }

  50. }
复制代码

  • Client端代码:

  1. package cn.rpc.test;

  2. import java.util.Map;

  3. import org.apache.thrift.protocol.TCompactProtocol;
  4. import org.apache.thrift.protocol.TProtocol;
  5. import org.apache.thrift.transport.TFramedTransport;
  6. import org.apache.thrift.transport.TSocket;
  7. import org.apache.thrift.transport.TTransport;

  8. import cn.rpc.service.StatQueryService;

  9. /**
  10. * @Date Mar 23, 2015
  11. *
  12. * @Author dengjie

  13. * @Note Test thrift client
  14. */
  15. public class StatsClient {

  16.     public static final String ADDRESS = "127.0.0.1";
  17.     public static final int PORT = 9090;
  18.     public static final int TIMEOUT = 30000;

  19.     public static void main(String[] args) {
  20.         if (args.length < 4) {
  21.             System.out.println("args length must >= 4,current length is " + args.length);
  22.             System.out.println("<info>****************</info>");
  23.             System.out.println("ADDRESS,beginDate,endDate,kpiCode,...");
  24.             System.out.println("<info>****************</info>");
  25.             return;
  26.         }
  27.         TTransport transport = new TFramedTransport(new TSocket(args[0], PORT, TIMEOUT));
  28.         TProtocol protocol = new TCompactProtocol(transport);
  29.         StatQueryService.Client client = new StatQueryService.Client(protocol);
  30.         String beginDate = args[1]; // "20150308"
  31.         String endDate = args[2]; // "20150312"
  32.         String kpiCode = args[3]; // "login_times"
  33.         String userName = "";
  34.         int areaId = 0;
  35.         String type = "";
  36.         String fashion = "";

  37.         try {
  38.             transport.open();
  39.             Map<String, String> map = client.queryConditionDayKPI(beginDate, endDate, kpiCode, userName, areaId, type,
  40.                     fashion);
  41.             System.out.println(map.toString());
  42.         } catch (Exception e) {
  43.             e.printStackTrace();
  44.         } finally {
  45.             transport.close();
  46.         }
  47.     }

  48. }
复制代码

  • StatQueryService类:
  这个类的代码量太大,暂不贴出。需要的同学请到以下地址下载。
  下载地址: git@gitlab.com :dengjie/Resource.git
  • StatQueryServiceImpl类:
  下面实现其中一个函数的内容,代码如下所示:

  1. package cn.rpc.service.impl;

  2. import java.util.HashMap;
  3. import java.util.List;
  4. import java.util.Map;

  5. import org.apache.thrift.TException;

  6. import cn.rpc.conf.ConfigureAPI;
  7. import cn.rpc.dao.KpiDao;
  8. import cn.rpc.domain.ReportParam;
  9. import cn.rpc.domain.ReportResult;
  10. import cn.rpc.service.StatQueryService;
  11. import cn.rpc.util.MapperFactory;

  12. /**
  13. * @Date Mar 23, 2015
  14. *
  15. * @Author dengjie
  16. */
  17. public class StatQueryServiceImpl implements StatQueryService.Iface {

  18.     public Map<String, String> queryDayKPI(String beginDate, String endDate, String kpiCode) throws TException {
  19.         return null;
  20.     }

  21.     public Map<String, String> queryConditionDayKPI(String beginDate, String endDate, String kpiCode, String userName,
  22.             int areaId, String type, String fashion) throws TException {
  23.         Map<String, String> res = new HashMap<String, String>();
  24.         ReportParam param = new ReportParam();
  25.         param.setBeginDate(beginDate + "");
  26.         param.setEndDate(endDate + "");
  27.         param.setKpiCode(kpiCode);
  28.         param.setUserName(userName == "" ? null : userName);
  29.         param.setDistrictId(areaId < 0 ? 0 : areaId);
  30.         param.setProductStyle(fashion == "" ? null : fashion);
  31.         param.setCustomerProperty(type == "" ? null : type);
  32.         List<ReportResult> chart = ((KpiDao) MapperFactory.createMapper(KpiDao.class)).getChartAmount(param);
  33.         Map<String, Integer> title = ((KpiDao) MapperFactory.createMapper(KpiDao.class)).getTitleAmount(param);
  34.         List<Map<String, Integer>> tableAmount = ((KpiDao) MapperFactory.createMapper(KpiDao.class))
  35.                 .getTableAmount(param);
  36.         String avgTime = kpiCode.split("_")[0];
  37.         param.setKpiCode(avgTime + "_avg_time");
  38.         List<Map<String, Integer>> tableAvgTime = ((KpiDao) MapperFactory.createMapper(KpiDao.class))
  39.                 .getTableAmount(param);
  40.         res.put(ConfigureAPI.RESMAPKEY.CHART, chart.toString());
  41.         res.put(ConfigureAPI.RESMAPKEY.TITLE, title.toString());
  42.         res.put(ConfigureAPI.RESMAPKEY.TABLEAMOUNT, tableAmount.toString());
  43.         res.put(ConfigureAPI.RESMAPKEY.TABLEAVG, tableAvgTime.toString());
  44.         return res;
  45.     }

  46.     public Map<String, String> queryDetail(String beginDate, String endDate, String userName) throws TException {
  47.         // TODO Auto-generated method stub
  48.         return null;
  49.     }

  50. }
复制代码


4.Hadoop V2的RPC简述   Hadoop V2中的RPC采用的是自己独立开发的协议,其核心内容包含服务端,客户端,交互协议。源码内容都在hadoop-common-project项目的org.apache.hadoop.ipc包下面。
  • VersionedProtocol类:
  
  1. package org.apache.hadoop.ipc;

  2. import java.io.IOException;

  3. /**
  4. * Superclass of all protocols that use Hadoop RPC.
  5. * Subclasses of this interface are also supposed to have
  6. * a static final long versionID field.
  7. */
  8. public interface VersionedProtocol {
  9.   
  10.   /**
  11.    * Return protocol version corresponding to protocol interface.
  12.    * @param protocol The classname of the protocol interface
  13.    * @param clientVersion The version of the protocol that the client speaks
  14.    * @return the version that the server will speak
  15.    * @throws IOException if any IO error occurs
  16.    */
  17.   public long getProtocolVersion(String protocol,
  18.                                  long clientVersion) throws IOException;

  19.   /**
  20.    * Return protocol version corresponding to protocol interface.
  21.    * @param protocol The classname of the protocol interface
  22.    * @param clientVersion The version of the protocol that the client speaks
  23.    * @param clientMethodsHash the hashcode of client protocol methods
  24.    * @return the server protocol signature containing its version and
  25.    *         a list of its supported methods
  26.    * @see ProtocolSignature#getProtocolSignature(VersionedProtocol, String, 
  27.    *                long, int) for a default implementation
  28.    */
  29.   public ProtocolSignature getProtocolSignature(String protocol, 
  30.                                  long clientVersion,
  31.                                  int clientMethodsHash) throws IOException;
  32. }

复制代码

  该类中的两个方法一个是作为版本,另一个作为签名用。
  • RPC下的Server类:

  1. /** An RPC Server. */
  2.   public abstract static class Server extends org.apache.hadoop.ipc.Server {
  3.    boolean verbose;
  4.    static String classNameBase(String className) {
  5.       String[] names = className.split("\\.", -1);
  6.       if (names == null || names.length == 0) {
  7.         return className;
  8.       }
  9.       return names[names.length-1];
  10.     }
复制代码

  对外提供服务,处理Client端的请求,并返回处理结果。
  至于Client端,监听Server端的IP和PORT,封装请求数据,并接受Response。

5.总结  这篇博客赘述了RPC的相关内容,让大家先熟悉一下RPC的相关机制和流程,并简述了Hadoop V2的RPC机制,关于Hadoop V2的RPC详细内容会在下一篇博客中给大家分享。这里只是让大家先对Hadoop V2的RPC机制有个初步的认识。

转自:董的博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值