用DotNet做简单的分布式计算的几个关键技术点
2012-02-03 21:39 java线程例子 阅读(281) 评论(1) 编辑 收藏 举报 hadoop的数据流分布式处理模型,是分布式计算模型的一种实现,hadoop对海量文件数据比较适合,但对于很多公司的应用系统而言,基本都是基于数据库的,并没有多少文件数据需要实时分析,就是日志文件,也可以放在数据库中,特别是用户操作日志(不是系统级日志),当然,就是存成文件,格式和内容也基本是确定的,分析的时候并不需要分拆和Map.其实只要一个简单的分布式分析(reduce)即可。因此模型上没必要搞得像hadoop那么复杂(虽然说hadoop原理和实现也不是很复杂).何况大部分应用系统需要分析的数据还达不到这个级别.
考虑到一般的公司应用的实时数据存放都是确定的,也就是分析数据的来源基本是确定的,绝大部分的分析任务都会关顾所有的数据节点,因此也没必要把调度服务搞得很复杂。模型可以进一步简化。分布式计算的关键点其实就在于分析代码的部署和管理、分布计算调度和执行、结果合并等。
首先,对于分布式计算代码的自动部署其实很简单,可以利用dotnet的wcf,(用 socket也可以,但用代码wcf简单,效率吧也不会差多少,如果用socket就看写的人功底了).用wcf来传送命令,同时传送要执行任务的代码(代码量一般都不大,直接用byte数组就完全够了),代码部署服务接到代码后可按照自己设定的规则来存为计算节点上的代码。
其次对于分布式计算的执行,可以利用dotnet的应用程序域和程序集动态加载技术来完成,其实我觉得dotnet的这个架构还是非常好的,将用户任务代码放在自己的应用程序域中来执行比在宿主程序主应用程序域中采用线程来执行要安全很多(当然也可以体外执行,但可控性会小很多),不会影响宿主应用本身,用户代码之间也会有更好的隔离性,对资源的消耗也小很多,而且是同一进程,也有利于主应用程序监控执行过程和获取执行结果。同时还可以弥补程序集加载后不能卸载的DotNet框架的缺点(其实也不能完全说是缺点,毕竟程序集加载后,可能很多其它地方都在应用该程序集,你卸载它势必会造成一些问题,而整个应用程序域卸载,由于其在程序集上的独立性,就不会有什么问题产生,比较安全,而且易于实现)。
对于分布式计算的调度,由于这种基于数据库的应用数据源节点都比较确定,用全部都执行和用户任务指定节点执行两种方式就可以了,这就免除了基于负载情况的复杂调度模式。结果合并了逻辑可由客户代码自己完成,只是由宿主程序来执行(宿主是对等的,就是计算节点,但合并只在接受计算任务请求的节点执行)。中间的分布式计算结果我觉得接口上都采用字符串来进行,这个字符串怎么解释交给用户代码自己决定(实体类结果可以序列化成字符串,回来后可以反序列化回去,字符串可以达到4G,如果不行采用文件流也可以,但一般情况下字符串就足够了)。
虽然上面说计算节点是对等的,但有个问题就是如何解决一个节点知道其它节点的问题,如果每个节点都探测其它节点,这当然不是有效率的。我采用的方法是选一台比较好的服务器做master,规定服务地址,由该节点维持一个其它节点的状态。但这种状态信息也没必要持久化(其它节点反而可以持久化,好处是master挂掉还是可以继续工作)。其它节点启动后每隔一段时间就会向Master发送自己的状态,并向这个节点获取其它节点信息。再获取这些节点信息后,节点还是会相互之间更新状态(不是必须的),如果Master挂掉后,这些节点由于保存有其它一些节点的信息,还是可以工作,当然新起来的节点还是会受到影响,而Master重新起来后,其它节点就会把自己的状态注册进来,因此Master只是起到一个简化探测的桥梁作用。这些heartbeat消息我也是采用wcf实现,只不过使用的是一次性服务(不是应答模式和双工模式).
整体过程如下: 用户基于提供的计算合并接口(两个接口)开发一个或多个自己的计算类,并编译成程序集代码,然后将该程序集代码作为参数(字节流)调用部署服务将代码,调用成功后,就可以调用执行服务代码(也可以把代码放在这里做为参数传入),代码并不需要每次都部署,系统会按一定规则寻找原先部署的代码来完成计算,分布式计算完成后,服务将结果反馈给用户(可异步和同步).当然执行的时候需要指定计算类.
安全在服务层做(如图边线),内部节点间请求可采用网卡物理地址认证,所有的请求都进行AES加密,并用时间戳和内部执行序列完成重复请求和伪造请求的安全认证,当然一般情况下没必要,因为这个系统是运行在内部的.用户代码安全可在应用程序域创建的时候通过控制程序域的安全参数来完成.
其实基于以上分布式计算模型,不仅可以做实时分析,也可以做计算机管理等,而且可以随时动态的增加功能,动态升级,一次部属(节点Host程序),当然,如果搞点其它技术,就是一个超级病毒。
主要技术点:应用程序域,程序集动态加载,泛型,类的动态实例化,WCF(服务,自建宿主,动态调用代理),多线程(分发执行时),接口(分布式计算执行接口).
大家可以去实现一下,其实做进去就没这么难了,在这个基础上再模拟做MapReduce就很简单了.
补充(2012-02-08):真正做的时候细节需要处理的地方还是很多,就是调试也需要技巧的,因为很多地方都需要用多线程实现异步调用。当然,WCF的安全和序列化问题,也耗费了不少时间,WCF报错很多时候都比较笼统,加上有时正常有时异常,使得追踪分析错误很困难。如果大家做的过程中遇到这些问题,可以参考我后面写的博客,可以少走些弯路。