纪事本 乱码
在这一部分中,我们着眼于将组件变成服务。
在第1部分中 ,我们研究了如何轻松地创建和测试期望异步消息进入并产生异步消息的组件。 但是,我们如何将其转变为服务 ?
将我们的组件变成服务。
我们的组件缺少的关键是运输 。 缺乏传输方式简化了测试,配置和调试,但是我们需要分发组件,为此,我们需要传输方式。
有多种可能的运输方式:
- 编年史队列
- 带有Netty之类的库的原始TCP消息或UDP数据包
- JMS消息传递
- REST API [ 4 ]
- 通过JDBC的数据库表
- 将文件放入目录并使用目录WatchService
- 线程安全队列,例如BlockingQueue
- 共享内存
- 适用于可插拔传输的Apache Aries
- 完全没有传输(方法调用对于给定的用例来说很好)
这是我们将在帖子中查看的编年史队列。
在单元测试中使用队列
编年史队列已保留,但是在单元测试中,您通常希望重新启动并随后删除队列。 您可以使用的成语如下:
创建一个临时队列
File queuePath = new File(OS.TARGET, "testName-" + System.nanoTime());
try {
try (SingleChronicleQueue queue = SingleChronicleQueueBuilder.binary(queuePath).build()) {
// use the queue
}
} finally {
IOTools.shallowDeleteDirWithFiles(queuePath);
}
这将创建一个存储在单个文件中的队列。 默认情况下,该文件每天滚动,并将当前日期包括在路径中。
写作活动
如果像以前一样重复测试,则可以使用侦听器,而不是使用模拟侦听器 ,该侦听器会将调用的每个方法写入队列:
将调用方法写入任一接口的队列
OrderIdeaListener orderManager = queue.createAppender()
.methodWriter(OrderIdeaListener.class, MarketDataListener.class);
我们的组合器将写入此队列,就像我们的测试一样:
SidedPrice组合器
SidedMarketDataCombiner combiner = new SidedMarketDataCombiner((MarketDataListener) orderManager);
我们还可以重复入站事件。 将所有这些放在一起,我们得到:
try (SingleChronicleQueue queue = SingleChronicleQueueBuilder.binary(queuePath).build()) {
OrderIdeaListener orderManager = queue.createAppender().methodWriter(OrderIdeaListener.class, MarketDataListener.class);
SidedMarketDataCombiner combiner = new SidedMarketDataCombiner((MarketDataListener) orderManager);
// events in
orderManager.onOrderIdea(new OrderIdea("EURUSD", Side.Buy, 1.1180, 2e6)); // not expected to trigger
combiner.onSidedPrice(new SidedPrice("EURUSD", 123456789000L, Side.Sell, 1.1172, 2e6));
combiner.onSidedPrice(new SidedPrice("EURUSD", 123456789100L, Side.Buy, 1.1160, 2e6));
combiner.onSidedPrice(new SidedPrice("EURUSD", 123456789100L, Side.Buy, 1.1167, 2e6));
orderManager.onOrderIdea(new OrderIdea("EURUSD", Side.Buy, 1.1165, 1e6)); // expected to trigger
}
将所有事件写入队列后,就可以在测试中处理队列。 一个更现实的示例是在不同的线程,进程或不同的机器上运行这两个组件,但这只会使测试复杂化,并且如果传输能够发挥作用,结果应该是相同的。
阅读事件。
读取事件时,我们需要一个实现上述方法的组件和一个模拟侦听器,以确保触发正确的事件。
阅读所有事件并检查正确的输出
// what we expect to happen
OrderListener listener = createMock(OrderListener.class);
listener.onOrder(new Order("EURUSD", Side.Buy, 1.1167, 1_000_000));
replay(listener);
try (SingleChronicleQueue queue = SingleChronicleQueueBuilder.binary(queuePath).build()) {
// build our scenario
OrderManager orderManager = new OrderManager(listener); (1)
MethodReader reader = queue.createTailer().methodReader(orderManager); (2)
for (int i = 0; i < 5; i++)
assertTrue(reader.readOne()); (3)
assertFalse(reader.readOne()); (4)
System.out.println(queue.dump()); (5)
}
verify(listener);
我们要测试的组件
我们的队列读取器将调用方法 循环一次读取/处理一种方法。 我们没有更多消息 转储队列内容,以便我们可以看到输入内容。
最后,测试转储队列的原始内容。 这将读取队列使用的文件中存储的数据。 此转储仅对具有少量MB数据的较小队列有用。 如果您有几个GB,它将无法存储在字符串中。 您可以使用DumpQueueMain
dump()的输出
--- !!meta-data #binary
header: !SCQStore {
wireType: !WireType BINARY,
writePosition: 777,
roll: !SCQSRoll {
length: 86400000,
format: yyyyMMdd,
epoch: 0
},
indexing: !SCQSIndexing {
indexCount: !int 8192,
indexSpacing: 64,
index2Index: 0,
lastIndex: 0
}
}
# position: 227
--- !!data #binary
onOrderIdea: {
symbol: EURUSD,
side: Buy,
limitPrice: 1.118,
quantity: 2000000.0
}
# position: 306
--- !!data #binary
onTopOfBookPrice: {
symbol: EURUSD,
timestamp: 123456789000,
buyPrice: NaN,
buyQuantity: 0,
sellPrice: 1.1172,
sellQuantity: 2000000.0
}
# position: 434
--- !!data #binary
onTopOfBookPrice: {
symbol: EURUSD,
timestamp: 123456789100,
buyPrice: 1.116,
buyQuantity: 2000000.0,
sellPrice: 1.1172,
sellQuantity: 2000000.0
}
# position: 566
--- !!data #binary
onTopOfBookPrice: {
symbol: EURUSD,
timestamp: 123456789100,
buyPrice: 1.1167,
buyQuantity: 2000000.0,
sellPrice: 1.1172,
sellQuantity: 2000000.0
}
# position: 698
--- !!data #binary
onOrderIdea: {
symbol: EURUSD,
side: Buy,
limitPrice: 1.1165,
quantity: 1000000.0
}
...
# 83885299 bytes remaining
要运行测试并在我的IDE中转储队列需要233毫秒。
结论
我们可以通过使用更多的队列来测试组件是否与队列独立或成链地运行。 更重要的是,我们可以在不使基础结构使调试过程复杂化的情况下测试我们的组件。 当我们的组件在没有运输工具的情况下工作时,我们可以证明它们在运输工具的作用相同。
在下一部分
在第3部分中,我们将研究Queue的基准测试和性能分析 。 尽管Queue被设计为简单透明,但即使没有调整,它也被设计为比其他持久传输更快。
翻译自: https://www.javacodegeeks.com/2017/02/microservices-chronicle-world-part-2.html
纪事本 乱码