Live data from Hacker News

Microservices should form a polytree

bytesauna.com

51–60 of 121 posts

Re: Microservices should form a polytree

#51

Why do we use polytree in this context instead of DAG? Because nodes can’t ever come back together?

The author is not saying you should use a polytree but rather that the ideal graph of microservices should also be a polytree.

A polytree has the property that there is exactly one path that each node can be reached. If you think of this as a dependency graph, for each node in the graph you know that none of its dependencies have shared transitive dependencies.

I'll give it one though: if there are no shared transitive dependencies then there cannot be version conflicts between services, where two otherwise functioning services need disparate versions of the same transitive dependency.

Re: Microservices should form a polytree

#52
Here's a really simple way to get a cycle.

Service A: publish a notification indicating that some new data is available.

Service B: consume these notifications and call back to service A with queries for the changed data and perhaps surrounding context.

What would you recommend when something like this is desired?

Re: Microservices should form a polytree

#53
post #31

Avoiding cyclic dependencies is good, sure. And they do name specific problems that can happen in counterexample #1. However, the reasoning as to why it can't be a general DAG and has to be restricted to a polytree is really tenuous. They basically just say counterexample #2 has the same issues with no real explanation. I don't think it does, it seems fine to me.

An AuthN/Z system would probably end looking like counterexample #2, which immediately raised a red flag for me about the article.

Yeah if services can't be used by multiple other services, then what's the point?

Re: Microservices should form a polytree

#54

Here's a really simple way to get a cycle. Service A: publish a notification indicating that some new data is available. Service B: consume these notifications and call back to service A with queries for the changed data and perhaps surrounding context. What would you recommend when something like this is desired?

There is no cycle here.

Service B initiates the connection to Service A in order to receive notifications, and Service B initiates the connection to Service A to query for changed data.

Service A never initiates a connection with Service B. If Service B went offline, Service A would never notice.

Re: Microservices should form a polytree

#55
The article is not wrong, but I feel like the polytree restraint is a bit forced, and perhaps not the most important concern.

You really need to consider why you want to use micro services rather than a monolith, and how to achieve those goals.

Here's where I'll get opinionated: the main advantage micro services have over a monolith is the unique failure modes they enable. This might sound weird at first, but bear with me. First of all, there's an uncomfortable fact we need to accept: your web service will fail and fall over and crash. Doesn't matter if you're Google or Microsoft or whatever, you will have failures, eventually. So we have to consider what those failures will look like, and in my book, microservices biggest strength is that, if built correctly, they fail more gracefully than monoliths.

Say you're targeted by a DDOS attack. You can't really keep a sufficiently large DDOS from crashing your API, but you can do damage control. To use an example I've experienced myself, where we foresaw an attack happening (it came fairly regularly, so it was easy to predict) and managed to limit the damage it did to us.

The DDOS targeted our login API. This made sense because most endpoints required a valid token, and without a token the request would be ignored with very little compute wasted on our end. But requests against /login had to hit a database pretty much every time.

We switched to signed JWT for Auth, and every service that exposed an external API had direct access to the public key needed to validate the signatures. This meant that if the Auth service went down, we could still validate tokens. Logged in users were unaffected.

Well, just add predicted, the Auth service got ddosed, and crashed. Even with auto scaling pods, and a service startup time of less than half a second, there was just no way to keep up with the sudden spike. The database ran out of connections, and that was pretty much it for our login service.

So, nobody could login for the duration of the attack, but everyone who was already logged in could keep using our API's as if nothing had happened. Definitely not great, but an acceptable cost, given the circumstances.

Had we used a monolith instead, every single API would've gone down, instead of just the Auth ones.

So, what's the lesson here? Services that expose external API's should be siloed, such that a failure in one, or it's dependencies, does not affect other API's. A polytree can achieve this, but it's not the only way to do it. And for internal services the considerations are different, I'd even go so far as to say simpler. Just be careful to make sure that any internal service than can be brought down by an attack on an external one, doesn't bring other external services down with it.

So rather than a polytree, strive for siloes, or as close to them as you can manage. When you can't make siloes, consider either merging services, or create deliberate weak-points to contain damage

Re: Microservices should form a polytree

#56
post #7

Earlier quoted context omitted.

IAM roles. Said less snarky, it should be trivial to define and restrict the dependencies of services (Although there are many ways to do that). If its not trivial, that's a different problem.

Since you called the problem “trivial,” we can now all depend on you to resolve these problems for us at little cost, correct?

Restricting arbitrary east-west traffic should be table stakes... It should be the default and you opt into services being able to reach each other. So in that sense its already done.

Re: Microservices should form a polytree

#57
post #22
post #7

Earlier quoted context omitted.

IAM roles. Said less snarky, it should be trivial to define and restrict the dependencies of services (Although there are many ways to do that). If its not trivial, that's a different problem.

I don't mean that. I mean that eventually the business is going to need some feature that requires breaking the acyclic rule.

Ah, you don't mean enforce a novice making a mistake, you mean ensure from a design purity perspective?

I don't think its true that you need requests to flow both ways. For example, if a downstream API needs more context from an upstream one, one solution is to pass that data down as a parameter. You don't need to allow the downstream services to independently loop back to gather more info.

Re: Microservices should form a polytree

#58

Earlier quoted context omitted.

An AuthN/Z system would probably end looking like counterexample #2, which immediately raised a red flag for me about the article.

Yeah if services can't be used by multiple other services, then what's the point?

Treating N4 as a service is fair. I think the article was leaning more toward that idea of N4 being a database, which is a legit bad idea with microservices (if fact defeating the point entirely). My takeaway is that if you're going to have a service that many other services depend on, you can do it but you need to be highly away of that brittleness. Your N4 service needs to be bulletproof. Netflix ran into this exact issue with their distributed cache.

Re: Microservices should form a polytree

#59

Rule #2 sounds dumb. If there can't be a single source of truth, for let's say permission checking, that multiple other services relay on, how would you solve that? Replicate it everywhere? Or do you allow for a new business requirement to cause massive refactors to just create a new root in your fancy graph?

Services handle the permissions of their own features. Authentication is handled at the gateway.

Not sure if I agree its really the best way to do things but it can be done.

Re: Microservices should form a polytree

#60
post #27

Earlier quoted context omitted.

Most components need to depend on an auth service, right? I don’t think that means it’s all necessarily one service (does all of Google Cloud Platform or AWS need to be a single service)?

That's immediately what I thought of. You'll never be able to satisfy this rule when every service has lines pointing to auth. You'll probably also have lines pointing to your storage service or database even if the data is isolated between them. You could have them all be separate but that's a waste when you can leverage say a big ceph cluster.

The trick I've used is the N1 (gateway) service handles all AuthN and proxies that information to the upstream services to allow them to handle AuthZ. N+ services only accept requests signed by N1 - the original authentication info is removed.
Post reply on HN