Making Microservices Look Like a Monolith
The microservice API architecture has a lot of undisputed benefits. By breaking down your program into smaller independent pieces, teams find it easier to…
- Parallelize their work.
Ownership and responsibility are more naturally distributed. - Mix up different programming languages, frameworks and even run them at different versions.
It's much easier to evolve when no migrations of large codebases are involved. - Scale, detect performance bottlenecks and isolate failures.
The overall system tends to be more resilient and easier to analyze.
Yet two big challenges commonly follow: coordination and simulation.
To solve this problem, we added a new feature to
now alias
, which makes composing and coordinating services a breeze. We will also explain how developers can effectively simulate and iterate on a cluster of microservices with the now architecture.Build with Microservices. Serve as a Monolith.
Before we introduced path aliases, it was commonplace to launch services with
now
and later assign them a new, usually more accesible, URL via now alias
.For example, if you deploy our Node.js microservice you get a URL that looks like this:
api-auth-ybqnmnovxg.now.sh
. It's immutable and unique to that point-in-time.After that, you could run
now alias api-auth-ybqnmnovxg.now.sh auth.api.my-company.com
. That would point your new microservice to a more friendly sub-domain.This model works remarkably well for development and staging. It allows me to maintain an unlimited number of copies of my service online, and I can test them in a real environment.
But, how do I go from that to, for example, exposing it as
my-company.com/api/auth?
After all, the end-users of our applications or consumer of our APIs don't care about our underlying software architecture.In fact, pointing clients to different domains and sub-domains can be downright expensive:
- Extra DNS lookups and TCP connections will be required when starting up.
- Browsers will require CORS headers, which will increase the complexity of your codebase and the length of the responses.
- In some cases, User Agents will pre-flight requests to different origins. If
company.com
talks toapi.company.com
, you might incur in extra roundtrips for every request!
From the perspective of a consumer, the best possible interface is a monolith.
Alias Rules
If you're using our command line interface, you're able to pass a very simple JSON file to the
now alias
command with a list of forwarding rules for your domains or sub-domains:$ now alias company.com -r rules.json
Every time your run this command, the rules for company.com
are updated without any downtime.
The file looks like this:
{
"rules": [
{ "pathname": "/api/auth", "dest": "auth.api.company.com" },
{ "pathname": "/api/users", "dest": "users.api.company.com" },
{ "pathname": "/u/**", "dest": "profiles.company.com" },
{ "dest": "www.company.com" }
]
}
An example of rules.json
with 4 custom forwarding rules.
This means if an user goes to
company.com/api/auth
he's going to see that URL in the browser but internally the request will go to auth.api.company.com/api/auth
(yes the pathname
is appended to the dest
URL).Here are some of the main characteristics of the system we're excited about.
1. Atomic
Not a single request is dropped while or after the rules are loaded. You can run the command with confidence adding, subtracting or modifying rules.
2. Idempotent
If any of the rules remain the same, the system's performance is not impacted and no errors occur.
3. Versionable
You can check in your rules to source control (e.g.: GitHub) and keep track of the evolution of your architecture. Your team can review and discuss changes in pull requests. You can even automate synchronizing the rules in CI!
4. Flexible
Rules can include glob like wildcards (
*
and **
) to enable very flexible matching. You can specify a particular method ("method": "GET"
) or a set of them (["POST", "GET"]
). The rules are matched in the order they are specified.5. Universal
If the
dest
field of a given rule resolves to a now deployment or alias URL, we detect it and turn on intra-cluster optimizations.If it's an external URL, we act as a proxy, in line with our mission of gluing the cloud together through incremental changes and avoiding expensive migrations.
6. Unlimited
As said above, one of the remaining challenges with microservices is simulation. For example, if you are a developer tasked with improving the company's login experience, you might need to make changes to both the auth microservice and the frontend app.
With now, you can push out your modified endpoint, modify the rules and clone them into a new location. For example,
staging.company.com
can be exactly the same as company.com
, with the /api/auth
rule pointing to the new microservice and the last (fallback) rule pointing to the modified website.There are no limits to the number of times you can deploy or how many aliases you can create!