Use Spark Streaming in E-MapReduce (EMR) to consume messages from Simple Message Queue (formerly MNS) (SMQ) and process them in real time.
Prerequisites
Before you begin, ensure that you have:
-
An SMQ queue with at least one message to consume
-
An EMR cluster with Spark Streaming enabled
-
The EMR SDK (version 1.3.2 or later for MetaService access)
-
(If using AccessKey authentication) Environment variables
ALIBABA_CLOUD_ACCESS_KEY_IDandALIBABA_CLOUD_ACCESS_KEY_SECRETconfigured on your cluster nodes. See Configure environment variables.
Authentication options
EMR SDK provides two ways to authenticate Spark Streaming against SMQ:
| Method | Requires AccessKey pair | Available since | Recommended for |
|---|---|---|---|
| MetaService | No | EMR SDK 1.3.2 | EMR clusters (no credential management needed) |
| AccessKey pair | Yes | All versions | Non-EMR environments or older SDK versions |
Use MetaService when running on an EMR cluster — it removes the need to manage or rotate AccessKey credentials in your code.
Consume SMQ messages with MetaService
MetaService handles authentication automatically. Pass the queue name, endpoint, and storage level — no AccessKey pair required.
val conf = new SparkConf().setAppName("Test MNS Streaming")
val batchInterval = Seconds(10)
val ssc = new StreamingContext(conf, batchInterval)
val queueName = "<your-queue-name>"
// Use the SMQ endpoint for your region
val endpoint = "https://oss-cn-hangzhou.aliyuncs.com"
// MetaService authenticates automatically — no AccessKey pair needed
val mnsStream = MnsUtils.createPullingStreamAsBytes(ssc, queueName, endpoint, StorageLevel.MEMORY_ONLY)
mnsStream.foreachRDD { rdd =>
rdd.map(bytes => new String(bytes))
.flatMap(_.split(" "))
.map(word => (word, 1))
.reduceByKey(_ + _)
.collect()
.foreach(e => println(s"word: ${e._1}, cnt: ${e._2}"))
}
ssc.start()
ssc.awaitTermination()
Replace the following placeholders with actual values:
| Placeholder | Description | Example |
|---|---|---|
<your-queue-name> |
Name of your SMQ queue | my-queue |
endpoint |
SMQ service endpoint for your region | https://oss-cn-hangzhou.aliyuncs.com |
Consume SMQ messages with an AccessKey pair
If MetaService is unavailable, pass your AccessKey credentials explicitly. Store them as environment variables rather than hardcoding them in your code.
val conf = new SparkConf().setAppName("Test MNS Streaming")
val batchInterval = Seconds(10)
val ssc = new StreamingContext(conf, batchInterval)
val queuename = "<your-queue-name>"
val accessKeyId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID")
val accessKeySecret = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET")
// In this example, the endpoint of the China (Hangzhou) region is used. Specify your actual endpoint.
val endpoint = "https://oss-cn-hangzhou.aliyuncs.com"
val mnsStream = MnsUtils.createPullingStreamAsRawBytes(ssc, queuename, accessKeyId, accessKeySecret, endpoint,
StorageLevel.MEMORY_ONLY)
mnsStream.foreachRDD { rdd =>
rdd.map(bytes => new String(bytes))
.flatMap(line => line.split(" "))
.map(word => (word, 1))
.reduceByKey(_ + _)
.collect()
.foreach(e => println(s"word: ${e._1}, cnt: ${e._2}"))
}
ssc.start()
ssc.awaitTermination()
MnsUtils provides two MetaService-compatible methods: createPullingStreamAsBytes and createPullingStreamAsRawBytes. Both omit the AccessKey parameters; the AccessKey pair versions add accessKeyId and accessKeySecret before the endpoint.
What's next
For the complete sample code, see SparkMNSDemo on GitHub.