在stackOverflow网站上看到这一提问,下文是部分摘抄问题简述:

Java cluster, run task only once

We have a java process, which listen's to a directory X on the file system using apache commons vfs. Whenever a new file is exported to this directory, our process kicks in. We first rename the file to filename.processing and parse the file name, get some information from the file and insert into tables, before sending this file to a Document management system. This is a single-threaded application per cluster. Now consider this running in a cluster environment, we have 5 server's. So 5 different VM's are trying to get access of the same file. The whole implementation was on the basis that only one process can rename the file to .processing at a given time, as OS will not allow multiple processes modifying the file at the same time. Once a cluster get's holds and renames file to .processing, other cluster's will ignore files which are of format .processing.

上述问题简而言之,就是假设软件里有一个监听某个文件变化以及命名服务,这在单机部署时一点问题都没有,但是当多机集群时,如果不加额外逻辑限制,那么每个集群节点都会去执行多个监听以及命名服务,对于文件系统,这是非常危险的。

还有比如,软件里存在一个定时发送email的服务,单机部署,那么接收方最多收到一份email。当多机集群部署时,如果不去额外限制,接收方应当接收到多个email。

问题是这个额外的逻辑限制应当怎么样去设计呢?

解决方案当然不止一种。

Via a shared database

第一种你可以利用数据库,建立job表。

找出需要执行的job,然后去执行它,大致逻辑类似如此。

SELECT *
FROM jobs
WHERE state = 'NotRun'
ORDER BY run_time ASC
UPDATE jobs
SET state = 'Running'
WHERE job_id = :id
AND state = 'NotRun'

Via a cluster singleton

借助集群单例即可。

我们来看看akka-cluster中对cluster singleton的描述。

For some use cases it is convenient and sometimes also mandatory to ensure that you have exactly one actor of a certain type running somewhere in the cluster.

我们知道akka的架构是树状层级结构。就是说每一个节点都对应着一个path。当akka.actor.provider为LocalProvider是,ActorPath是从/user/somePath开始。当集群时,也就是akka.actor.provider为ClusterProvider或者RemoteProvider时,ActorPath是由akka.tcp://systemName@hots:port/user/somePath组成。

代码解析:

system.actorOf(
ClusterSingletonManager.props(
singletonProps = Props(classOf[Consumer], queue, testActor),
terminationMessage = End,
settings = ClusterSingletonManagerSettings(system).withRole("worker")),
name = "consumer")
val proxy = system.actorOf(
ClusterSingletonProxy.props(
singletonManagerPath = "/user/consumer",
settings = ClusterSingletonProxySettings(system).withRole("worker")),
name = "consumerProxy")

上述代码分为两步骤。第一步是创建一个集群单例对象,第二步创建单例对象的代理对象。

那么为何需要这样设计呢?代理对象是逻辑地址,第一步创建的是单例的实际地址。

以下代码利用单例实现只执行一次的语义。

class OnlyExecuteOnce[A](exe: () => A) extends Actor {
override def preStart(): Unit =
exe() override def receive: Receive = {
case _ => ()
}
} object OnlyExecuteOnce {
// /user/onlyExecuteOnce1234
// /user/onlyExecuteOnce1234Proxy
def apply[A](id: String)(exe: () => A)(implicit system: ActorSystem) = {
system.actorOf(
ClusterSingletonManager.props(Props(classOf[OnlyExecuteOnce[A]], exe), PoisonPill, ClusterSingletonManagerSettings(system)),
name = s"onlyExecuteOnce${id}")
system.actorOf(ClusterSingletonProxy.props(s"/user/onlyExecuteOnce${id}", ClusterSingletonProxySettings(system)),
name = s"onlyExecuteOnce${id}Proxy")
}
}

参数id用于构建单例对象的path。

Run a task only once in (akka) cluster的更多相关文章

  1. akka cluster sharding source code 学习 (1/5) 替身模式

    为了使一个项目支持集群,自己学习使用了 akka cluster 并在项目中实施了,从此,生活就变得有些痛苦.再配上 apache 做反向代理和负载均衡,debug 起来不要太酸爽.直到现在,我还对 ...

  2. Task.Run Vs Task.Factory.StartNew

    在.Net 4中,Task.Factory.StartNew是启动一个新Task的首选方法.它有很多重载方法,使它在具体使用当中可以非常灵活,通过设置可选参数,可以传递任意状态,取消任务继续执行,甚至 ...

  3. Task.Run Vs Task.Factory.StartNew z

    在.Net 4中,Task.Factory.StartNew是启动一个新Task的首选方法.它有很多重载方法,使它在具体使用当中可以非常灵活,通过设置可选参数,可以传递任意状态,取消任务继续执行,甚至 ...

  4. .Net4.0如何实现.NET4.5中的Task.Run及Task.Delay方法

    前言 .NET4.0下是没有Task.Run及Task.Delay方法的,而.NET4.5已经实现,对于还在使用.NET4.0的同学来说,如何在.NET4.0下实现这两个方法呢? 在.NET4.0下, ...

  5. Akka Cluster简介与基本环境搭建

      akka集群是高容错.去中心化.不存在单点故障以及不存在单点瓶颈的集群.它使用gossip协议通信以及具备故障自动检测功能. Gossip收敛   集群中每一个节点被其他节点监督(默认的最大数量为 ...

  6. Task.Run与Task.Factory.StartNew的区别

    Task是可能有延迟的工作单元,目的是生成一个结果值,或产生想要的效果.任务和线程的区别是:任务代表需要执行的作业,而线程代表做这个作业的工作者. 在.Net 4中,Task.Factory.Star ...

  7. C# Task.Run 和 Task.Factory.StartNew 区别

    Task.Run 是在 dotnet framework 4.5 之后才可以使用,但是 Task.Factory.StartNew 可以使用比 Task.Run 更多的参数,可以做到更多的定制.可以认 ...

  8. Task.Run Vs Task.Factory.StartNew 【收藏】

    在.Net 4中,Task.Factory.StartNew是启动一个新Task的首选方法.它有很多重载方法,使它在具体使用当中可以非常灵活,通过设置可选参数,可以传递任意状态,取消任务继续执行,甚至 ...

  9. akka cluster 初体验

    cluster 配置 akka { actor { provider = "akka.cluster.ClusterActorRefProvider" } remote { log ...

随机推荐

  1. android 开源收藏

    第一部分 个性化控件(View) 主要介绍那些不错个性化的View,包括ListView.ActionBar.Menu.ViewPager.Gallery.GridView.ImageView.Pro ...

  2. Flash真的老了,HTML5将取代其地位

    简单讲一些网页开发的趋势吧! Flash老了 Flash是一个落后于时代的技术,靠对客户端的高资源占用率来获取传输过程的低带宽占用. Flash不再安全 Flash是一个落后于时代的技术,靠对客户端的 ...

  3. python学习笔记 tuple

    1. ()去声明.与list类似,但是其元素不能改变. 2. 需要注意的是1中的不能改变是指()中的元素不能改变,如果其元素是一个list,那么list中的元素是可以改变的,不论是大小还是其他的. 3 ...

  4. GacUtil

    编辑本段工具简介 全局程序集缓存工具 (Gacutil.exe) 管理程序集缓存的 .NET 实用工具库还提供一种命令行接口工具,名为全局程序集缓存实用工具 (Gacutil.exe). 编辑本段命令 ...

  5. react入门到进阶(二)

    一.react属性与事件 1.State属性 State,翻译过来是状态的意思,所以它就代表着组件的状态.React把用户界面(UI)当做是状态机,想象它有不同的状态然后渲染这些状态,可以轻松让用户界 ...

  6. 2715:谁拿了最多奖学金-poj

    总时间限制:  1000ms 内存限制:  65536kB 描述 某校的惯例是在每学期的期末考试之后发放奖学金.发放的奖学金共有五种,获取的条件各自不同: 1) 院士奖学金,每人8000元,期末平均成 ...

  7. #centos7 设置bond、bridge、vlan

    #centos7 设置bond.bridge.vlan #centos7 设置bond.bridge.vlan # CentOS7中 nmcli命令由NetworkManager提供 # 可以用于设置 ...

  8. IntelliJ IDEA(一) :安装

    前言 我是从eclipse转IDEA的,对于习惯了eclipse快捷键的我来说,转IDEA开始很不习惯,IDEA快捷键多,组合多,记不住,虽然可以设置使用eclipse的快捷键,但是总感觉怪怪的.开始 ...

  9. ACM HDU Bone Collector 01背包

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2602 这是做的第一道01背包的题目.题目的大意是有n个物品,体积为v的背包.不断的放入物品,当然物品有 ...

  10. iOS 处理socket粘包问题

    1.什么是粘包? 粘包通常出现在TCP的协议里面,对于UDP来说是不会出现粘包状况的,之所以出现这种状况的原因,涉及到一种名为Nagle的算法. Nagle算法通过减少必须发送的封包的数量,提高网络应 ...