Glenn Engstrand

Building a Scalable News Feed Web Service in Clojure

The company where I currently work pays for each engineer to go to the conference of their choice once a year. One of my co-workers decided to go to Java One. When he came back, he shared with us the theme for that year which was Functional Programming. I decided that it was time to revisit FP if it was starting to pick up traction with the stodgy Java One types.

So, I whipped up a news feed web service using Clojure, Redis, Cassandra, Postgresql, Kafka, and Solr. Then I set it up on AWS and put some load testing on it to see how well these new open source technologies compare to their older brethren. I aggregated the performance metrics using Hadoop and surfaced the data using the Mondrian OLAP cube. The blog documents my findings.

Q: How do you set up the blog feed service and get it running?
A: See the feed/doc/intro.md file for a more detail explaination.
Q: How do you set up and start the load test?
A: See load/doc/intro.md file for a more detailed explaination.
Q: How do you capture the performance data from the load test?
A: That is also covered in the load/doc/intro.md file.
Q: How do you set up the OLAP cube?
A: See etl/doc/intro.md file for a more detailed explaination.
Q: Why use postgresql for the news feed service itself yet capture the performance data in a MySql database?
A: The default Mondrian installation uses MySql so there is less set up if you go that route.
Q: How do you run the map reduce job?
A: Review the etl/README.md for more information.
Q: Why did you attribute the spike to the cloud? Could it have been something else such as redis?
A: It is unlikely that Redis is the cause because, were that to have been the case, then the same spike would not have shown up in all the graphs.
Q: I understand why you would want to stay with the JVM. It is mature, stable, and hardened by countless man hours of engineering. Why didn’t you code this service in Java?
A: There is a big trend these days to use Functional Programming. In FP, you are discouraged from mutating state which is the cause of a large number of bugs in multi-threaded services.
Q: Why did you pick Clojure? Why not pick another JVM based Functional Programming language such as Scala or Groovy?
A: I felt that such features as Software Transactional Memory, lazy sequences, and Persistent Data Storage made Clojure more focused on addressing real world server side concerns such as less buggy concurrency and excessive object creation.
Q: Why use Redis for caching? Why not ehcache?
A: The default topology for ehcache is embedded. I did not want to put the cache on the heap because that can pause the app during a full GC. You can code around those problems but it increases the complexity of your service.
Q: Okay then, if you needed an external cache, why not use memcached?
A: Redis has support for the ability to add to the end of a list without first fetching the list. This solves a lot of timing window problems where individual items of a list can get lost during concurrent writes. You can code around those problems with at the cost of additional complexity and some degradation of performance.
Q: Why did you store the activity content itself in a NoSql data store? Why not put everything in the RDBMS?
A: I am a “right tool for the job” kind of engineer and not a “one size fits all” engineer. Modern relational databases are complicated systems but, basically, it is a B Tree data structure. That is a good fit for profile data or a social graph but not the best when we are talking about time series such as a news feed. For that type of access pattern, a log structured merge tree makes more sense.
Q: Why did you pick Cassandra then? Why not hbase?
A: In a social broadcast use case, you are typically going to have more writes than reads. Cassandra is more optimized for that than hbase.

Building a Scalable News Feed Web Service in Clojure

Leave a Reply