Spark Summit 2013 Talk:
At Sharethrough we have deployed Spark to our production environment to support several user facing product features. While building these features we uncovered a consistent set of challenges across multiple streaming jobs. By addressing these challenges you can speed up development of future streaming jobs. In this talk we will discuss the 3 major challenges we encountered while developing production streaming jobs and how we overcame them.
First we will look at how to write jobs to ensure fault tolerance since streaming jobs need to run 24/7 even under failure conditions. Second we will look at the programming abstractions we created using functional programming and existing libraries. Finally we will look at the way we test all the pieces of a job –from manipulating data through writing to external databases– to give us confidence in our code before we deploy to production
2. What We’re Going to Cover
•What we do and Why we choose Spark
•Fault tolerance for long lived streaming jobs
•Common patterns and functional abstractions
•Testing before we “do it live”
@rweald
Monday, December 2, 13
7. Why Spark Streaming
•Liked theoretical foundation of mini-batch
•Scala codebase + functional API
•Young project with opportunities to contribute
•Batch model for iterative ML algorithms
@rweald
Monday, December 2, 13
10. Keys to Fault Tolerance
1.Receiver fault tolerance
2.Monitoring job progress
@rweald
Monday, December 2, 13
11. Receiver Fault Tolerance
•Use Actors with supervisors
•Use self healing connection pools
@rweald
Monday, December 2, 13
12. Use Actors
class RabbitMQStreamReceiver (uri:String, exchangeName: String,
routingKey: String) extends Actor with Receiver with Logging {
implicit val system = ActorSystem()
override def preStart() = {
//Your code to setup connections and actors
//Include inner class to process messages
}
def receive: Receive = {
case _
=> logInfo("unknown message")
}
}
@rweald
Monday, December 2, 13
13. Track All Outputs
•Low watermarks - Google MillWheel
•Database updated_at
•Expected output file size alerting
@rweald
Monday, December 2, 13
23. WTF is a Monoid?
trait Monoid[T] {
def zero: T
def plus(r: T, l: T): T
}
* Just need to make sure plus is associative.
(1+ 5) + 2 == (2 + 1) + 5
@rweald
Monday, December 2, 13
34. How do we store the
results?
@rweald
Monday, December 2, 13
35. Storage API Requirements
•Incremental updates (preferably associative)
•Pluggable to support “big data” stores
•Allow for testing jobs
@rweald
Monday, December 2, 13
36. Storage API
trait MergeableStore[K,
def get(key: K): V
def put(kv: (K,V)): V
/*
* Should follow same
* as our Monoid from
*/
def merge(kv: (K,V)):
}
@rweald
Monday, December 2, 13
V] {
associative property
earlier
V
43. Testing best Practices
•Try and avoid full integration tests
•Use in-memory stores for testing
•Keep logic outside of Spark
•Use Summingbird in memory platform???
@rweald
Monday, December 2, 13