架构设计:一种远程调用服务的设计构思(zookeeper的一种应用实践)
在深入学习zookeeper我想先给大家介绍一个和zookeeper相关的应用实例,我把这个实例命名为远程调用服务。通过对这种应用实例的描述,我们会对zookeeper应用场景会有深入的了解。
远程调用是系统与系统之间的通信机制,它的另一种理解就是进程间的通信。做分布式系统的开发,远程调用技术是其核心技术。远程调用技术可以将一组计算机系统形成一个网络系统,对外提供整体服务,那么这一群的计算机系统就构成了一个更大型,性能更高的计算机系统。
我在前面的博客里介绍了一种分布式网站的架构设计,其中就有一个使用netty技术编写的组件作为前端系统和服务端系统通信的媒介。在一个大型的互联网公司里会有很多这样的网站系统,如果每一个网站都像我博客里所论述的进行开发,那么对于系统通信维护和管理,以及每个系统网络资源的分配管理就会造成一定的问题,对于这样的问题,我举个例子可能大家会更明白些,比如一个互联网公司有数个对外提供服务的网站,有的网站访问量很大,有的相对较小,但是公司的宽带资源是有限的,那么我们就希望动态的管理和分配这些资源,如果我们网站的通信功能和网站都是紧耦合的,那么调配这些资源的工作就会比较复杂和繁琐,也很容易出问题。这样的问题还会还有很多,我这里不做细致分析了。做软件开发时候,有个原则,如果某个功能是可以通用的,该功能很需要统一管理时候,我们就应该把这个功能抽取成一个独立的系统或组件,并且这个系统或组件赋予一些增强级的功能特性,这样必定对整个系统的健壮性、可用性以及效率上有所提升。
而我在分布式网站里所描述的通信技术,就是远程调用技术的一种,远程调用技术就是客户端和服务端的通信技术,它可以当做cs架构技术的一种,在java里有很多优秀的框架实现远程调用,例如java自带的RMI,spring自带的Httpinvoker,webservice技术等等。但是现有的这些技术满足不了互联网公司的远程调用需求,今天我将讲述一套我自己构思的一套远程调用技术,这个是借鉴了一些我们公司的类似软件的做法。
该框架主要是针对java的,其他语言目前不能支持。首先我要总结远程调用技术要包括那些技术,它们分别是:
- 通信技术:远程调用就是通过网络技术将不同系统构成一个整体,因此通信技术是其重点,通信技术我这里选择的是netty技术,Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。Netty会让我们开发通信程序变得简单,高效,其效率也是非常好的,同时它还支持多种不同的网络协议。
- 序列化和反序列化技术:java的序列化技术是指将对象转换为byte数据,这些数据可以被还原为java对象,这种还原的过程就是反序列化了,该机制可以自动处理不同操作系统之间的差异,例如window下序列化的对象,可以在linux上进行重新构建。Java的jdk里自带了一个序列化和反序列化机制,熟悉hadoop的人知道hadoop设计了一套序列化和反序列化机制,为什么hadoop作者不选择使用java自带的序列化机制,这是因为java序列化机制非常复杂,复杂带来效率低下,java的序列化机制还有一个重要的缺点就是它序列化的二进制数据会非常大,因为java序列化时候会附带太多该对象的相关信息,过大的数据量就会影响网络传输的效率,因此hadoop自己设计了一套序列化和反序列化机制,hadoop不同节点之间的通信也是一种远程调用机制,因此我们发现好的序列化和反序列化技术对于远程调用是相当重要的。我们公司的远程调用框架序列化技术有两种一种就是java自带的序列化和反序列化机制,一种是hessian技术,它是一种更加高效的序列化和反序列化技术。
- 压缩技术:做网络编程,最稀缺的资源就是宽带资源,如果传输数据过大,那么对数据的压缩就会显得十分重要,这里我推荐一个压缩技术snappy,它是一种高效的压缩和解压缩包,google公司内部广泛使用的一种压缩技术。
- 高并发的技术:远程调用技术一定会是多线程,只有这样才能满足多个并发的处理请求,java在1.5的版本里提供了一个Executor框架,它在线程开发里引入了任务的概念,使得多线程的程序开发会更加合理和可控,关于executor的技术大家可以看看一本经典的书籍《java并发编程实践》。想让线程更加有效率,池技术也是并不可少的,apache的common-pool是一个非常好的池技术,我们可以将线程都预先创建好,然后放入到common-pool池里进行管理。
- 非侵入式:这个也可以叫做松耦合,对于java的web开发,最好的解耦方式就是使用spring技术,当我们系统里把远程调用框架引入后,配置好相关的参数,我们可以把用于远程调用的方法定义在spring的配置文件里,那么在程序里调用的时候,利用spring直接获取这个bean,那么对于远程调用的开发就和我们在action里调用server的方法没啥区别了。下面是一段实例代码:
<!-- 服务提供者配置 -->
<bean id="serverProvider" class="cn.com.sharpxiajun.RmifSpringProviderBean">
<property name="interface" value="cn.com.ITest"></property><!-- 远程调用的接口 -->
<property name="target" ref="clsTest"></property><!-- clsTest实现ITest的实现类,clsTest这里是一个bean的id值 -->
</bean> <!-- 服务调用者配置 -->
<bean id="clientConsumer" class="cn.com.sharpxiajun.RmifSpringConsumerBean">
<property name="interface" value="cn.com.clsTest"></property><!-- value就是Provider定义的target的接口实现类 -->
<property name="seriaType" value="hessian"></property><!--序列化方式 -->
<property name="compress" value="true"></property><!-- 压缩标记 -->
</bean>
6.负载均衡:分布式系统都离不开负载均衡,好的负载均衡可以充分利用好不同服务器的计算资源,提供系统的并发量和运算能力,对于网站而言(我们公司现在网站服务器不是太多)少于10台服务器可以使用两种策略:一种是简单轮询,比如有6台服务端,我们会把第一个请求给第一台服务器,第二个请求给第二台,依次类推,等6台循环完毕,又从第一台开始;第二种是随机方式,即使用random函数,当然更多的服务器我就不知道有什么轮询机制比较好,希望有知道的童鞋可以给我推荐下。
我这里设计的远程调用框架,除了以上的功能外,我希望它还能有心跳管理机制,超时管理机制,服务分级管理,就是根据服务的重要性或者系统的繁忙度可以调节网络资源。
哈哈,讲了这么久估计有童鞋可能有点烦了,不是说应用zookeeper的实例吗?怎么还没见到zookeeper的影子。别着急,zookeeper马上就要上场了。
还是以我前面博客里写分布式网站讲起,服务端系统我们可以当做服务提供者,前端系统当做服务调用者,提供者可以类比商户,调用者可以类比客户,商户和客户可以直接进行交易,这种直接交易方式非常原始甚至还会有风险,现代社会商户和客户直接的交易十分高效,高效的原因是因为有一个规范的大市场,商户和客户的交易在市场里进行的,这样交易会变得更加安全和高效,我设计的分布式框架最大的特点就是提供了一个类似市场的角色,它来管理服务提供者和服务调用者,我把这个功能模块称为远程调用管理组件。
远程调用管理组件是本框架的核心,它的主要作用是接收服务端提供者的注册的通知,该通知一般是接口以及该接口的实现类还有服务器的ip地址,管理组件会将这些通知记录下来,并且根据配置对这些服务程序进行分组和标记,注册好的信息管理组件会将这些信息推送到服务调用者。远程调用管理组件还包含心跳机制,这个心跳机制是针对服务提供者,通过心跳机制检测服务提供者的健康状况,管理组件不会检测服务调用者的健康状态,因为这个没必要,因为本框架的使用还是调用者直接去请求提供者,逻辑上是没必要关心调用者的状态,这和bs架构里浏览器一样,我们不会去关心浏览器用户是不是存在。服务提供者、服务调用者和远程调用管理组件的关系如下图所示:
远程调用框架运行的过程是:当服务提供者启动时候,它会将自己的ip地址和注册的方法传输到远程调用管理组件,管理组件接收到注册信息会将这些信息存储下来,存储技术就是使用zookeeper,存储成功后,管理组件会将成功通知传回给服务提供者,同时管理组件还会通过心跳检测服务提供者是否健康;当服务调用者启动时候,它会向管理组件请求服务提供者信息,管理组件接收到请求后会将相关信息推送给服务调用者。在实际系统运行时候,服务调用者直接和服务提供者进行通信交互了,通信方式是netty,如果调用者和提供者有相关变化,都会先通知服务管理组件,服务管理组件会将相关变更信息推送给相应的系统。
远程调用管理组件主要是通过zookeeper实现,zookeeper拥有一个层次的命名空间,它的模型是一个树状结构,树状结构是一个强大的数据类型,它几乎能存储所有不同的数据类型,我们通过zookeeper将这些信息保存起来,便于我们管理整个远程调用框架,同时zookeeper还是高可靠的,这个我在前面zookeeper文章里讲到了,这样就保证了整个远程调用框架的稳定性,实际应用中我们会将组件编译成一个jar包,不同的项目直接引用这个jar包,这样管理组件服务端和服务的提供者和调用者就联系起来。至于提供者和调用者的通信机制是直接进行,因为我们将通信程序集成在jar包里,只不过相应的管理机制抽取到外部服务端进行统一管理。
这就是我设计的远程调用框架,可惜的是,这个构思我还没有真正实现过,今天拿出来是想体现zookeeper的实际应用,为我后面讲解zookeeper做铺垫,至于是否可行,看以后有没有机会开发个类似的系统,到时估计还有很多意想不到的问题要解决。
(远程调用服务的设计我参考了技术友人马德鑫的设计,他曾是淘宝的技术架构师)
架构设计:一种远程调用服务的设计构思(zookeeper的一种应用实践)的更多相关文章
- 架构设计:远程调用服务架构设计及zookeeper技术详解(下篇)
一.下篇开头的废话 终于开写下篇了,这也是我写远程调用框架的第三篇文章,前两篇都被博客园作为[编辑推荐]的文章,很兴奋哦,嘿嘿~~~~,本人是个很臭美的人,一定得要截图为证: 今天是2014年的第一天 ...
- 如何从零开始实现一个soa远程调用服务基础组件
说起soa远程调用基础组件,最著名的莫过于淘宝的dubbo了,目前很多的大型互联网公司都有一套自己的远程服务调用分布式框架,或者是使用开源的(例如dubbo),或者是自己基于某种协议(例如hessia ...
- 使用AIDL远程调用服务中的方法
AIDL:android interface define language(接口定义语言) 作用:方便远程调用其他服务中的方法 注意:安卓四大组件都要在清单文件注册 aidl创建图: AIDL的全称 ...
- spring boot / cloud (八) 使用RestTemplate来构建远程调用服务
spring boot / cloud (八) 使用RestTemplate来构建远程调用服务 前言 上周因家里突发急事,请假一周,故博客没有正常更新 RestTemplate介绍: RestTemp ...
- 几种远程调用接口协议简单比较和web service(SOAP)与HTTP接口的区别:
什么是web service? 答:soap请求是HTTP POST的一个专用版本,遵循一种特殊的xml消息格式Content-type设置为: text/xml任何数据都可以xml化. ...
- springcloud系列五 feign远程调用服务
一:Feign简介 Feign 是一种声明式.模板化的 HTTP 客户端,在 Spring Cloud 中使用 Feign,可以做到使用 HTTP请求远程服务时能与调用本地方法一样的编码体验,开发者完 ...
- Android Service AIDL 远程调用服务 【简单音乐播放实例】
Android Service是分为两种: 本地服务(Local Service): 同一个apk内被调用 远程服务(Remote Service):被另一个apk调用 远程服务需要借助AIDL来完成 ...
- 远程调用服务框架-CXF(WebServic)
介绍 远程调用web服务,不需要自己编写具体代码,只需要调用作者给出的接口即可. 我们可以调用互联网上查询天气信息Web服务,然后将它嵌入到我们的程序(C/S或B/S程序)当中来,当用户从我们的网点看 ...
- Springcloud踩坑记---使用feignclient远程调用服务404
公司项目进行微服务改造,由之前的dubbo改用SpringCloud,微服务之间通过FeignClient进行调用,今天在测试的时候,eureka注册中心有相应的服务,但feignclient就是无法 ...
随机推荐
- 如何一步一步用DDD设计一个电商网站(八)—— 会员价的集成
阅读目录 前言 建模 实现 结语 一.前言 前面几篇已经实现了一个基本的购买+售价计算的过程,这次再让售价丰满一些,增加一个会员价的概念.会员价在现在的主流电商中,是一个不大常见的模式,其带来的问题是 ...
- Asp.Net Mvc 使用WebUploader 多图片上传
来博客园有一个月了,哈哈.在这里学到了很多东西.今天也来试着分享一下学到的东西.希望能和大家做朋友共同进步. 最近由于项目需要上传多张图片,对于我这只菜鸟来说,以前上传图片都是直接拖得控件啊,而且还是 ...
- Java基础Map接口+Collections工具类
1.Map中我们主要讲两个接口 HashMap 与 LinkedHashMap (1)其中LinkedHashMap是有序的 怎么存怎么取出来 我们讲一下Map的增删改查功能: /* * Ma ...
- Javascript正则对象方法与字符串正则方法总结
正则对象 var reg = new Regexp('abc','gi') var reg = /abc/ig 正则方法 test方法(测试某个字符串是否匹配) var str = 'abc123'; ...
- iOS 键盘添加完成按钮,delegate和block回调
这个是一个比较初级一点的文章,新人可以看看.当然实现这个需求的时候自己也有一点收获,记下来吧. 前两天产品要求在工程的所有数字键盘弹出时,上面带一个小帽子,上面安装一个“完成”按钮,这个完成按钮也没有 ...
- 游走 bzoj 3143
游走(2s 128MB)walk [问题描述] [输入格式] [输出格式] [样例输入] 3 3 2 3 1 2 1 3 [样例输出] 3.333 [样例说明] 题解: 主要算法:贪心:高斯消元: 题 ...
- ABP项目中使用Swagger生成动态WebAPI
本文是根据角落的白板报的<使用ABP实现SwaggerUI,生成动态webapi>一文的学习总结,感谢原文作者角落的白板报. 1 安装Swashbuckle.core 1.1 选择WebA ...
- git命令行操作
从本地上传代码到仓库(假设已经建好仓库): 1.初始化: git init 2.将所有文件加入缓存区: git add * 3.提交当前工作空间的修改内容: git commit -m 'commit ...
- 多本地代码工作点更新到2个远端GIT仓库
摘要:本文介绍了笔者多个本地工作节点(地方)的多台电脑(PC/笔记本电脑)同步源码到2个远端的GIT(一个GITHUB国外强制公开,一个oschina国内可不公开). 作者:太初 转载说明:请指明原作 ...
- Android快乐贪吃蛇游戏实战项目开发教程-04虚拟方向键(三)三角形按钮效果
该系列教程概述与目录:http://www.cnblogs.com/chengyujia/p/5787111.html 一.知识点讲解 当我们点击系统自带的按钮时,按钮的外观会发生变化.上篇博文中我们 ...