- 浏览: 177304 次
- 性别:
- 来自: 重庆
最新评论
-
way_super:
请问楼主,地图都可以下载了,就是你这里面没有的添加标记的功能, ...
googleMap本地化(离线) -
way_super:
gaoxiangky 写道你好,这个经纬度我解决了,但是我将这 ...
googleMap本地化(离线) -
foreach1025:
...
java源程序加密解决方案(基于Classloader解密) -
cuishuailingcsl:
写的很好,学习了~
java源程序加密解决方案(基于Classloader解密) -
liuchao123:
“保存文件并使用命名source /etc/profile重新 ...
windows上hadoop安装(cygwin等)
java基于线程的分布式
1. 引言
1.1. 背景
有的任务比较消耗资源,需要将任务分散在不同的机器上运行,充分利用硬件资源。
例如下载任务、例如计算1---1万亿的和。
2. 总体思路
任务分发服务器1个、工作客户端若干个
见图:
2.1. 任务分发服务器
负责任务的分发、维护各个客户端的状态。
将应用程序中的任务,添加到队列中,通过策略分发任务给工作线程,维护客户端状态、维护任务状态,对超时的任务等进行处理。
2.2. 工作客户端
在启动的时候向任务分发服务器注册,并开启一定数量的线程池,等待任务分发服务器分配任务。
根据配置文件里的配置,想服务器注册,提供任务执行线程,保持与服务器的会话,维护与服务器的状态,提供自身硬件资源的说明,方便服务器端制定策略分发任务。
3. 详细设计
3.1. 传送对象
3.1.1. 传送任务对象
利用java的对象流传送对象,将服务器端的任务以对象的方式传送给客户端,客户端同样适用对象流接收任务,并复原对象的各个属性。
ObjectOutputStream和ObjectInputStream
ObjectOutputStream在传送对象的时候要求对象是实现了序列化接口的,这要求在编写任务的时候需要实现此接口。
ObjectInputStream在接收对象的时候,需要能够找到对应的类定义,这需要客户端启动之后,能够动态的加载任务类,可以考虑自定义Classloader,在特定的目录中加载任务类定义。这个过程也是由服务器端发起,服务器端在发送任务对象前,先判断任务对象的类定义(字节码)是否已经发送给了客户端,如果没有,则先发送字节码定义给客户端。
3.1.2. 传送工作相关对象
在使用ObjectInputStream,接收对象的时候,不仅需要对象本身能够被加载,对象中使用到的其他类也必须能够被加载。
如:传送对象a,他的类型A,在a中调用了b的方法,b的类型是B,那么ObjectInputStream接收a对象的时候,必须能够加载A、B两个类,才能接受正常。
那么这就需要能够在传送a之前,将a对象嵌套使用的类定义全部传送,这一点暂时没有想到好的办法。(要是有好的建议,请说明。。。)
3.2. 自定义classloader
使用对象流传送对象,在客户端读取对象的时候,需要对内存中能够加载传送过来的任务类,如果在客户端无没有定义传送的任务类,则会跑出ClassCastException,在客户端,采用自定义的Classloader,目的是能够从临时目录中加载传送的任务类定义,在服务器端端,每次分发任务前,会先判断传送的任务类是否已经传送到这个客户端,如果没有,则会首先将任务类的字节码传送到客户端,客户端在接受到任务类的字节码的时候,会将字节码放入到客户端的临时目录里,在后续的接受任务对象的时候,才能够从临时目录中加载对应的类定义,从而实例化并复原从服务器端发送的任务对象。
3.3. 任务失败拦截
在客户端执行的任务,如果在执行的过程中出现异常,会自动向服务器端发送异常报告,说明是哪一个任务没有能够正常的执行完成,将错误信息发送到服务器端,服务器接收到这种异常报告,会将这个任务再次分配,将任务再一次的交给被的客户端去执行。当然,如果任务正常执行结束,客户端也会自动向服务器报告状态,说明任务正常完成,服务器在接收到这种报告的时候,会清除对应的任务再服务器端的状态等信息,这就是整个任务的生命周期。
3.4. 任务的生命周期
1、 初始化的任务,会添加到服务器的队列中,等待服务器分发任务
2、 服务器分发任务到一台客户端上,并且表示这个任务的状态
3、 客户端执行任务,并返回任务的状态
4、 如果客户端没有完成任务,会将任务重新交回到服务器端,服务器会执行步骤2
5、 如果客户端正常完成任务,服务器会在接收到状态报告之后,清除任务的状态标识,任务结束
4. 使用
4.1. 服务器端
4.1.1. 导入依赖包
apache-commons-discovery.jar
apache-commons-id.jar
commons-logging-1.0.4.jar
log4j-1.2.15.jar
distribution.jar
4.1.2. 编写任务类
例子:
public class CalculateWork extends DistributionSupport implements Serializable { private static final long serialVersionUID = 1L; @Override public void run() { /* * 在run的这一层,不处理异常 * 当异常发生的时候,客户端会想服务器报告错误,服务器会重新分发任务 */ int maxNum = new Random().nextInt(100000); int sum = 0; for(int i = 1; i < maxNum; i++){ sum += i; } String message = "计算结果:1---" + maxNum + "的总和为" + sum + ""; if(new Random().nextInt(100) < 30){//概率任务失败 @SuppressWarnings("unused") int errorInt = 1 / 0; }else{ //封装的向服务器传送对象的方法 //向服务器端发送一个打印请求 eventToServer(new Event(EventType.W_ECHO_MESSAGE, message, this, null)); } } }
4.2. 工作客户端
4.2.1. 配置客户端
配置distribution.properties文件
serverIp=127.0.0.1//服务器ip地址 serverPort=10004//服务器监听端口 clientThreadPoolCount=10//客户端工作的线程池大小
4.2.2. 启动客户端
distribution.jar既是服务器端,同时也是一个可运行jar包,直接运行就可以
jar –jar distribution.jar
当然运行的时候需要保证目录中有distribution.properties文件和distribution_lib文件夹(依赖性jar包)
5. 运行截图
5.1. 启动客户端
5.2. 启动服务器端
5.3. 服务器分发3个任务
5.4. 客户端处理任务
6. 目前版本说明:
1、 没有实现任务相关对象的传递,即在任务中,不能使用别的类中的方法,也不能别的类的定义。
2、 服务器端和工作客户端的通信是阻塞式IO
3、 任务的分发是轮询机制,没有加入工作客户端的cpu、内存等资源的参考,以后可以考虑在分发机制上根据工作客户端的状态进行分发
源码、测试程序见distribuition.rar
- distribution.rar (2.4 MB)
- 下载次数: 470
评论
1.强制保证客户端与服务器处于相同的基础ClassPath环境下,可以通过时间检查点来保证这一点。
关于时间检查点可以说详细点吗?
mapreduce
存储+运算
当然不一定就必须使用线程作为任务的载体,也可以使用Task,或是别的(如设计一个接口,在客户端复原对象的时候,强制转换被传输对象为接口,然后调用接口方法)。不过个人感觉使用线程还是有一定的优势的,这种分布式本来就是处理比较耗时的任务(或是叫做工作),当这样的工作发送给客户端执行的时候,客户端再接收到这样的任务的时,一定不能以阻塞式的执行这样一个任务,然后返回结果给服务器端,因为服务器端可能源源不断在传输这样的多个任务到客户端,并且这些任务不具有任何联系,各自完成一部分逻辑操作。客户端再接收到这样的工作后,需要单独开启线程资源来执行这些任务,并行的。
使用队列这一点,你能讲的具体一点么?我这里没有怎么理解,使用队列能满足这样的需求么,如何实现?
假如有这样三个事情需要处理:
1、计算1---1000的累加和,保存结果到本地磁盘文件中d:/calculateResult.txt
2、下载http://www.baidu.cn网页内容,保存结果到磁盘文件d:/downloadResult.txt
3、检查磁盘文件d:/test.txt是否存在,如果存在,则删除
通过“Task分配线程”分配Task,再结合线程池,可以提高效率。存在空闲线程则从Queue取出一个Task分配到该线程上。其实就是通过分配实现并行。当然使用队列还有很多额外的好处,当然这是另一个话题了。
若果你的想实现并行的是有序操作集,则可自己建立TaskQueue作为操作集,同时作为并行单元进行任务。
当然不一定就必须使用线程作为任务的载体,也可以使用Task,或是别的(如设计一个接口,在客户端复原对象的时候,强制转换被传输对象为接口,然后调用接口方法)。不过个人感觉使用线程还是有一定的优势的,这种分布式本来就是处理比较耗时的任务(或是叫做工作),当这样的工作发送给客户端执行的时候,客户端再接收到这样的任务的时,一定不能以阻塞式的执行这样一个任务,然后返回结果给服务器端,因为服务器端可能源源不断在传输这样的多个任务到客户端,并且这些任务不具有任何联系,各自完成一部分逻辑操作。客户端再接收到这样的工作后,需要单独开启线程资源来执行这些任务,并行的。
使用队列这一点,你能讲的具体一点么?我这里没有怎么理解,使用队列能满足这样的需求么,如何实现?
假如有这样三个事情需要处理:
1、计算1---1000的累加和,保存结果到本地磁盘文件中d:/calculateResult.txt
2、下载http://www.baidu.cn网页内容,保存结果到磁盘文件d:/downloadResult.txt
3、检查磁盘文件d:/test.txt是否存在,如果存在,则删除
LZ的想法是正确的,至于前面提到的是否合并task结果,是否让部分task有序,那是后续和细化
可以为每个客户机分配一个queue,让分配task的线程往各个queue里塞任务
当然也要看客户机是怎么实现的,可以做些有序化的处理什么的
思路随便想想总有的,我也是随便说的
当然不一定就必须使用线程作为任务的载体,也可以使用Task,或是别的(如设计一个接口,在客户端复原对象的时候,强制转换被传输对象为接口,然后调用接口方法)。不过个人感觉使用线程还是有一定的优势的,这种分布式本来就是处理比较耗时的任务(或是叫做工作),当这样的工作发送给客户端执行的时候,客户端再接收到这样的任务的时,一定不能以阻塞式的执行这样一个任务,然后返回结果给服务器端,因为服务器端可能源源不断在传输这样的多个任务到客户端,并且这些任务不具有任何联系,各自完成一部分逻辑操作。客户端再接收到这样的工作后,需要单独开启线程资源来执行这些任务,并行的。
使用队列这一点,你能讲的具体一点么?我这里没有怎么理解,使用队列能满足这样的需求么,如何实现?
假如有这样三个事情需要处理:
1、计算1---1000的累加和,保存结果到本地磁盘文件中d:/calculateResult.txt
2、下载http://www.baidu.cn网页内容,保存结果到磁盘文件d:/downloadResult.txt
3、检查磁盘文件d:/test.txt是否存在,如果存在,则删除
fork-join ...
douglas lea is working hard for that...included in JDK 7...
那你这个task是小task.如果有一个task,很大,运行完要很久。能不能把这个task分在不同机器上同时跑,跑完合并task结果。
这种牵涉到逻辑切分的东东,暂时不会。。。。。。
你说是多进程,这个我同意,我觉得也可以这样理解,每个进程中可以运行多个线程,每个进程里面的线程不是在进程初始化的时候拥有的,是通过网络的传输从分发服务器端获得的,这样的过程可以持续,这样的工作端进程是可以一直运行,等待处理分发服务器端的线程任务。
“多机器并行task”
这个似乎不是这样,在分发服务器端获取到这样一个task之后,只会将这样一个任务交给一个客户端处理,并不会在多个机器上都持有这样一个对象(任务)的副本,并且,分发之后,在服务器端只是保留了这样一个对象的唯一标示(uuid),并不保留这样一个任务的任何引用,在服务器端的垃圾回收阶段,可能将这个任务的内存分配都给回收,这个对象在创建---分发之后,就只存在于某一台客户端机器上(某一个进程中)上。
那你这个task是小task.如果有一个task,很大,运行完要很久。能不能把这个task分在不同机器上同时跑,跑完合并task结果。
你说是多进程,这个我同意,我觉得也可以这样理解,每个进程中可以运行多个线程,每个进程里面的线程不是在进程初始化的时候拥有的,是通过网络的传输从分发服务器端获得的,这样的过程可以持续,这样的工作端进程是可以一直运行,等待处理分发服务器端的线程任务。
“多机器并行task”
这个似乎不是这样,在分发服务器端获取到这样一个task之后,只会将这样一个任务交给一个客户端处理,并不会在多个机器上都持有这样一个对象(任务)的副本,并且,分发之后,在服务器端只是保留了这样一个对象的唯一标示(uuid),并不保留这样一个任务的任何引用,在服务器端的垃圾回收阶段,可能将这个任务的内存分配都给回收,这个对象在创建---分发之后,就只存在于某一台客户端机器上(某一个进程中)上。
task跟thread的确是两个概念。
线程从来都是性能的杀手。
假如客户端使用完成端口来处理这个task怎么办?
task跟thread的确是两个概念。
我可能在描述上有的时候没有说得很清楚,我将需要处理的事情也看做是一个任务,我这里讲的任务并不是java中直接使用new等方式创建的task,本文中提到的任务是指一系列的有序操作的集合。
线程从来都是性能的杀手。
线程的start才会导致系统资源的消耗,在服务器端,只是使用了new 方法来创建一个新的对象,并没有分配线程资源,这个任意别的对象的初始化是一样的,不会因为它是线程对象而对系统的性能造成影响。创建好的对象,会以流的方法分发到工作的客户端,客户端才会为这个线程消耗系统资源,调度这个线程运行。这就是设计这个分布式的理由了,利用多台机器的硬件资源得到运行结果。
假如客户端使用完成端口来处理这个task怎么办?
这个没有看懂意思。。。。
建议楼主参考一下C# 4.0 task,那个叫简单哦
线程从来都是性能的杀手。
设计依赖线程,是个错误的依赖方向。
假如客户端使用完成端口来处理这个task怎么办?
别个那个Class之间的依赖关系处理的问题,我觉得有这几种方法。
1.强制保证客户端与服务器处于相同的基础ClassPath环境下,可以通过时间检查点来保证这一点。
2.引入诸如OSGI这种需要依赖配置的依赖管理的框架。
3.自己对Class文件进行import级别的依赖分析,这一点基本不太可能做到自动化,比如我不能过import而直接用class.forname("xxxx"),你基本很难分析出来你这个依赖于xxxx。
发送的东西是能够被序列化的对象,对象都能够以流的方式被发送,至于是task或是thread,这个都没有什么关系,重要的是在传输之后,能在客户端上复原对象,然后让对象处理对应的业务逻辑。这里之所以选择 基于线程 ,是因为觉得线程能够在客户端复原后运行,执行对应的业务逻辑操作。
至于class的依赖关系,我觉得还是不要强制同一个classpath等方式,因为在这里,就是为了方便开发,客户端根本就不需要知道服务器的任务是什么,只需要注册到服务器,由服务器分发任务即可,服务器在分发任务的时候,需要将客户不能识别的类定义传送给客户端,方便客户端接收。这样,在开发的时候,只需要关注任务是什么,不关注服务器与客户端的部署问题,客户端可以是世界上的任意机器,在任意位置,启动后注册,然后就能利用客户端的硬件资源帮助处理业务。
别个那个Class之间的依赖关系处理的问题,我觉得有这几种方法。
1.强制保证客户端与服务器处于相同的基础ClassPath环境下,可以通过时间检查点来保证这一点。
2.引入诸如OSGI这种需要依赖配置的依赖管理的框架。
3.自己对Class文件进行import级别的依赖分析,这一点基本不太可能做到自动化,比如我不能过import而直接用class.forname("xxxx"),你基本很难分析出来你这个依赖于xxxx。
发送的东西是能够被序列化的对象,对象都能够以流的方式被发送,至于是task或是thread,这个都没有什么关系,重要的是在传输之后,能在客户端上复原对象,然后让对象处理对应的业务逻辑。这里之所以选择 基于线程 ,是因为觉得线程能够在客户端复原后运行,执行对应的业务逻辑操作。
至于class的依赖关系,我觉得还是不要强制同一个classpath等方式,因为在这里,就是为了方便开发,客户端根本就不需要知道服务器的任务是什么,只需要注册到服务器,由服务器分发任务即可,服务器在分发任务的时候,需要将客户不能识别的类定义传送给客户端,方便客户端接收。这样,在开发的时候,只需要关注任务是什么,不关注服务器与客户端的部署问题,客户端可以是世界上的任意机器,在任意位置,启动后注册,然后就能利用客户端的硬件资源帮助处理业务。
别个那个Class之间的依赖关系处理的问题,我觉得有这几种方法。
1.强制保证客户端与服务器处于相同的基础ClassPath环境下,可以通过时间检查点来保证这一点。
2.引入诸如OSGI这种需要依赖配置的依赖管理的框架。
3.自己对Class文件进行import级别的依赖分析,这一点基本不太可能做到自动化,比如我不能过import而直接用class.forname("xxxx"),你基本很难分析出来你这个依赖于xxxx。
将需要处理的工作封装在线程内,由服务器将这个工作线程分发给客户端处理,这就是和线程的关系。
如果不适用线程,没有想到好一点的方法将一个工作(任务)从一个机器传到另外一个机器上,然后怎么样复原。
发表评论
-
java基于filter的应用缓存框架
2012-08-10 17:34 3567java web 基于filter的缓存 ... -
hadoop未修复bug6287的解决办法(ttprivte to 0700的bug、setPermission failed)
2012-04-06 17:31 3753hadoop-0.20.2以上版本,若在windows下使用c ... -
windows上hadoop安装(cygwin等)
2012-04-05 19:32 9790hadoop运行方式 1、本机方式:不做任何配置 2、伪分布式 ... -
云计算的理解
2012-03-30 15:19 1500分布式系统,解决的问 ... -
mybatis二级缓存工作机制
2012-03-22 15:31 19288mybatis二级缓存工作机制 在mybatis的主配置文件 ... -
js获取get方式传递的参数
2012-01-05 12:48 3009String.prototype.GetValue= f ... -
Tomcat_Broken pipe
2011-12-31 10:10 4619这个异常是由于以下几个原因造成。 1、客户端再发起请求后没有等 ... -
linux1024下端口安全性问题
2011-11-13 09:55 1368Linux下认为1024以下的端口都是不安全的,所以打开102 ... -
Parameters Invalid chunk '' ignored警告
2011-11-07 09:59 1396Parameters Invalid chunk '' ign ... -
hql语句中支持的本地时间函数
2011-11-01 16:17 11650hql语句中支持的本地时间函数 1、UNIX_TIMES ... -
ckeditor等在线编辑器于struts结合无法上传图片问题
2011-10-21 08:32 2535ckeditor与struts结合的时候,需要注意Struts ... -
java的server模式
2011-10-21 08:30 1342The Java HotSpotTM Server VM is ... -
linux top命令中各cpu占用率含义
2011-10-20 08:24 15960.3% us 用户空间占用CPU百分比 1.0% sy 内核 ... -
iframe自适应高度
2011-10-19 17:34 946<script> function dyni ... -
tomcat部署为服务器注意事项
2011-10-19 08:57 1122(1)使用内存 在启动脚本 catalina.sh或 ... -
jpa/hibernate继承注解
2011-03-24 23:08 9246hibernate继承映射 以下测试是在mysql中进行的。 ... -
OpenJMS(java消息服务的一个实现)的使用
2010-12-13 10:22 1878Openjms的使用 jms:java message ser ... -
web爬虫的广度优先算法
2010-12-10 13:23 6095web爬虫中需要设计一个广度优先的算法,以控制爬虫爬行网址的先 ...
相关推荐
Java的多线程和平台独立的特性为在异构系统中实现分布式计算提供了一个良好的环境。同时Java提供的远程方法调用(Remote Method Invocation, RMI)特性使客户机上运行的程序可以引用远程服务器上的远程对象方法,使得...
8、调度线程池:调度系统多线程触发调度运行,确保调度精确执行,不被堵塞; 9、执行日志:支持在线查看调度结果,并且查看完整的执行日志; 10、邮件报警:任务失败时支持邮件报警,支持配置多邮件地址群发...
多线程Web服务器一种多线程(例如,基于文件的)Web服务器,具有Java中实现的线程池。 任何实现WebApp接口的类都可以作为处理程序应用程序插入。 在此示例中,我使用FileServingApp (从文档根目录提供静态文件)...
基于Java整合ChickHouse的分布式日志收集与检索系统 实现功能 UDP与HTTP日志接收(基于缓冲队列,使用多线程批量消费日志消息至ChickHouse) 日志分类划分(利用Redis存储日志级联分类信息) 监控台日志检索与数据...
分布式(多进程)架构,几行代码实现一个功能服务器的搭建 多线程设计,注解方式配置,轻松管理所有消息流 强大的RPC功能,调用远程RPC近似于调用本地函数,无需手工定义内部协议 支持插件功能,轻松实现功能插件 框架...
zooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是集群的管理者。提供了文件系统和通知机制。 在开发项目的过程中,很多大型项目都是分布式部署的,那么我们现在使用zookeeper实现一个分布式锁。
在分布式系统中,往往需要使用分布式锁来保证某个代码块在同一时间只被一个线程执行。Redis作为高性能的内存数据库,可以通过其原语命令实现分布式锁。Java集成步骤包括:引入Redis客户端依赖、编写分布式锁工具类利用...
一个基于棋牌、MMORPG游戏的分布式java游戏服务器,理论上可以无限水平扩展网关服,大厅服、游戏服达到人数承载。实现了集群注册中心,网关、登陆、后台服务器监控等通用服务器;封装了redis集群、mongodb等数据库...
软件开发设计:应用软件开发、系统软件开发、移动应用开发、网站开发C++、Java、python、web、C#等语言的项目开发与学习资料 硬件与设备:单片机、EDA、proteus、RTOS、包括计算机硬件、服务器、网络设备、存储设备...
基于Redis的过期机制,DLock实现了锁[租借](以保证释放。为了提供高性能,DLock采用进程级锁模型并使用变体 CLH 队列来管理锁竞争者。 要求:+、 +(需要Redis Set -> NX PX命令) 建筑学 特征 原子锁操作 一个锁...
它是用于多线程ETL的完整软件包-它包含代码,可以并行使用来自分布式Apache Kafka服务器的消息; 其次,它具有易于适应的Hibernate接口,可用于数据库操作; 此外,它还配置有Spring,以轻松访问和管理整个应用程序...
使用zookeeper来实现分布式锁 原理 监听zookeeper的临时有序节点,监听到NodeDeleted事件,就会让线程重新获取锁 测试方法 public class ZookeeperLockTest { public static void main(String[] args) throws ...
socket通信实现,登录系统,玩家线程模型,db系统,分布式id生成器,分布式锁,缓存系统,热更新机制,rpc系统,全服组队等等组织结构gameserver├── client -- 测试用netty客户端├── rpc-api -- 提供分布式的rpc基础├...
这是基于Java8的官方文档,使用Easy ...Java具有简单性、面向对象、分布式、健壮性、安全性、平台独立与可移植性、多线程、动态性等特点 。Java可以编写桌面应用程序、Web应用程序、分布式系统和嵌入式系统应用程序等。
与单机的多线程不一样的是,分布式跨多个机器。线程的共享变量无法跨机器。 为了保证一个在高并发存场景下只能被同一个线程操作,java并发处理提供ReentrantLock或Synchronized进行互斥控制。但是这仅仅对单机环境...
一个用spring、mybatis、redis和shiro开发的分布式权限管理系统 Java是一种高性能、跨平台的面向对象编程语言。它由Sun Microsystems(现在是Oracle Corporation)的James Gosling等人在1995年推出,被设计为一种...
可定制每一个流程)速度快(多线程爬虫,线程池管理,线程池下载,分布式)分布式(基于redis,mq等,部署简单,速度很快)使用情况近12个月maven中央仓库使用情况。安装使用maven<dependency> <groupId>...
基于JAVA的UDP服务器模型源代码,内含UDP服务器端模型和UDP客户端模型两个小程序,向JAVA初学者演示UDP C/S结构的原理。 简单聊天软件CS模式 2个目标文件 一个简单的CS模式的聊天软件,用socket实现,比较简单。 ...
基于JAVA的UDP服务器模型源代码,内含UDP服务器端模型和UDP客户端模型两个小程序,向JAVA初学者演示UDP C/S结构的原理。 简单聊天软件CS模式 2个目标文件 一个简单的CS模式的聊天软件,用socket实现,比较简单。 ...
java.rmi.dgc 为 RMI 分布式垃圾回收提供了类和接口。 java.rmi.registry 提供 RMI 注册表的一个类和两个接口。 java.rmi.server 提供支持服务器端 RMI 的类和接口。 java.security 为安全框架提供类和接口。 ...