高吞吐量事务处理策略

时间:2011-11-09 00:21:15

标签: java performance transactions

我的系统对其所做的事情有严格的“一次且一次”要求。它是一个带有中间件的事件驱动系统,它不能保证只发送一次消息(如果对这是否是重新发送有疑问,它会将任何给定消息标记为“重新发送”)。 “一次且仅一次”处理基本上归结为我们的核心域对象的状态,即它是一个相当标准的设置,即....

  1. 消息到达
  2. 执行业务逻辑
  3. 州更新
  4. 生成输出并发送到下游系统
  5. 3必须最终打到一个数据库(书籍和记录),4可以采取各种形式,但都是对外部系统的某种消息。还有其他各种流程,但它们都归结为这种处理方式。所有消息都将在核心域对象的单个实例上运行,因此处理可以将该实例固定到单个jvm。

    我的Q很通用,可能太笼统但我还是会问。即,在保持所需保证的同时,可以采用哪些策略/模式来提高吞吐量?或者,会破坏性能的主要问题是什么?

    例如,一种思路就是避免在关键路径中存在任何持久性,这一问题归结为如何保持内存状态的一致性而无需从数据库刷新。

    您可以假设可以通过某种分区策略进行扩展,但该方面超出了q的范围。 Q是关于如何在这样的系统中扩大单个节点的吞吐量。

    请注意,这是一个大型企业设置中的java / oracle,因此小众硬件(例如exadata和朋友或某些花哨的网络套件)都可以。

3 个答案:

答案 0 :(得分:2)

很大程度上取决于您在如何处理故障方面需要什么保证。使用平面日志文件和/或冗余服务器来实现持久性,您可以实现每秒超过一百万的消息传递速率。

您需要的主要模式是演员模式。要提高吞吐量,您需要能够透明地批量处理数据,作为设计的一部分。我个人喜欢使用直接ByteBuffers(大多数数据不在堆上),因为它们是处理大量数据的轻量级方法,可以轻松地复制和读取/写入NIO通道。我为gc-less输入/输出编写了自己的解析/日志记录库。

另一个有用的策略是预分配和回收对象。这可以通过不产生垃圾(或仅创建可以每天收集一次的非常少量)来帮助消除GC的风险。

技巧不是在满足持久性保证之前发布处理结果。 (最简单的方法是没有任何保证,并说最后几笔交易可能会丢失并将手动处理)

可以扼杀性能的主要因素是

  • IO,您希望这是异步的。
  • 过度锁定
  • 创建大量对象将导致缓存效率低下(因为新对象有效地滚动出有用数据)循环对象可以保留在缓存中。
  • GC会伤害您最坏的情况延迟。如果你只关心吞吐量,这没关系。
  • 确保您预热代码。默认情况下,您需要在短时间内执行10,000次方法调用(或者有一个迭代这么多次的循环)以触发它进行编译。如果您具有低延迟但不是高吞吐量系统,则可能无法编译大部分关键代码。
  • 确保您使用合适的硬件并拥有最新版本的Java。较旧的机器和旧版本的Java可能会慢得多。

答案 1 :(得分:1)

  • 可以采用哪些策略/模式来提高吞吐量,同时保持所需的保证?

不确定我是否可以轻松地将此问题与您提到的"once and only once" requirements相关联,但无论如何我都会试一试。

事件驱动/非阻止方法,我认为在messages arrive评判的流程中已经“有点”了。想象一下自包含/不可变组件能够接收消息并根据消息的类型/有效负载做出反应,让我们暂时调用这些组件actors。然后你的流程就会变成:

消息到达

演员

执行业务逻辑

在与该消息的类型

对应/匹配的无状态method

状态已更新

state可以是平面文件/ RDBMS / NoSQL /内存,仅取决于您的架构=>这是由业务驱动的。

因此,相同的method可以调用store.update()或者只是向StatusActor发送另一条消息(例如UpdateStatus),因此我们不会锁定/阻止[这取决于“update => ; generate =>发送下游“需要是原子的还是非原子的”

生成

输出并将其发送到下游系统

现在,actor向另一个生成输出的actor发送另一条消息(例如GenerateOutput),并向另一个actor发送另一条消息(例如SendDownstream)。

  • 或者,会破坏性能的主要问题是什么?

阻止/锁定和......过早优化

答案 2 :(得分:0)

这是“相当”容易,“只是”使您的操作具有幂等性并且可以完成所有操作。