在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.providerLocalProvider是,ActorPath是从/user/somePath开始。当集群时,也就是akka.actor.providerClusterProvider或者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. 一个页面tab标签切换,都有scroll事件的解决办法

    当前页有多个tab,如果都有scroll事件, 先解绑$(window).off('scroll') 再执行scroll就不可以了,多个标签就不会互相干扰: 给你们个例子: //标签切换    $(' ...

  2. SpringQuartz 实现定时任务调度

    最近公司新项目需要用到定时器,于是研究了一下发现: Spring中使用Quartz有两种方式实现: 第一种是任务类继承QuartzJobBean 第二种则是在配置文件里定义任务类和要执行的方法,类和方 ...

  3. 自学python笔记(一)

    一   简介:Python是著名的"龟叔"Guido van Rossum在1989年圣诞节期间,为了打发无聊的圣诞节而编写的一个编程语言.其他的就不说了..... python是 ...

  4. iscroll遇到的两个坑

    最近移动端闪付遇到的两个坑做下总结: 1.使用iscroll后,滑动并没有生效 解决方案: 首先要查看:结构是否正确: <div id="wrapper">   //w ...

  5. Process Doppelgänging

    Process Doppelgänging -- 新的代码注入技术,通杀windows系统的所有版本,并且能绕过绝大多数的安全软件. 介绍 今天(2017-12-07),在伦敦举行的2017年黑帽欧洲 ...

  6. 自动微分方法(auto diff)

    学习机器学习的同学在学习过程中会经常遇到一个问题,那就是对目标函数进行求微分,线性回归这类简单的就不说.复杂的如神经网络类那些求导过程的酸爽.像我还是那种比较粗心的人往往有十导九错,所以说自动求导就十 ...

  7. PHP扩展安装方法

    php扩展安装方法极简单. 也遵循3大步.但多出一个phpize的步骤. 1.pecl.php.net  在右上解的输入框 中输入需要的扩展    比如 redis 2.搜索完成后会看到两个蓝色的框 ...

  8. Linux上安装 MongoDB ZK MEMCACHE PHP扩展

    安装mongo扩展: 下载地址:https://github.com/mongodb/mongo-php-driver,下载该源码包 /usr/local/php/bin/pecl install m ...

  9. C# 在RichTextBox中滚动鼠标时滚动的是父窗口的滚动条

    1. RichTextBox u2 = new RichTextBox(); 2. 先记住日RichTextBox没有显示滚动条时的总宽度和显示宽度 u2.Width - u2.ClientSize. ...

  10. 大数据:Hadoop入门

    大数据:Hadoop入门 一:什么是大数据 什么是大数据: (1.)大数据是指在一定时间内无法用常规软件对其内容进行抓取,管理和处理的数据集合,简而言之就是数据量非常大,大到无法用常规工具进行处理,如 ...