Apache Spark is a powerful big data engine used for large-scale data analytics. Its in-memory computing makes it great for iterative algorithms and interactive queries. You can use Apache Spark to process streaming data from a variety of streaming sources, including Amazon Kinesis Data Streams for use cases like clickstream analysis, fraud detection, and more. Kinesis Data Streams is a serverless streaming data service that makes it straightforward to capture, process, and store data streams at any scale.
With the new open source Amazon Kinesis Data Streams Connector for Spark Structured Streaming, you can use the newer Spark Data Sources API. It also supports enhanced fan-out for dedicated read throughput and faster stream processing. In this post, we deep dive into the internal details of the connector and show you how to use it to consume and produce records from and to Kinesis Data Streams using Amazon EMR.
Introducing the Kinesis Data Streams connector for Spark Structured Streaming The Kinesis Data Streams connector for Spark Structured Streaming is an open source connector that supports both provisioned and On-Demand capacity modes offered by Kinesis Data Streams. The connector is built using the latest Spark Data Sources API V2, which uses Spark optimizations. Starting with Amazon EMR 7.1, the connector comes pre-packaged on Amazon EMR on Amazon EKS, Amazon EMR on Amazon EC2, and Amazon EMR Serverless, so you don’t need to build or download any packages. For using it with other Apache Spark platforms, the connector is available as a public JAR file that can be directly referred to while submitting a Spark Structured Streaming job. Additionally, you can download and build the connector from the GitHub repo.
Kinesis Data Streams supports two types of consumers: shared throughput and dedicated throughput. With shared throughput, 2 Mbps of read throughput per shard is shared across consumers. With dedicated throughput, also known as enhanced fan-out, 2 Mbps of read throughput per shard is dedicated to each consumer. This new connector supports both consumer types out of the box without any additional coding, providing you the flexibility to consume records from your streams based on your requirements. By default, this connector uses a shared throughput consumer, but you can configure it to use enhanced fan-out in the configuration properties.
You can also use the connector as a sink connector to produce records to a Kinesis data stream. The configuration parameters for using the connector as a source and sink differ—for more information, see Kinesis Source Configuration. The connector also supports multiple storage options, including Amazon DynamoDB, Amazon Simple Service for Storage (Amazon S3), and HDFS, to store checkpoints and provide continuity.
For scenarios where a Kinesis data stream is deployed in an AWS producer account and the Spark Structured Streaming application is in a different AWS consumer account, you can use the connector to do cross-account processing. This requires additional Identity and Access Management (IAM) trust policies to allow the Spark Structured Streaming application in the consumer account to assume the role in the producer account.
You should also consider reviewing the security configuration with your security teams based on your data security requirements.
How the connector works Consuming records from Kinesis Data Streams using the connector involves multiple steps. The following architecture diagram shows the internal details of how the connector works. A Spark Structured Streaming application consumes records from a Kinesis data stream source and produces records to another Kinesis data stream.
A Kinesis data stream is composed of set of shards. A shard is a uniquely identified sequence of data records in a stream and provides a fixed unit of capacity. The total capacity of the stream is the sum of the capacity of all of its shards.
A Spark application consists of a driver and a set of executor processes. The Spark driver acts as a coordinator, and the tasks running in executors are responsible for producing and consuming records to and from shards.
The solution workflow includes the following steps:
kinesis.describeShardInterval) to configure the interval between two successive ListShard API calls.kinesis.startingPosition. If it’s a restart of an existing job, it’s read from last record metadata checkpoint from storage (for this post, DynamoDB) and ignores kinesis.startingPosition.Solution overview The following diagram shows an example architecture of how to use the connector to read from one Kinesis data stream and write to another.
In this architecture, we use the Amazon Kinesis Data Generator (KDG) to generate sample streaming data (random events per country) to a Kinesis Data Streams source. We start an interactive Spark Structured Streaming session and consume data from the Kinesis data stream, and then write to another Kinesis data stream.
We use Spark Structured Streaming to count events per micro-batch window. These events for each country are being consumed from Kinesis Data Streams. After the count, we can see the results.
Prerequisites To get started, follow the instructions in the GitHub repo. You need the following prerequisites:
After you deploy the solution using the AWS CDK, you will have the following resources:
Create your Spark Structured Streaming application After the deployment is complete, you can access the EMR primary node to start a Spark application and write your Spark Structured Streaming logic.
As we mentioned earlier, you use the new open source Kinesis Spark connector to consume data from Amazon EMR. You can find the connector code on the GitHub repo along with examples on how to build and set up the connector in Spark.
In this post, we use Amazon EMR 7.1, where the connector is natively available. If you’re not using Amazon EMR 7.1 and above, you can use the connector by running the following code:
cd /usr/lib/spark/jars sudo wget https://awslabs-code-us-east-1.s3.amazonaws.com/spark-sql-kinesis-connector/spark-streaming-sql-kinesis-connector_2.12-1.2.1.jarsudo chmod 755 spark-streaming-sql-kinesis-connector_2.12-1.2.1.jar
Complete the following steps:
emr-spark-kinesis cluster.You’re redirected to the Amazon EC2 console.
ssm-user, we need to switch to the Hadoop user:sudo su hadoopFor this post, we use Python for writing to a stream using a PySpark shell in Amazon EMR.
pyspark.Because you already have the connector installed in the EMR cluster, you can now create the Kinesis source.
kinesis = spark.readStream.format("aws-kinesis") \ .option("kinesis.region", "<aws-region>") \ .option("kinesis.streamName", "kinesis-source") \ .option("kinesis.consumerType", "GetRecords") \ .option("kinesis.endpointUrl", "https://kinesis.<aws-region>.amazonaws.com") \ .option("kinesis.startingposition", "LATEST") \ .load()For creating the Kinesis source, the following parameters are required:
aws-kinesisGetRecords (standard consumer) or SubscribeToShard (enhanced fan-out consumer)LATEST, TRIM_HORIZON, or AT_TIMESTAMP (refer to ShardIteratorType)For using an enhanced fan-out consumer, additional parameters are needed, such as the consumer name. The additional configuration can be found in the connector’s GitHub repo.
kinesis_efo = spark \.readStream \.format("aws-kinesis") \.option("kinesis.region", "<aws-region>") \.option("kinesis.streamName", "kinesis-source") \.option("kinesis.consumerType", "SubscribeToShard") \.option("kinesis.consumerName", "efo-consumer") \.option("kinesis.endpointUrl", "https://kinesis.<aws-region>.amazonaws.com") \.option("kinesis.startingposition", "LATEST") \.load()
Deploy the Kinesis Data Generator Complete the following steps to deploy the KDG and start generating data:
You might need to change your Region when deploying. Make sure that the KDG is launched in the same Region as where you deployed the solution.
{ "id": {{random.number(100)}}, "data": "{{random.arrayElement( ["Spain","Portugal","Finland","France"] )}}", "date": "{{date.now("YYYY-MM-DD hh:mm:ss")}}"}from pyspark.sql.types import *pythonSchema = StructType() \ .add("id", LongType()) \ .add("data", StringType()) \ .add("date", TimestampType())from pyspark.sql.functions import *events= kinesis \ .selectExpr("cast (data as STRING) jsonData") \ .select(from_json("jsonData", pythonSchema).alias("events")) \ .select("events.*")events \ .selectExpr("CAST(id AS STRING) as partitionKey","data","date") \ .writeStream \ .format("aws-kinesis") \ .option("kinesis.region", "<aws-region>") \ .outputMode("append") \ .option("kinesis.streamName", "kinesis-sink") \ .option("kinesis.endpointUrl", "https://kinesis.<aws-region>.amazonaws.com") \ .option("checkpointLocation", "/kinesisCheckpoint") \ .start() \ .awaitTermination()You can view the data in the Kinesis Data Streams console.
kinesis-sink.You can see the data sent, as shown in the following screenshot. Kinesis Data Streams uses base64 encoding by default, so you might see text with unreadable characters.
Clean up Delete the following CloudFormation stacks created during this deployment to delete all the provisioned resources:
EmrSparkKinesisStackKinesis-Data-Generator-Cognito-User-SparkEFO-BlogIf you created any additional resources during this deployment, delete them manually.
Conclusion In this post, we discussed the open source Kinesis Data Streams connector for Spark Structured Streaming. It supports the newer Data Sources API V2 and Spark Structured Streaming for building streaming applications. The connector also enables high-throughput consumption from Kinesis Data Streams with enhanced fan-out by providing dedicated throughput up to 2 Mbps per shard per consumer. With this connector, you can now effortlessly build high-throughput streaming applications with Spark Structured Streaming.
The Kinesis Spark connector is open source under the Apache 2.0 license on GitHub. To get started, visit the GitHub repo.
About the Authors Idan Maizlits is a Senior Product Manager on the Amazon Kinesis Data Streams team at Amazon Web Services. Idan loves engaging with customers to learn about their challenges with real-time data and to help them achieve their business goals. Outside of work, he enjoys spending time with his family exploring the outdoors and cooking. Subham Rakshit is a Streaming Specialist Solutions Architect for Analytics at AWS based in the UK. He works with customers to design and build search and streaming data platforms that help them achieve their business objective. Outside of work, he enjoys spending time solving jigsaw puzzles with his daughter. Francisco Morillo is a Streaming Solutions Architect at AWS. Francisco works with AWS customers helping them design real-time analytics architectures using AWS services, supporting Amazon MSK and AWS’s managed offering for Apache Flink. Umesh Chaudhari is a Streaming Solutions Architect at AWS. He works with customers to design and build real-time data processing systems. He has extensive working experience in software engineering, including architecting, designing, and developing data analytics systems. Outside of work, he enjoys traveling, reading, and watching movies.