使用Apache Kafka和MongoDB进行时间序列数据流处理
有一件事是全世界都同意的,那就是时间的概念。许多应用都是基于时间的。考虑一下太阳能场发电、股票交易和健康监测。这些只是产生和使用包含关键时间成分的数据的大量应用中的几个。一般来说,时间序列数据应用重在插入,很少执行更新,更不可能删除数据。这些应用产生了巨大的数据量,需要一个强大的数据平台来有效地管理和查询数据。使用MongoDB,你可以轻松地:
-
使用MongoDB查询语言和窗口函数对数据进行预先汇总
-
用MongoDB时间序列集合优化存储大量的时间序列数据
-
使用MongoDB Atlas Online Archive将数据归档到具有成本效益的存储中
由于Apache Kafka的可扩展性,它经常被用作数据的摄入点。通过使用MongoDB Connector for Apache Kafka和Apache Kafka Connect服务,很容易在Kafka主题和MongoDB集群之间传输数据。从MongoDB Connector for Apache Kafka的1.6版本开始,你可以配置kafka主题数据直接写入MongoDB的时间序列集合。这种配置发生在汇中。
在水槽中配置时间序列集合
使用MongoDB,应用程序不需要在开始写入数据之前创建数据库和集合。这些对象会在数据首次到达MongoDB时自动创建。然而,在开始写入数据之前,需要先创建一个时间序列集合类型。为了方便从Kafka将时间序列数据摄入MongoDB,这些集合选项被暴露为sink参数,如果时间序列集合还不存在,则由连接器创建。一些新的参数被定义如下。
timeseries.timefield用于时间的顶层字段的名称。
timeseries.expire.after.seconds这个可选的字段决定了数据在被自动删除之前在MongoDB中的时间量。省略此字段意味着数据将不会被自动删除。如果你熟悉MongoDB中的TTL索引,设置这个字段可以提供一个类似的行为。
timeseries.timefield.auto.convert这个可选的字段告诉连接器将字段中的数据转换成BSON Date格式。支持的格式包括整数、长和字符串。
有关新的时间序列参数的完整列表,请查看MongoDB Sink连接器的在线文档。当数据存储在时间序列集合中时,MongoDB在幕后优化了数据的存储和桶化。与普通集合中典型的每个数据点一个文档的数据结构相比,这节省了大量的存储空间。你还可以探索MongoDB查询语言中许多新的时间和窗口功能。例如,考虑这个样本文档结构:
{
tx_time: 2021-06-30T15:47:31.000Z,
_id: '60dc921372f0f39e2cd6cba5',
company_name: 'SILKY CORNERSTONE LLC',
price: 94.0999984741211,
company_symbol: 'SCL'
}
你可以使用新的$setWindowFields pipeline来定义文档的窗口来执行操作,然后执行排名、累积总数和其他复杂时间序列数据的分析。例如,使用教程中生成的数据,让我们对数据确定滚动平均数,如下所示:
db.StockDataTS.aggregate(
[
{
$match: {company_symbol: 'SCL'}
},
{
$setWindowFields:
{
partitionBy: '$company_name',
sortBy: { 'tx_time': 1 },
output:
{
averagePrice:
{
$avg: "$price",
window:
{
Documents:
[ "unbounded", "current" ]
}
}
}
}
}
])
结果集的一个样本如下:
{
tx_time: 2021-06-30T15:47:45.000Z,
_id: '60dc922172f0f39e2cd6cbeb',
company_name: 'SILKY CORNERSTONE LLC',
price: 94.06999969482422,
company_symbol: 'SCL',
averagePrice: 94.1346669514974
},
{
tx_time: 2021-06-30T15:47:47.000Z,
_id: '60dc922372f0f39e2cd6cbf0',
company_name: 'SILKY CORNERSTONE LLC',
price: 94.1500015258789,
company_symbol: 'SCL',
averagePrice: 94.13562536239624
},
{
tx_time: 2021-06-30T15:47:48.000Z,
_id: '60dc922472f0f39e2cd6cbf5',
company_name: 'SILKY CORNERSTONE LLC',
price: 94.0999984741211,
company_symbol: 'SCL',
averagePrice: 94.13352966308594
}
注意额外的 "averagePrice "字段现在是用滚动平均数填充的。关于MongoDB中时间序列集合的更多信息,请查看在线文档。
迁移现有的集合
要将现有的MongoDB集合转换为时间序列集合,你可以使用MongoDB Connector for Apache Kafka。只需将源连接配置到你现有的集合,并通过使用 "timeseries.timefield "参数将汇连接器配置为写到MongoDB时间序列集合。你可以通过将 "copy.existing "参数设置为 "true "来配置源连接器以复制现有数据。这将为源中的所有现有文档创建插入事件。任何在复制过程中被插入的文档都将在复制过程结束后被插入。虽然并不总是可能,但建议在复制过程中暂停对源数据的写入。要看它何时完成,你可以查看日志中的消息,"完成了从集合中复制现有数据"。
例如,考虑一个具有这种结构的源文件:
{
company_symbol: (STRING),
company_name: (STRING),
price: (DECIMAL),
tx_time: (STRING)
}
对于MongoDB时间序列集合的初始版本,代表时间的字段需要被存储为Date。在我们的例子中,我们使用一个字符串来展示连接器自动从字符串转换为日期的能力。如果你选择在连接器之外执行转换,你可以在Kafka Connect中使用单一消息转换,在Sink将字符串转换为日期。然而,某些SMT(如Timestampconverter)需要为Kafka主题中的数据定义模式,以便工作。这可能会给配置增加一些复杂性。你可以使用新的timeseries.timefield.auto.convert和timeseries.timefield.auto.convert.date.format选项自动转换为Dates,而不是使用SMT。
下面是一个源配置的示例,它将从StockData集合中复制所有的现有数据,然后继续推送数据变化到stockdata.Stocks.StockData主题:
{"name": "mongo-source-stockdata",
"config": {
"tasks.max":"1",
"connector.class":"com.mongodb.kafka.connect.MongoSourceConnector",
"key.converter":"org.apache.kafka.connect.storage.StringConverter",
"value.converter":"org.apache.kafka.connect.json.JsonConverter",
"publish.full.document.only": true,
"connection.uri":(MONGODB SOURCE CONNECTION STRING),
"topic.prefix":"stockdata",
"database":"Stocks",
"collection":"StockData",
"copy.existing":"true"
}}
这是一个样本配置,用于将stockdata.Stocks.StockData主题中的数据写入MongoDB的时间序列集合:
{"name": "mongo-sink-stockdata",
"config": {
"connector.class":"com.mongodb.kafka.connect.MongoSinkConnector",
"tasks.max":"1",
"topics":"stockdata.Stocks.StockData",
"connection.uri":(MONGODB SINK CONNECTION STRING),
"database":"Stocks",
"collection":"StockDataMigrate",
"key.converter":"org.apache.kafka.connect.storage.StringConverter",
"value.converter":"org.apache.kafka.connect.json.JsonConverter",
"timeseries.timefield":"tx_time",
"timeseries.timefield.auto.convert":"true",
"timeseries.timefield.auto.convert.date.format":"yyyy-MM-dd'T'HH:mm:ss'Z'"
}}
在这个水槽示例中,连接器将把 "tx_time "字段中的数据转换为Date,并将其解析为yyyy-MM-ddTHH:mm:ssZ的字符串格式(例如:'2021-07-06T12:25:45Z')
注意,在时间序列集合的初始版本中,只支持插入到时间序列集合中。在源文件上更新或删除文件将不会传播到目的地。另外,你不能在这种情况下使用MongoDB CDC处理程序,因为该处理程序使用ReplaceOne,这是一种更新命令。这些都是MongoDB中最初发布的时间序列的限制,当你看到这篇文章时,可能已经不重要了。请查看在线文档以了解最新信息。
Apache Kafka的MongoDB连接器1.6版可以从GitHub下载。本周晚些时候,在Confluent Hub上可以看到它。