dubbo源码分析一

    对于开发者而言,可选择的开源分布式服务框架挺多的,按照我目前所了解到的有阿里的dubbo、facebook开源的thrift、zeroc的ice、google的grpc等等,包括springcloud也有基于rest的分布式服务方案,以及早前流行基于soap协议的webservice。腾讯也有开源一款叫做毫秒级服务引擎msec,但出来不是很久,所以名气还不是很大。

    为什么先选择dubbo这款框架来进行源码分析呢?第一个原因是我最擅长的语言是java,学习起这款纯java开发的框架可以忽略语言平台级别的问题,把更多的精力放在框架原理上。第二是因为dubbo这款框架在国内比较流行,官方的文档也比较齐全,意味着我可以用较低的学习成本快速解决学习中的疑问。在这之前,我仅有分布式框架的使用经验,但没有深入研究过其他框架,借dubbo这个框架我能够快速接触到分布式服务实现的核心原理,学习了dubbo之后还可以基于dubbo学习经验之上学习其他类似的框架。

    dubbo是阿里开源的一款纯java开发的分布式服务框架,它不仅仅解决了分布式服务通信问题,还提供了服务治理方案。但它仅仅适用于java服务之间的通信,如果要和其他语言、平台通信,可以结合其他手段例如rest、thrift等。实际上,在项目开发中,很难避免跨语言的调用,ice、grpc、thrift这些支持跨语言的框架可能更加适合在实际项目中使用,但跨语言意味着你需要一个中间语言来定义服务之间的通信接口,在ice和grpc中提供了slice、protobuf这种c++风格的语言来定义接口,通过特定编译器编译为不同语言的版本提供给开发者调用。在dubbo中,则是直接使用java语言来定义接口,定义过程和你开发本地java服务完全没有区别,当你定义了接口、参数、返回值、异常之后将其打包成一个jar,就可以提供给消费者服务开发者和生产服务开发者进行开发。并且dubbo能够和spring很好的结合,这让dubbo的入门门槛变得很低,更受Java开发者们的欢迎。

    dubbo有很长一段时间没有更新了,记得在github上看到最后一个发布版本是在2014年。后来当当网对dubbo进行功能扩展推出了dubbox。其实阿里并没有放弃dubbo,在阿里云官网的互联网中间件中有一项“企业级分布式应用服务 EDAS”,这是dubbo的商业化版本。在近期,dubbo官网也发出公告,阿里将继续维护dubbo这一款开源产品。

    讲真,dubbo的文档写的着实不错,这是吸引我学习它的一个最重要的理由。

    在dubbo官网,dubbo将文档分为了三类:使用者指南、开发者指南和管理员指南,分别面对了程序员、系统架构师以及运维人员三种角色。在项目中应用dubbo,你仅仅需要阅读使用者指南;如果dubbo不能够满足你的需求或者你发现dubbo有bug,你可以对dubbo进行修改,开发者指南能够对你起到指导性的作用;而管理员指南能够帮助你了解在日常工作中如何对dubbo进行维护。所以在此建议研究dubbo的同学先把官方文档多看几遍。

    我的开源框架学习方法是先收集到网上已有的框架资料,将这些资料先看懂,对框架使用熟练之后,明确框架解决了什么问题,如果之前研究过其他框架还可以将两者进行对比得出这款框架没解决什么问题,也就是总结优缺点。这个类型的框架所解决的问题,如果交由我来开发,我该如何对其进行架构?如何进行开发?

    对于分布式服务这个领域,我从一个互联网产品的业务发展来引入。在一个产品早期,通常用户量不大, 开发者开发了一个javaweb项目之后,可以发布到一个服务器上运行。随着业务发展,用户数在不断增多,功能需求也在不断扩充,开发人员此时将会面临两个大问题:1.单台服务器无法再支撑不断增多的用户访问;2.功能不断迭代,模块开发越来越复杂,每次发布都需要将所有服务模块重启。为了支撑更多的用户数,可能公司会决定增加服务器配置,加缓存,将程序部署到多台服务器进行负载均衡,但是这仍然无法解决开发复杂和重启所有服务模块的问题,并且,有些服务模块对于cpu要求比较高,有些服务模块对于存储读写要求比较高,如果仅仅是将程序简单的部署为多台,将会造成服务器资源的浪费。在一次bugfix中,你可能仅仅需要更新一个服务模块,却面临着需要重新打包整个项目以及重启所有服务时,这将影响团队的开发效率和带来许多风险。

    分布式服务便能够解决这个问题,将一个大系统拆分为多个服务,每个服务都可以进行集群部署,服务之间具有调用关系,理论上来说,分布式服务之间的调用带来的性能消耗绝对是比本地服务调用来的大的。但是在大量的请求之下,分布式服务消耗了一些性能却带来的更高的吞吐量。

    分布式服务,是在多台服务器之间进行服务调用。要在多台服务器之间进行服务调用,第一步要解决的是网络通信问题。在计算机领域,网络通信都是使用以TCP/IP协议栈,因此我们可选择的便是TCP和UDP协议来进行数据传输。在我所知道的分布式服务框架中,都是基于TCP进行通信的,用UDP传输需要自行实现TCP的许多机制,成本较高,实现出来了也不一定比TCP好。在Unix网络通信模型中,有同步的、异步的、阻塞的、非阻塞的。在java中对应了BIO、NIO、AIO。其中AIO性能最好,当然,我们要尽量的挑选性能最好的,成本最合理的方式来实现。在SpringCloud和WebService这种方案中,是使用http协议,虽然底层也是基于TCP,但Http是文本传输,加上一些Http的协议特性,在效率上是不会比dubbo、ice这类基于TCP自定义二进制协议来的高的。所以在分布式框架实现上,我一定会选择直接基于TCP来进行网络传输,可能直接操作TCP还是要面临许多问题,但是Java在网络通信方面,有Netty、Mina这类高度封装的网络通信框架。

    确定了底层网络传输协议之后,需要制定框架自己的通信协议,这样服务双方才能理解对方传达的目的。由于服务之间的通信接口需要支持自定义,所以传输内容的灵活性要求高。通常为了保持灵活性,都会使用序列化的方式将接口定义的实体进行序列化后作为协议的载荷。常见的序列化方式包括Java自带的序列化,json,xml,protobuf等。json、xml都是属于文本形式,占用空间较大,因此如果我自己来实现,我会选择java序列化或者protobuf这种二进制形式的序列化方式,通常使用这些现有方案就能解决问题,如果不能,需要自己实现一套序列化方式,成本较高。

    确定了TCP和序列化机制之后,我会将这两者封装为一个简单易用的API模型。实际上这一部分在我早期未接触分布式服务框架前在日常开发中经常碰到的,通常我会将客户端/服务端的通信封装为一个请求/响应模型,和http类似,但是是自定义的协议,可以选择不同的api实现同步请求或异步接收响应,底层可能会使用连接池来管理客户端与服务端的连接,因为在启动通信模块时会建立多个连接并保持以提高通信效率,并且可以设置请求失败的策略,例如:断线重连、失败重试等。做到这个程度,已经可以满足普通的网络通信需求。

    有了这个通用的网络通信库,在此基础上,可以定义一些内置的服务交互接口,例如可用性检查,安全检查等等。如果要做到监控,那么就应该针对网络请求编写一些过滤器,在请求响应中提取例如调用次数、响应时间、失败次数等信息,并提交到监控服务器。

    接下来聊聊分布式中关键的特性:集群、服务注册和服务发现。

    如果一个服务仅仅部署了一个节点,如果这个节点宕掉了,那么这个服务也就不可用了。因此在实际生产环境下,通常一个服务会部署多个节点。多个节点部署同一个服务,那么消费者应该访问哪个节点呢?这就需要从这些节点之中选择出一个节点,消费者是不能同时访问多个节点的,所以对于消费者来说,不管访问哪一个节点都是一样的。这些节点必须做到无状态,才能够实现这种效果。那么谁来决定选择哪一个节点?有两种方式,一是有一个独立的服务,专门统计了所有的节点的信息,消费者来访问这个服务,这个服务转发请求到提供者,再将提供者的响应转发给消费者。nginx负载均衡集群就是这种形式。另外一种方式是,消费者从这个服务中获取他所要访问的服务的所有节点,自行决定访问哪一个节点并直接访问。如果是这种方式,消费者需要每次都从独立服务去拉取节点信息,否则就需要初始化拉取一次信息,后续节点信息有变化,需要推送给消费者服务。采用这种形式可以降低独立服务的压力,采用推送变化的方式可以保证独立服务宕了之后消费者还能够访问到提供者。dubbo中就是采用这种方式来实现,而这个独立服务叫做注册中心,提供者将自己的节点信息提交到注册中心的动作叫做注册服务,消费者从注册中心获取节点信息的动作叫做发现服务。消费者可以根据节点的状态采用最合适的策略来选择访问的节点,这便达到了负载均衡的目的。

    在项目中采用分布式服务自然会有网络通信的性能损耗。但是并不是每一次请求都一定要到提供者去执行,对于一些数据变化少的接口,我们可以加入缓存,第一次请求之后,后续只需要从缓存获取即可,减少了网络请求的损耗,当然使用了缓存,就要关注缓存什么时候应该过期。

    采用了分布式架构后,会产生许多原来本地调用不存在的问题,例如事务问题。许多问题都需要我们一步步去解决。

以上是我看到了阿里dubbo的架构图后所思考到的分布式服务的架构思路,这张图我仅仅看了每个层次的作用,基本和我的思路差不多,不过,框架开发上,细节非常重要,每个功能的实现细节将影响整体。这篇文章废话比较多,但都是我本人的主要想法,后面的文章会客观的去分析dubbo的源码。

/dev-guide/images/dubbo-framework.jpg

    

转载于:https://my.oschina.net/souljava/blog/1504454

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值