When we are talking about Serverlesss Eventing, we are talking about more than products and technologies. We are talking about a platform and best practices. One thing that I have not been mentioning in my blog posts is the importance of an “Eventing Bus”.
An “Eventing Bus” is a publisher-subscriber style communication system. Its primary purpose is to be a liaison between services rather than having them communicate directly. Many people call this a “Message Bus” or “Message Queue” but since we are talking about eventing, we’ll call it an “Eventing Bus”. There are various benefits to using an Eventing Bus as I fully believe that it is important to the Serverless Eventing philosophy.
Earlier we described Serverless Eventing as a platform that utilizes the microservices architecture (as opposed to monolithic). This architecture gives us the leniency to give our developers the ability to use the right tool(s) for their service(s) and accelerate development by decoupling the services. The side-effect is that you will have tens if not hundreds or thousands of individual services.
Let’s say that you went on a two week vacation in Tokyo with ten friends. Everyone dispersed throughout the day, doing their own thing, but you want to hit up an izakaya with everyone at night. The original place you wanted to visit is closed so you need to find a new one. It is now your job to communicate the closure, determine a new place to meet, and figure out where everyone is so you can find something somewhat central. What’s the best way to communicate and plan this?
Do we want everyone to send a text to everyone else and try to coordinate that way? Imagine texting Sally to see where she wants to go then texting Jimmy to say Sally wants to go here and Jimmy says he’d rather go here but then you text Laura and she is on the other part of Tokyo and would rather get something halfway between the hotel and where she is. Laura then texts Bob to see if he has heard from you and what you think. You get the idea. How crazy would those threads of text look? Probably something like this:
Inevitably, something is going to be lost in communication and someone will show up to the wrong restaurant, arrive at the wrong time and so on. I bet many of you have applications like this today.
This could be your services if you used simply REST or gRPC to communicate with services. Each service is directly communicating with another service(s) and messages are sent back and forth. Many people choose this option and in some cases it’s a fine choice (more on that later). However, you are setting yourself up for failure if you are designing your modern application this way.
For one, how are you guaranteeing messages are sent and received? By default, many services will error out if the receiver can’t receive messages. It may also send a message assuming that receiver is there but it isn’t and that message is lost forever.
Another notion is scale of distribution. This example has me sending texts to nine individuals (clients). What happens when the clients scale to a hundred or a thousand? Can your service handle the workload needed to both send and receive messages at this scale? How will it handle blocking? Are you able to guarantee receipt? Are you able to guarantee the immutability of the message?
Order is also very important. When we are dealing with real-time events, the order of events is very important. Using the izakaya example, if we are talking about one place then 20 minutes later agree on a new place, it is important that you get the most recent information after the older information.
THERE HAS TO BE A BETTER WAY! Of course, the “Eventing Bus”. Let’s look at this a different way. Instead of directly texting people, we create a group chat in some kind of chat app such as WhatsApp. Everyone joins (subscribes) to the group chat (“Eventing Bus”). You send the message once, it’s received by everyone. You get little notifications for when the message is received and read. Replies are sent to the room. Every message is time stamped. Now our communication looks like this:
Our microservices should be structured in a similar way. We should be using an Eventing Bus. Now, I will say that Eventing Bus isn’t a panacea for messaging issues. There are still times when REST or gRPC are a valid solution. Here are key times when you should be using REST or gRPC over HTTP.
- Tight Coupling: The services need to know the existence of other services. This usually means that a service is implicitly sending to another service.
- Publicly Facing APIs: You are wanting to create an API that is internet accessible. Something like OpenID.
- Synchronous Messaging: If you need message A to finish before handling message B and so on, this is a great option.
Otherwise, when creating loosely coupled services, you should absolutely use an Eventing Bus. An Eventing Bus should give you these benefits.
- Loose Coupling: Your services do not need to explicitly know the existence of other services. The service performs its task, sends its output as a message to the bus, and you write another service to consume from the bus.
- Asynchronous Messaging: You do not need to wait for a response before processing a new message. This allows for more effective resource usage.
- Delivery Guarantee: Many message buses have protocols built into them to ensure that the message is received by its intended recipient at least once.
- Resilience: Since the services are sending messages to a bus, if a receiving service is broken, this doesn’t immediately cause the message to be lost. The message is stored in the bus and what the recipient service returns, it can then read the message and continue.
- Scalability: Using an Eventing Bus allows you to more efficiently add recipient services/clients to a smaller amount of sending services. You would simply add the new services as a subscriber to the Eventing Bus.
Now, I am not here to endorse a specific technology or brand over another. My policy is “the right tool for the job”. Depending on your team’s comfort level, existing investments, business requirements, etc. you will choose a tool that fits those needs.
The great news is that Knative Eventing allows you to use many existing buses as an event source. As mentioned in an earlier post, you can also use SinkBinding to define your event source. You can also write a custom event source. This allows you to turn your legacy messaging queue/bus into an Eventing Bus, ready for Serverless Eventing.
So if today you are building an app and want to adopt the freedom of Serverless Eventing, please give a great consideration to using these apps.