我开始抄代码来学编程

之前研究 Hadoop 源码,把 hadoop-common 模块下的 RPC 模块源码通读一遍,又花了 3 个月抄了一遍 Hadoop RPC 代码,学到很多东西。我觉得学习编程最有效的方式就是抄代码,我觉得这个过程对正在学编程的朋友很有帮助,所以想做成教程,以下是周末写的一个开头,后续教程的形式以及进展会发布在公众号,有兴趣的朋友欢迎文末关注

1. 起源

故事得从19年上半年说起,那时候我正打算研究一下Hadoop源码。 现在大家都听说过Hadoop,它是一个分布式存储和计算的框架。作为分布式系统,节点之间的通信、交互式必不可少的。Hadoop自己实现了RPC(Remote Procedure Call,远程过程调用)模块来满足这样的需求。带着好奇,我便阅读了整个Hadoop RPC模块的源代码,读完后发现这个模块设计的非常好,与其他模块无耦合,完全可以独立出来当成一个独立的框架。为了能够学习相关的编程知识,同时还可以看到Apache 顶级开源项目的代码如何编写的,因此我便把Hadoop RPC模块做成教程。

虽然这个项目是实现RPC功能,但我觉得我们重点不应该过多关注RPC本身,而应该重点学习RPC所涉及的客户端开发、服务端开发、网络编程、多线程、并发编程、设计模式等核心知识,尤其是对于刚学习Java没有接触线上实战项目的朋友,掌握好了这些知识,写其他项目也会更有思路。

2. 起名

为了能让不熟悉Hadoop的朋友也能学习本教程,因此我们将Hadoop RPC赋予了新的业务含义。

假设我们有这样一个场景,公司开发一个新的数据库,这个数据库的底层可能是Mysql,也可能是MongoDB,甚至可能是公司自研的数据库技术,无论是什么,数据库都可以作为服务端。作为用户来说,数据库底层用了什么技术并不关系,而是关心怎么使用。数据库需要提供了API方便用户调用,因此就需要有客户端。

实现连接客户端请求和服务端响应的技术就是RPC。我给这个项目起了一个名字叫Manis,那么,数据库的名字便是ManisDb。工作中我们也比较鼓励大家给自己的项目起个名字,有了名字,它就像自己的孩子一样,我们会更有责任心把它做好。

3. 优势

优势都是相对的。Hadoop RPC 相比于一般的实战项目来说,它是经过线上检验的,Hadoop集群规模最大达到上万台,单一个RPC模块完全可以独立出来用于实战。同时,我们还可以积累顶级开源项目的开发经验,大到架构设计,小到设计模式,代码规范。RPC在客户端开发、服务端开发、网络编程三方面都有涉及,且都是重点内容。

Hadoop RPC相比于源码分析类的教程来说,优势在于实战意义比较强。我们会按照Hadoop RPC源码把我们的野生项目Manis从0到1完整的敲一遍,还原度为95%。解释下为什么不是100%,一方面为了突出重点,我会把不太重要、不是很核心的技术舍弃掉。另一方面为了符合新的业务定义,我会做一些改进,而不是照搬Hadoop RPC。比如:Hadoop RPC到了2.6版本只支持Protobuf序列化协议,但为了体现高扩展以及模块间的低耦合,Manis支持了多种序列化协议。

在写教程之前,我花了大概3个月时间先对照Hadoop RPC源码把Manis敲出来了。学会了Manis后,你完全有能力阅读Hadoop RPC的源码,这也算是面试的加分项吧。可能有些读者觉得这种方式比较LOW,但我还是相信马化腾说的“抄代码培养感觉”,写代码好比学字画,不临摹好的作品怎么学习别人的优点。真正要把看到的东西变成自己的,最终扎实的方式就是自己走一遍。至于Manis中被舍弃的部分我会在教程中说明,必要的时候会截取Hadoop源码一起分析。

4. Manis架构图

图1-1是Manis的架构图,基本上是一般的RPC架构图。

图1-1 Manis架构图

5. Manis核心组件时序图

 

图1-2 Manis 核心组件时序图

6. Manis核心组件概念

结合图1-2对Manis中涉及的核心的组件概念进行说明。

ManisDb:图中没有表示,它代表数据库,负责启动服务端(即ipc.Server类),这里需要说明一下我们的重点在于RPC开发,这里的数据库只是举一个例子,不会涉及真正的数据库开发。

ManisClient:提供给普通用户的客户端类,用于对ManisDb进行增删改查,它使用Protobuf协议与ManisDb进行通信。

Manager:提供给管理员的客户端类,用于对ManisDb进行管理,它使用Serializable协议(Java原生的序列化方式)与ManisDb进行通信

ProtoBufRpcEngine:支持Protobuf协议的RPC引擎,它定义了两个内部类——Invoker类和ProtoBufRpcInvoker类。Invoker类用于封装客户端的调用请求,并使用Protobuf协议序列化。ProtoBufRpcInvoker类用于完成客户端请求的方法调用(服务端调)。

SerializableRpcEngine:支持Serializable协议的RPC引擎,它定义两个内部类——Invoker类和SerializableRpcInvoker类。Invoker类用于封装客户端的调用请求,并使用Serializable协议序列化。SerializableRpcInvoker类用于完成客户端请求的方法调用(服务端调)。

Client:建立与服务端的socket连接,接收客户端调用,并发送调用请求给服务端,等待服务端返回并将结果返回。

ipc.Server:该类定义在ipc包下面,通过Reactor模式接收并处理客户端请求,最终调用ProtoBufRpcInvoker或SerializableRpcInvoker的方法获得结果,并返回给客户端。

 

公众号「渡码」,分享更多高质量内容

posted @ 2019-10-21 13:11 渡码 阅读(...) 评论(...) 编辑 收藏