我正在尝试使用DynamoDB流和AWS提供的Java DynamoDB流Kinesis适配器捕获DynamoDB表更改。我正在使用Scala应用程序中的AWS Java SDK。
我开始关注AWS guide并浏览AWS发布的code example。但是,我遇到了在我的环境中使用亚马逊自己发布的代码的问题。我的问题在于KinesisClientLibConfiguration
对象。
在示例代码中,KinesisClientLibConfiguration
配置了DynamoDB提供的流ARN。
new KinesisClientLibConfiguration("streams-adapter-demo",
streamArn,
streamsCredentials,
"streams-demo-worker")
我在我的Scala应用程序中遵循类似的模式,首先从我的Dynamo表中找到当前的ARN:
lazy val streamArn = dynamoClient.describeTable(config.tableName)
.getTable.getLatestStreamArn
然后使用提供的ARN创建KinesisClientLibConfiguration
:
lazy val kinesisConfig :KinesisClientLibConfiguration =
new KinesisClientLibConfiguration(
"testProcess",
streamArn,
defaultProviderChain,
"testWorker"
).withMaxRecords(1000)
.withRegionName("eu-west-1")
.withMetricsLevel(MetricsLevel.NONE)
.withIdleTimeBetweenReadsInMillis(500)
.withInitialPositionInStream(InitialPositionInStream.TRIM_HORIZON)
我已经验证了提供的流ARN,所有内容都与我在AWS控制台中看到的相符。
在运行时,我最终得到一个异常,说明提供的ARN不是有效的流名称:
com.amazonaws.services.kinesis.clientlibrary.lib.worker.ShardSyncTask call
SEVERE: Caught exception while sync'ing Kinesis shards and leases
com.amazonaws.services.kinesis.model.AmazonKinesisException: 1 validation
error detected: Value 'arn:aws:dynamodb:eu-west-1:STREAM ARN' at
'streamName' failed to satisfy constraint: Member must satisfy regular
expression pattern: [a-zA-Z0-9_.-]+ (Service: AmazonKinesis; Status Code:
400; Error Code: ValidationException; Request ID: )
查看KinesisClientLibConfiguration
上提供的文档,这确实有意义,因为第二个参数列为 streamName 而没有提及ARN。
我似乎无法在KinesisClientLibConfiguration
上找到与ARN相关的任何内容。由于我正在使用DynamoDB流而不是Kinesis流,因此我也不确定如何查找我的流名称。
此时我不确定我在已发布的AWS示例中缺少什么,似乎他们可能正在使用更旧版本的KCL。我正在使用版本1.7.0的amazon-kinesis-client。
答案 0 :(得分:4)
问题实际上最终超出了KinesisClientLibConfiguration
。
我能够通过使用相同的配置并提供DynamoDB流适配器库中包含的流适配器以及DynamoDB和CloudWatch的客户端来解决此问题。
我的工作解决方案现在看起来像这样。
定义Kinesis客户端配置。
//Kinesis config for DynamoDB streams
lazy val kinesisConfig :KinesisClientLibConfiguration =
new KinesisClientLibConfiguration(
getClass.getName, //DynamoDB shard lease table name
streamArn, //pulled from the dynamo table at runtime
dynamoCredentials, //DefaultAWSCredentialsProviderChain
KeywordTrackingActor.NAME //Lease owner name
).withMaxRecords(1000) //using AWS recommended value
.withIdleTimeBetweenReadsInMillis(500) //using AWS recommended value
.withInitialPositionInStream(InitialPositionInStream.TRIM_HORIZON)
定义流适配器和CloudWatch客户端
val streamAdapterClient :AmazonDynamoDBStreamsAdapterClient = new AmazonDynamoDBStreamsAdapterClient(dynamoCredentials)
streamAdapterClient.setRegion(region)
val cloudWatchClient :AmazonCloudWatchClient = new AmazonCloudWatchClient(dynamoCredentials)
cloudWatchClient.setRegion(region)
创建RecordProcessorFactory
的实例,由您来定义实现提供的{1}}和返回的IRecordProcessorFactory
的KCL的类。
IRecordProcessor
我失踪的部分,所有这些都需要提供给你的工人。
val recordProcessorFactory :RecordProcessorFactory = new RecordProcessorFactory(context, keywordActor, config.keywordColumnName)
答案 1 :(得分:0)
或者,您可以使用com.amazonaws.services.dynamodbv2.streamsadapter.StreamsWorker
代替com.amazonaws.services.kinesis.clientlibrary.lib.worker.Worker
内部使用AmazonDynamoDBStreamsAdapterClient
。
即
lazy val kinesisConfig :KinesisClientLibConfiguration =
new KinesisClientLibConfiguration(
getClass.getName, //DynamoDB shard lease table name
streamArn, //pulled from the dynamo table at runtime
dynamoCredentials, //DefaultAWSCredentialsProviderChain
KeywordTrackingActor.NAME //Lease owner name
).withMaxRecords(1000) //using AWS recommended value
.withIdleTimeBetweenReadsInMillis(500) //using AWS recommended value
.withInitialPositionInStream(InitialPositionInStream.TRIM_HORIZON)
val worker = new com.amazonaws.services.dynamodbv2.streamsadapter.StreamsWorker(recordProcessorFactory, kinesisConfig)
答案 2 :(得分:0)
只是为了回答问题所在 - 当你想要流名称时,你正在提供ARN。
答案 3 :(得分:0)
我最近对这个项目gfc-aws-kinesis做了PR,你现在可以通过传递适配器并编写KinesisRecordAdapter实现来使用它。
在示例中,我使用Scanamo来解析hashmap
创建客户端
val streamAdapterClient: AmazonDynamoDBStreamsAdapterClient =
new AmazonDynamoDBStreamsAdapterClient()
将其传递给配置:
val streamConfig = KinesisStreamConsumerConfig[Option[A]](
applicationName,
config.stream, //the full dynamodb stream arn
regionName = Some(config.region),
checkPointInterval = config.checkpointInterval,
initialPositionInStream = config.streamPosition,
dynamoDBKinesisAdapterClient = Some(streamAdapterClient)
)
KinesisStreamSource(streamConfig).mapMaterializedValue(_ => NotUsed)
创建一个适合阅读dynamodb事件的隐式记录阅读器:
implicit val kinesisRecordReader
: KinesisRecordReader[Option[A]] =
new KinesisRecordReader[Option[A]] {
override def apply(record: Record): Option[A] = {
record match {
case recordAdapter: RecordAdapter =>
val dynamoRecord: DynamoRecord =
recordAdapter.getInternalObject
dynamoRecord.getEventName match {
case "INSERT" =>
ScanamoFree
.read[A](
dynamoRecord.getDynamodb.getNewImage)
.toOption
case _ => None
}
case _ => None
}
}
}