在我们的系统中,我们有多个数据生成器在共享文件系统中创建文件内容,并在文件名中指示DataSourceId
。需要有一个公平的调度机制来读取所有源生成的文件,解析,展平和放大。丰富(使用参考数据)文件中的数据记录,批量化丰富的记录并写入数据库。
我使用IPartitionedTridentSpout
。拓扑看起来像这样:
TransactionalTridentEsrSpout spout
= new TransactionalTridentEsrSpout(NUM_OF_PARTITIONS);
TridentTopology topology = new TridentTopology();
topology.newStream("FileHandlerSpout", spout)
.each(new Fields("filename", "esr"), new Utils.PrintFilter())
.parallelismHint(NUM_OF_PARTITIONS)
.shuffle()
.each(new Fields("filename", "record"), new RecordFlattenerAndEnricher(), new elds("record-enriched"))
.each(new Fields("filename", "record-enriched"), new Utils.PrintFilter())
.project(new Fields(record-enriched")) // pass only required
.parallelismHint(PARALLELISM_HINT_FOR_ESR_FLATTENER_ENRICHER)
.shuffle()
.aggregate(new Fields("record-enriched"), new BlockWriterToDb(), new Fields("something"))
.each(new Fields("something"), new Utils.PrintFilter())
.parallelismHint(PARALLELISM_HINT_FOR_GP_WRITER);
由于数据文件非常大(通常是100万条记录),我会阅读小批量的10K记录。对于transactionId
生成的每个Coordinator
,我的Emitter
会在其分区中发出当前/下一个文件的下一个10K记录。最后的BlockWriter
会将丰富的记录聚合到缓冲区中,并在“完整”方法调用中将缓冲区写入DB。
拓扑工作正常,但我有以下问题:
parallelismHint
的{{1}}影响ParttionedTridentSpout
的数量,设置为分区数。接下来的两个图层Emitters
(parallelismHint
和FlattenerAndEnricher
)需要设置为更高的值,因为我们还有很多工作要做。由于此处不需要BlockWriterToDb
,因此我在此处的所有阶段之间使用groupBy
。当特定的下游螺栓死亡时,Trident应该使用适当的旧元数据调用shuffle()
,要求它重新发射。但是,由于发生了混乱,作为一个Emitter
的一部分发射的特定记录将落在多个下游螺栓中。那么,Trident如何调用适当的发射器进行重新发射,以便重新发射完全相同的记录。即使Trident调用适当的发射器,Emitter
也会重新发出整个10K批次,其中一些记录只是失败了。这整个序列是如何由Storm处理的,我们如何在这里设计应用程序逻辑来处理完全一次语义的容错。
答案 0 :(得分:0)
使用Trident时,整个批次成功,或整个批次失败。 当批次失败时,喷口应该(自动)重放整个批次,并且您将无法在发出时选择其记录。
要获得完全一次的语义,您的下游逻辑/数据库更新应该忽略重放的项目(跟踪成功更新的项目的批次ID),或者是幂等的。