Creating a Scalable WebSocket Application in an Hour with Scala
In general, a web browser does not keep the HTTP connection open when it requests a resource from a server. Of course, there are several exceptions when the web browser keeps the connection open for a period of time such as long polling (which is kind of hacky way to do a push notifications), Pushlet, SSE, web browser plugins, and WebSocket. Some of them take advantage of HTTP keep-alive while some use different protocols.
WebSocket is a technology that comes with the HTML5 specification. It’s a full-duplex connection that means a web browser can send and receive data from a web server and vise versa over a single TCP connection. It sounds really good because we can do many cool things with it; however, this feature comes with a cost since the number of connections in a single server has a limit. When you want to scale it out, you have to figure out how to correlate the connections across a cluster.
Good news! You can implement a scalable WebSocket solution in less than an hour using Play! framework, Akka, and Redis. The language that I’m going to demonstrate is Scala. You can use Java, but it’s going to be a bit harder because Rediscala plugin doesn’t have a Java version (actually, you can guess that from its name). This solution is surely not the best solution since it still has some scalability issues, and one of the issues is from Redis. You can find a better publisher/subscriber toolkit that is more scalable and robust than Redis. The reason that I decided to use Redis here is because it’s very simple to setup. You can get it up and running with default configurations in the blink of an eye. I’m not kidding. You can use this solution to create a Minimum Viable Product (MVP) in less than an hour. It’s really nice, isn’t it?
I’m not going to show you how to setup Play! project nor will I show you how to configure an sbt project because this is not a tutorial for that, so I’ll skip the boring parts and go right to the fun part :).
Each web browser page has its own connection. When the web browser initiates a connection, it will ask the load balancer which web server it should talk to. After getting the specific server address, the web browser will create a persistent TCP connection to that web server. From figure 1, you might wonder why there is only one Redis server. Actually, it’s not necessary because you can setup a Redis cluster but Redis pubsub model is not that robust and you may have traffic congestion from the synchronization of messages across a cluster. Of course, I might be wrong since I didn’t test it out (I didn’t even look into it), please share your thoughts if you think otherwise and I will really appreciate :). You can replace Redis with either pure Akka solution or other middlewares such as Kafka, RabbitMQ, and ActiveMQ to get more scalability and reliability.
Let’s start from the Controller part.
You may want to read this tutorial from Playframework website before you get going.
What we are missing in the server side is SubscribeActor which is the dispatcher for Redis pubsub service. Let’s implement it.
That’s pretty simple, isn’t it? It doesn’t do anything much here because what we want is just to delegate the message receiving from Redis pubsub to the Actor that is bound to a WebSocket’s connection.
I’m pretty sure you can write the better code than my PoC code. You may have already guessed what the program does. Yes, it is a chatroom where you can change the channel. The subscriber will be labelled by channel name. At this point, I have shown you the server side code and the client side code. What about Redis, our message coordinator? I don’t need to show you because you just have to run the server and that’s it! That’s another reason why I picked Redis.
You think creating a scalable WebSocket chatroom in an hour is a bit too long? Clone this repository and you will get it in a minute.