事件驱动程序设计
总览
开发人员经常询问系统或其代码的性能或效率。 这到底是什么意思?
- 我的代码是如此高效,只有编码神能理解它的工作原理。
- 我的代码确实很聪明,但是却难以维护。 下一位开发人员将继续重写它。
- 我的代码对机器确实很有效,但对开发人员却没有效率。
- 我的代码很容易理解,这意味着开发人员会更高效,并且代码不仅足够快而且容易修复(如果没有的话)。
因此,与其问自己可以编写代码有多快以及可以放入多少技巧,不如问自己。 我能做得多么简单,而且仍然足够快?
简单的事件处理。
对我来说,最简单的事件处理是不返回任何内容的方法调用。 这很容易转换为异步消息传递,例如
public interface EventProcessor {void event(MyEventData data);void eventTwo(MyEventData2 data);
}
这非常简单,一个组件通过调用方法来生成事件,另一个组件通过提供实现来使用或处理该事件。
有多简单?
您可以使用一个按钮从调试器中的生产者组件升级到消费者组件。
与生产者(称为消费者)建立单元测试需要两行代码。
MyConsumer mc = new MyEventProcessor();
MyProducer mp = new MyProducer(mc);
您可以使用任何模拟工具模拟事件处理器,并检查生产者是否创建了您期望的事件。 您可以通过在单元测试中调用使用者上的方法来模拟生产者。
效果如何?
您可能会认为这几乎没有开销,一个组件只调用另一个。 但是,即使方法调用也有开销,这就是JIT支持内联的原因。 这可能意味着开销是名义上的,甚至比将这些方法一起优化时的开销要少(即,这可能比两种方法的总和要快得多)
我想念什么吗?
实际上确实有很多遗漏,但与业务需求无关;
- 运输工具。
- 监控
- 序列化
- 故障转移
- 服务发现
- 安全
这些是单独的问题,通常不是应用程序本质复杂性的一部分。
我可以使用哪种交通工具?
有很多选择,不可能知道将来所有情况下都适用。 因此,运输的选择(或缺乏运输)应为配置详细信息。 设计的唯一基本部分应该是,可以轻松更换运输装置,而不必触碰您的业务逻辑。
运输的一个例子?
低延迟,高吞吐量的解决方案是使用Chronicle Queue。 重复自己; 您只需要在合理的情况下使用它,否则就可以使用任何其他交通工具。
编年史队列做什么;
- 保留每条消息的重播功能并检查错误修复。
- 低延迟序列化,支持模式更改,并具有可读性以进行验证
- 记录和监视。
最后一点很重要。 如果您已经坚持了组件要执行的每个动作以及每个状态都发生变化,则在正常操作中不需要任何其他日志记录。 任何下游组件都可以重新创建其感兴趣的状态,而无需接触产生该信息的组件。
编年史队列如何做到这一点?
编年史队列使用两个组件;
- 实现您的界面的作家。 每个方法调用都会写入一条消息。
- 一个读取器,调用您的接口的实现。 每个消息都调用相应的方法。
注意:这种策略几乎可以用于任何运输。 编年史队列为您提供的是低延迟记录或用于重播和替换日志的所有消息。
这一切表现如何?
如果您使用诸如YAML,Binary YAML或JSON之类的灵活序列化,并且您的组件没有做太多事情,那么您可以期望获得每秒100,000条消息的吞吐量,而无需进行大量调整。 如果使用较低级别的二进制协议,短消息和多个线程,则每秒可以获得超过1000万条消息。
您可以选择免费使用所有这些GC,但这会使您的设计复杂化,因此您很可能会创建一些垃圾,但是您可以选择根据需要减少垃圾。
其他值得注意的交通工具。
Aeron是一种基于UDP的低延迟传输。
Chronicle Queue Enterprise支持通过TCP进行复制和远程访问。
Chronicle Websocket Jetty支持通过websocket访问JSON,消息速率约为100K / s
结论
您应该开始设计和测试,着重于实际需要的关键组件。 您应该允许您的设计适用于任何运输方式,并可以选择用一种替代另一种。
在单元测试和调试中,不进行传输以表明组件仍可以以最小的复杂度运行是很有用的。
我们能帮你什么吗?
Chronicle Software在现场研讨会上运行了一个星期,我们会训练/指导您的团队使用这些设计方法来构建原型系统。 解决方案的选择取决于您,因此这可能是启动新项目并进行培训的好方法,这将立即有用。 有关更多详细信息,请联系sales@chronicle.software 。
翻译自: https://www.javacodegeeks.com/2016/03/simple-event-driven-design.html
事件驱动程序设计