在大数据领域,实时写入(upsert)和快速OLAP查询一直是鱼和熊掌不能兼得,比如apache hudi,要事先决定好是倾向于快速写入还是快速OLAP查询,即Copy On Write Table vs. Merge On Read Table一旦选定好,就不能更改。databricks的delta-io也是类似的实现。而现实往往是希望在近乎实时upsert的同时,能快速的查询,至少是接近列存数据库的查询速度。正是这个需要,cloudera于2015年推出了apache kudu。这是一个支持schema的非K-V存储引擎,不依赖HDFS,内存是行存,flush到硬盘是列存,c++11实现,同时提供java/scala/python API,兼容Spark生态。弥补了大数据实时领域缺失的一环。
本文实现一个demo,通过往kafka实时发送股票变化的event,模拟实时写入数据流。通过spark streaming消费kafka数据流,将数据实时写入kudu表,实现数据的入库。再用一个简单的jsp页面调用后端的spark SQL定时查询kudu表结果,展示一个近实时监控平台。由于牵涉多个apache开源项目,为了测试方便,都用docker或本地形式部署。最后可以通过browser查看结果,如下图所示。
实现步骤
生成kafka模拟数据
一个死循环,不停的往指定的kafka topic上写record,数据格式完全自己定义,用'\001'分割的key-value对。代码框架和主要数据结构如下:
// loop to generate data
while(true) {
while (openOrders.size() < 100) {
Order newOrder = new Order();
String newOrderSingleFIX = newOrder.newOrderSingleFIX();
producer.send(new ProducerRecord<String, String>(kafkaTopic, newOrderSingleFIX));
openOrders.add(newOrder);
}
for (Order order : openOrders) {
if (!order.isComplete()) {
if (order.hasFurtherExecuted()) {
Thread.sleep(1);
String executionReportFIX = order.nextExecutionReportFIX();
producer.send(new ProducerRecord<String, String>(kafkaTopic, executionReportFIX));
}