【问题标题】:Java daemon design practicesJava 守护进程设计实践
【发布时间】:2010-01-05 17:25:56
【问题描述】:

我正在用 Java 编写一个守护程序,它接收来自多个 provider 的请求,其中 provider 将为守护进程作为线程运行。

应用架构:

  • 主类
  • 提供者
  • 服务
  • 库/模型
  • 列表项

主类 基本上是加载配置文件,初始化所需的库等。一旦守护程序被初始化,它会循环遍历所有 providers 并初始化它们。之后,守护进程进入一个无限循环,不断地通过均匀分布的每个提供者,并尝试获取新的服务

提供者 提供者基本上是第 3 方服务的适配器。这可以是电子邮件、传真、作业队列、数据库等。初始化提供程序时,它会连接到第 3 方服务。每当应用程序从提供者那里获取一个新的 service 对象时,它会检查第 3 方服务,如果它找到一个新的请求,它会对其进行解析,然后返回一个新的 service 对象到应用程序。

服务 服务基本上是一项专门的工作。当provider 收到新请求时,它会返回与该请求相关的特定服务类型。当应用程序运行一个新的服务线程时,它会处理请求然后关闭。

这是一个示例,尽管它可能永远不会被这样使用。创建了一个新的provider,用于侦听 HTTP 端口。一个新的 HTTP 请求进来要求处理一个字符串(反转它)并将其存储在反转的数据库中。一个新的请求进来,提供者将服务返回给应用程序,应用程序启动一个新的服务,其中反转字符串并更新数据库。更新后,应用程序会看到工作已完成,并能够从另一个 provider 获取新的工作。

问题: 有没有像 MVC 这样的设计模式可以处理这样的架构?我意识到 MVC 是一个非常不好用的术语,因为它包含多种模式。我想我要问的是,我要采用的方法好吗?采用 MVC 背后的概念并将其移至此应用程序是否是一个好主意?提供者是控制器,服务是与模型相关的操作?虽然在这种类型的应用程序中从来没有任何视图。

编辑:

  • 守护进程异步处理请求者的请求。请求者永远不会收到直接响应。
  • 应用程序是分布式的,因此您可以在任意数量的服务器上运行此守护程序。每当 provider 检索到新请求时,它都会锁定该请求,以便其他守护进程不会重复该请求。 Jeff Storey 提到了可能对此有用的 JMS。我还考虑过集成 Memcache 以在提供程序处理锁定的基础上处理锁定。

谢谢

【问题讨论】:

    标签: java request daemon


    【解决方案1】:

    您所描述的内容听起来很像 enterprise integration patterns 解决的问题。

    支持这些模式的轻量级 Java 库是 Apache CamelSpring Integration,或者您可以使用完整的企业服务总线,如 ServiceMix 或 Mule。

    这是您的术​​语的粗略翻译:

    主类 - 在完整的 ESB 中,这将是 ESB 本身,即应用程序服务器。您可以自己编写,也可以使用现有的 ESB 或 OSGI 等通用应用服务器。

    提供者 - 通道适配器。

    服务 - 这些将是各种组件。有些可能是 EIP 组件,例如消息转换器以及服务激活器或其他通道适配器。

    【讨论】:

    • 我已经在使用消息传递系统 (Amazon SQS),问题是有一个主要提供商无法使用导致问题的队列。看起来通道适配器非常适合我与提供商一起做的事情。流程管理器听起来不错,尽管我在主类中使用它。服务只是由流程管理器执行的一种可运行的类型。感谢您的帮助 +1
    • Arg 这么多好答案,可惜你不能接受多个答案。我认为这实际上更适合我的问题,因为它涉及用于我想要的企业类型模式,尽管服务建议的模式似乎不是我需要的。谢谢
    • 没问题。如果有的话,企业集成模式对于建立一种通用语言很有用。不过,它可以迅速退化为建筑航天主义。轻量级集成库在以实用的方式提取它方面做得很好。
    • 另外,如果您不想处理 JMS,Spring 有提供许多这些概念的 Spring Integration 项目。
    • 我编辑了关于服务的部分,因为它不太正确。请参阅 Spring Integration 中的 Service Activators 或 Camel 中的 Bean Endpoints 以获得更好的想法。两者都需要一个“服务”注册表,通常只是 Spring ApplicationContext。
    【解决方案2】:

    根据您需要扩展的规模,您可能需要考虑 JMS 之类的消息传递服务。您的生产者和消费者(即提供者和响应者)可以发布并收听适当的 JMS 主题。

    【讨论】:

    • 在扩展方面,这个系统是高度分布式的。您可以在任意数量的服务器上启动此守护程序。每个提供程序都设置为锁定请求,因此没有其他守护程序获取它。所有提供商将只使用具有该功能的服务。尽管在某些情况下这是不可能的。我会研究 JMS,谢谢。
    • @Xepoch 谢谢。我们现在正在使用 Amazon SQS,它运行良好。问题是一些提供者(例如电子邮件)将无法添加到队列中,这个守护进程的重点是能够访问多个 3rd 方服务,只处理一次请求,并且高度分布。不确定 JMS 是否会对此有所帮助。虽然它很有用,我可能会将它用于其他用途。
    【解决方案3】:

    Web 服务器(不仅是 HTTP 类型)使用请求/响应模式。套接字侦听器等待传入的连接,使用请求工厂创建请求对象,然后将其传递给返回响应对象的处理程序(或者工厂也创建响应对象,处理程序只是修改它)。

    在 HTTP 世界中,处理程序由 URL 和 URL 参数或 POST 数据标识为请求数据。响应(通常是一些 HTML 页面)从响应对象编码并发送回浏览器。

    【讨论】:

    • 所以我在架构中要追求的概念(尽管名称提供者、服务不是很好)是我应该追求的吗?问题是这个守护进程可以有多个处理程序。该请求包含处理程序标识符以及其他数据。调用者永远不会有响应,因为它需要异步发生。感谢您的回答。
    • 是的。如果您还没有,请查看 Java 5 中的执行框架,它允许您将请求推送到作业队列并在线程中运行许多处理程序。
    • @Aaron 如果您在谈论 Java 的执行程序,我现在正在使用它来处理管理不同的线程(作业)。 “作业”是可运行的服务对象。看起来一切都像它应该的那样。看来我只需要弄清楚如何更好地分离这个系统。非常感谢 Aaron,当您确认我的想法时,我会将其设置为已接受的答案。
    【解决方案4】:

    根据我对您描述的要求的理解,我确实有一些建议。

    免责声明:我并不真正了解您的扩展要求或资源限制,如果您正在运行守护程序,这些可能很重要。一如既往,对即将提出的建议持保留态度。

    我最初的反应是,可能没有单一的设计模式可以解决您的整个问题,但有一些设计模式可能会帮助您解决问题的各个部分。

    1) 听起来您的 Main 类将轮询提供程序。您可能想做一些更多信息驱动的事情。如果/何时需要扩大规模,请查看Observer pattern 和相关的publish/subscribe pattern

    2) 您可能需要考虑为您的提供商预先分配thread pools。这可能不是绝对必要的,但可能对您的特定情况有意义。

    3) 根据您的描述,您可能正在进入architecture astronaut 领域(即在您需要之前概括所有内容)。除非您要分发 API 或有很多人在处理/重用此代码,否则我会提醒您不要发生这种行为:这是一个很大的浪费时间,而且目标如此之高令人沮丧,然后只有实现最初雄心的一小部分。

    其中一些建议可能并不直接适用于您的问题,但希望对您有所帮助。

    【讨论】:

    • 我正在使用基于服务器上 CPU 总数的预分配线程。我为我的提供者使用了与观察者模式非常相似的东西,但我可能应该完全切换到它更有条理的模式。由于 Java 的库,该守护进程相当容易构建,并且不需要花费太多时间。我的意图不是过早地扩展这个系统。感谢您的建议。 :) +1
    【解决方案5】:

    一种非 Java 特定的方法(我的意思是一种通用方法,而不是在使用 Java 时不适用的方法)是使用 Aaron Digulla 指出的简单请求/响应方法。这是一个非常常见的场景,但很容易过度设计(实际上,它的编写非常简单明了——尤其是在使用适当的支持库时)。

    如果您的用于从数据库中添加/删除整体的 Web 服务应用程序的代码行数超过 200-300 行,那么它可能是过度设计的(即使有合理的错误处理和动态配置)。

    如果您的数据库支持锁定和强制唯一性(以及事务,如果您需要这种功能),我建议您不要通过编写锁定恶魔来使事情过于复杂 - 只需让数据库处理它并处理例外。

    如果您确实需要进行锁定(例如,因为您正在写入一些外部服务,例如一些硬件),那么您可以使用典型的 UNIX 方法来锁定资源并编写一个在本地运行的单实例守护程序您的所有 Web 服务都可以与之通信的套接字 - 取决于它是否表明资源正忙,它们可以拒绝请求或将它们排队(例如,在排队系统中的内存中,在 SQL DB 中的表中,等等)使用守护进程处理排队的请求(也与锁定服务对话)。

    为了让事情变得非常简单,您始终可以始终从 Web 服务向排队系统推送请求,我建议除非您需要区分“现在正在执行此操作”和在您对提交请求的客户端的响应中“此操作已排队”。

    对于接口本身,我个人更喜欢被广泛认可为开放标准、易于实现和高度可解释的东西,比如 Document/Literal SOAP 服务,而不是像 RPC/encoded(不推荐使用和邪恶)或JMS(它是专有的,尽管在实践中得到了不同程度的广泛支持)。

    如果您正在编写一个专门的内部服务并且您是一个专门的 Java 商店,那么 JMS 非常适合,但如果它不是一个内部应用程序,最好玩得很好,不要假设其他人都只想使用 JMS 客户端与您的服务对话(我宣传 Doc/Lit SOAP,因为它可以被任何东西解析,甚至无法处理基本的 XML,并且得到了 WS-I 的认可)。

    【讨论】:

    • 感谢您的回答。这个系统并不太复杂,我首先在这里发帖的原因是我觉得我在制作系统时可能没有遵循设计模式,因为我写的太简单了。已经有一个队列系统,直接连接到守护进程永远不会发生。提供者连接到 3rd 方服务以请求新工作,他们不会直接接收它们。单实例守护进程可能是我稍后用来处理作业的地方,但目前我当前的架构还不错。
    猜你喜欢
    • 2020-08-10
    • 2010-10-09
    • 1970-01-01
    • 2010-09-24
    • 2018-03-10
    • 2011-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多