同样,是否有应该避免的设计模式?

有帮助吗?

解决方案

我假设你正在编写一个服务器类型的应用程序(让我们离开Web应用程序一段时间 - 有一些现成的解决方案可以帮助那些,所以让我们看看“我有这个伟大的新类型服务器我写了“,但我希望它是HA问题。”

在服务器实现中,来自客户端的请求通常(以某种形式或另一种形式)转换为某种事件或命令类型模式,然后在一个或多个队列上执行。

所以,第一个问题 - 需要以一种在集群中存活的方式存储事件/命令(即,当一个新节点作为主节点接管时,它会查看下一个需要执行并开始的命令)。 p>

让我们从一个单线程服务器impl开始(最简单 - 并且概念仍然适用于多线程但它有自己的一组问题.0。当处理命令时需要某种事务处理。

另一个问题是管理副作用以及如何处理当前命令的失败?在可能的情况下,以交易方式处理副作用,以便它们全部或全部。即。如果命令改变状态变量,但在执行中途崩溃,则能够返回到“先前”状态变量。国家很棒。这允许新的主节点恢复崩溃的命令并重新运行该命令。一个好方法是将副作用分解为可以再次在任何节点上运行的较小任务。即。存储主要请求的开始和结束任务,许多小任务处理每个任务只有一个副作用。

这也会引入其他会影响您设计的问题。这些状态变量不一定是数据库更新。它们可以是共享状态(比如内部组件的有限状态机),也需要在集群中分布。因此,管理更改的模式使得主代码必须看到所需状态的一致版本,然后在整个集群中提交该状态。使用某种形式的不可变(至少来自主线程进行更新)数据存储是有用的。即。所有更新都是在必须通过某种中介或外观的新副本上有效完成的,这些中介只在集群中更新后更新本地内存副本中的更新(或跨集群的最小成员数以保证数据的一致性)。 / p>

其中一些问题也存在于主工作者系统中。

还需要良好的错误管理,因为状态更新可能出错的事情数量增加(因为您现在涉及网络)。

我经常使用状态模式。对于您想要发送请求/响应的副作用,并使用会话特定的fsm来跟踪进度,而不是一行更新。

另一个问题是终点的表示。即。连接到主节点的客户端需要能够重新连接到新主节点,然后监听结果吗?或者您只是取消所有待处理结果并让客户重新提交?如果允许处理挂起的请求,则需要一种识别端点(客户端)的好方法(即查找中的某种客户端ID)。

还需要清理代码等(即不希望数据等待客户端重新连接以永远等待)。

使用了大量队列。因此,很多人会使用一些消息总线(jms说为java)以事务方式推送事件。

Terracotta(再次为java)为你解决了很多这个 - 只需更新内存 - 兵马俑是你的门面/调解员。他们只是为你注入方面。

Terracotta(我不为他们工作) - 引入了“超静态”的概念,因此您可以获得这些很酷的群集单例,但您只需要知道这将如何影响测试和开发工作流程 - 即。使用大量的组合,而不是继承

其他提示

创建可靠软件的一种方法是仅崩溃软件

  

仅限崩溃的软件是安全崩溃并快速恢复的软件。阻止它的唯一方法是崩溃它,启动它的唯一方法是恢复。仅崩溃系统由仅与崩溃的组件组成,这些组件与可重试的请求通信;通过崩溃并重新启动故障组件并重试任何超时的请求来处理故障。由此产生的系统通常更加强大和可靠,因为崩溃恢复在开发过程中是一流的公民,而不是事后的想法,并且您不再需要额外的代码(以及相关的接口和错误)来进行显式关闭。所有软件都应该能够安全地崩溃并快速恢复,但只有崩溃的软件必须具备这些特性,否则它们的缺乏就会很快显现出来。

我建议您阅读Michael的发布!尼加德。他概述了许多影响生产系统的反模式,以及帮助防止一个错误组件占用整个系统的模式。该书涵盖三个主要领域;稳定性,容量和一般设计(涵盖网络,安全性,可用性和管理)。

我之前的工作场所被各种各样的失败情景Nygard概述(每次造成停电的收入损失)被咬(在某个时间)。实现他建议的一些技术和模式导致了更加稳定和可预测的系统(是的,这本书有点以Java为中心,但这些原则适用于许多情况)。

错误的:

...并且将会有一个存储服务器

好的:

...并且将有一个(多个)存储的农场 前面有(多个)负载平衡器的服务器 其中

  • 将负载均衡器放在一切的前面。目前您可以有 4 个后端,但将来您可以有 400 个后端,因此明智的做法是仅在 LB 上管理它,而不是所有使用后端的应用程序。

  • 使用多级缓存。

  • 寻找流行的加速解决方案(例如 memcached)。

  • 如果您要更新系统,请分多个小步骤逐步进行。如果你迈出一大步(关闭旧的,打开新的并祈祷它能起作用),它很可能会失败。

  • 使用 DNS 名称来命名,例如 storage-lb.servicename 解析为所有存储负载均衡器的地址。如果您想添加一个,只需修改 dns,所有服务都会自动开始使用它。

  • 把事情简单化。您依赖的系统越多,您的服务受到的影响就越大。

设计高可用性(HA)系统是一个活跃的研究和开发领域。如果你看一下ACM或IEEE,有很多关于服务质量(可用性,可靠性,可扩展性等)以及如何实现它们的研究论文(松散耦合,适应等)。如果您正在寻找更多实际应用程序,请查看容错系统和中间件,这些系统和中间件是为了实现群集,网格或云功能而构建的。

复制和负载平衡(也称为反向代理)是实现HA系统的一些最常见的模式,并且通常可以在不对底层软件进行代码更改的情况下完成,假设它没有太紧密耦合。即使很多最近的云产品基本上都是通过复制和负载平衡来实现的,尽管它们倾向于建立弹性以处理广泛的系统需求。

使软件组件无状态减轻了复制的负担,因为状态本身不需要与软件组件一起复制。无状态是HTTP扩展如此之好的主要原因之一,但它通常要求应用程序添加自己的状态(例如会话),然后需要复制。

因此,松耦合系统比紧耦合系统更容易实现。由于系统组件的可靠性决定了整个系统的可靠性,因此可能需要更换不可靠的组件(硬件故障,软件错误等)。允许在运行时进行动态调整可以在不影响整个系统可用性的情况下更换这些故障组件。松散耦合是使用可靠消息系统的另一个原因,其中发送方和接收方不必同时可用,但系统本身仍然可用。

据我所知,您正在寻找在HA架构的Java应用程序中使用的特定模式。当然,可以使用许多模式和最佳实践,但这些并不是真正的“HA模式”。相反,它们是可以在manys环境中使用的好主意。

我想我想说的是:高可用性架构由许多小部件组成。如果我们选择其中一个小部件并检查它们,我们可能会发现这个小部件没有神奇的HA属性。如果我们检查所有其他组件,我们会发现相同的事情。当它们以智能方式组合成为HA应用程序时。

HA应用程序是一个从一开始就计划最坏的应用程序。如果你曾经想过“这个组件是如此稳定,以至于我们不需要额外的冗余”。它可能不是HA架构。毕竟,很容易处理您预见的问题场景。这是让你惊喜的一个系统。

尽管如此,有些模式在HA上下文中特别有用。其中许多都记录在Martin Fowler的经典着作“模式的企业应用程序架构”中。 / p>

我正在解释“ 高可用性 ”作为“ 零停机时间 ”,可根据其他SE问题实施:

Java应用程序的零停机时间部署

  1. A / B开关:(滚动升级+后退机制)
  2. 并行部署– Apache Tomcat :(仅适用于Web应用程序)
  3. 延迟端口绑定
  4. 高级端口绑定
  5. 我将使用其中一些概念从软件角度为高可用性系统提出设计模式,这与上述方法相辅相成。

    使用的模式:

    代理 / 工厂

    让代理对象和代理将决定重定向请求的位置。假设你有版本1&软件版本2。如果客户端使用旧协议进行连接,请将它们重定向到版本1软件。新客户端可以直接连接到版本2。代理可以使用Factory方法或AbstractFactory来呈现新版本的软件。

    策略

    您可以通过从一系列算法中选择一种算法来在运行时更改算法。如果以航空公司为例,您可以在非峰值和峰值流量月份之间切换DiscountFare和NormalFare算法。

    装饰者

    您可以在运行时更改对象的行为。添加一个新类并装饰其他责任。

    适配器

    在版本1和版本2之间更改接口或合同时很有用。适配器将响应旧版本和版本2。新客户请求得当。

    一般准则:

    1. 对象之间的松散耦合
    2. 在您的申请中遵循 S.O.L.I.D 原则
    3. 有关上述模式,请参阅 sourcemaking 网站文章,以便更好地理解。

      不使用的内容:

      除了设计模式之外,您还必须采取一些预防措施,以实现应用程序的零停机时间。

      1. 不要在系统中引入单点故障。
      2. 谨慎使用分布式缓存(例如Terracotta)/锁定。
      3. 删除服务之间的硬耦合。使用消息传递总线/框架(JMS,ActiveMQ等)
      4. 删除服务之间的紧密耦合

高可用性更多地是关于硬件可用性和冗余,而不是编码约定。我会在几乎所有HA案例中使用几种模式:我会为我的数据库对象选择单例模式,并使用工厂模式来创建单例。然后,工厂可以使用逻辑来处理数据库的可用性问题(这是大多数可用性问题发生的地方)。例如,如果Master关闭,则连接到第二个Master进行读取和写入,直到Master返回。我不知道这些是最具杠杆作用的模式,但它们是我代码中利用率最高的模式。

当然这个逻辑可以在__construct方法中处理,但工厂模式将允许您更好地控制代码以及如何处理数据库连接问题的决策逻辑。工厂还可以让您更好地处理单例模式。

我绝对会避免装饰器模式观察者模式。它们都会在代码中产生复杂性,使其难以维护。他们的情况是这些是满足您需求的最佳选择,但大多数时候他们不是。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top