同样,应该避免设计模式吗?
我假设你正在编写一个服务器类型的应用程序(让我们离开Web应用程序一段时间 - 有一些现成的解决方案可以帮助那些,所以让我们看看"我有这个伟大的新型服务器,我写了",但我希望它是HA问题).
在服务器实现中,来自客户端的请求通常(以某种形式或另一种形式)转换为某种事件或命令类型模式,然后在一个或多个队列上执行.
所以,第一个问题 - 需要以在集群中存活的方式存储事件/命令(即,当新节点接管为主节点时,它会查看需要执行并开始的下一个命令).
让我们从单线程服务器impl开始(最简单的 - 并且概念仍然适用于多线程,但它有自己的一组问题.0.当处理命令时需要某种事务处理.
另一个问题是管理副作用以及如何处理当前命令的失败?在可能的情况下,以交易方式处理副作用,以便它们全部或全部.即.如果命令改变状态变量,但在执行中途崩溃,则能够返回到"先前"状态是很好的.这允许新的主节点恢复崩溃的命令并重新运行该命令.一个好方法是将副作用分解为可以再次在任何节点上运行的较小任务.即.存储主要请求的开始和结束任务,许多小任务处理说每个任务只有一个副作用.
这也会引入其他会影响您设计的问题.这些状态变量不一定是数据库更新.它们可以是共享状态(比如内部组件的有限状态机),也需要在集群中分布.因此,管理更改的模式使得主代码必须看到所需状态的一致版本,然后在整个集群中提交该状态.使用某种形式的不可变(至少来自主线程进行更新)数据存储是有用的.即.所有更新都是在必须通过某种中介或外观的新副本上有效完成的,这些中介只在集群中更新后更新本地内存副本中的更新(或者跨集群的最小成员数以保证数据的一致性).
其中一些问题也存在于主工作者系统中.
还需要良好的错误管理,因为状态更新可能出错的事情数量增加(因为您现在涉及网络).
我经常使用状态模式.您想要发送请求/响应的副作用,而不是一行更新,并使用特定于会话的fsm来跟踪进度.
另一个问题是终点的表示.即.连接到主节点的客户端需要能够重新连接到新主节点,然后监听结果吗?或者您只是取消所有待处理结果并让客户重新提交?如果允许处理挂起的请求,则需要一种识别端点(客户端)的好方法(即查找中的某种客户端ID).
还需要清理代码等(即不希望数据等待客户端重新连接以永远等待).
使用了大量队列.因此,很多人会使用一些消息总线(jms说java)以事务方式推送事件.
Terracotta(再次为java)为你解决了很多这个 - 只需更新内存 - 兵马俑是你的门面/调解员.他们刚刚为你注入方面.
Terracotta(我不为他们工作) - 引入了"超静态"的概念,因此你可以获得很酷的集群范围的单例,但你只需要知道这将如何影响测试和开发工作流程 - 即.使用大量的组合,而不是继承具体的实现以实现良好的重用.
对于Web应用程序 - 一个好的应用程序服务器可以帮助进行会话变量复制和良好的负载均衡器.在某种程度上,通过REST(或您选择的Web服务方法)使用它是一种编写多线程服务的简单方法.但它会产生性能影响.再次取决于您的问题域.
消息服务(比如jms)通常用于引入不同服务之间的松散耦合.有了一个像样的消息服务器,你可以做很多msg路由(再次apache camel或类似的做得很好)即.说一个粘性消费者对一群jms生产者等也可以允许良好的故障转移.Jms队列等可以提供一种在集群中分配cmd的简单方法,主/从.(这又取决于你是在做LOB还是从头开始编写服务器/产品).
(如果我以后会有时间整理,可能会在修复拼写语法中加入更多细节等)
创建可靠软件的一种方法是仅崩溃软件:
仅崩溃软件是安全崩溃并快速恢复的软件.阻止它的唯一方法是崩溃它,启动它的唯一方法是恢复.仅崩溃系统由仅与崩溃的组件组成,这些组件与可重试的请求通信; 通过崩溃并重新启动故障组件并重试任何超时的请求来处理故障.由此产生的系统通常更加强大和可靠,因为崩溃恢复在开发过程中是一流的公民,而不是事后的想法,并且您不再需要额外的代码(以及相关的接口和错误)来进行显式关闭.所有软件都应该能够安全地崩溃并快速恢复,但是只有崩溃的软件必须具备这些特性,否则它们的缺乏就会变得非常明显.