Hacker News new | ask | show | jobs
by latch 4125 days ago
FWIW, I've found that building a robust and deep "API Gateway" is the key to making SOA/Microservices work. Otherwise, you end up with duplication and latency.

Routing and authentication are obvious candidates. It's also a good place to track stats and tag each request with a unique ID so you can trace it as it flows through your services.

By "deep", I mean that it should be application-aware. Caching is a good example. For many applications, url + querystring results in too many permutations. If the cache is aware, it can often use more meaningful keys. Additionally, events in the underlying services can be used to cache purge, which can result in a wicked cache hit ratio.

A more complex example has to do with duplication. Say you're building an ecomm platform. You have a service for search, and one for recommendations and one for the main catalog. They all need to return the same representation of a "product". Do you duplicate the logic? Do you tie them together and pay the latency and reliability price? No. Have them all just return IDS, and let the API Gateway hydrate the actual results. It's a form of API-aware server-side include and it works well.

4 comments

The article seems to describe a system which has funnel-shaped dataflow (narrow inlet, spread to services), which is also a side-effect of the 'API Gateway' approach you mention.

Three useful definitions[1] for microservices are:

1) collaborating

2) independently deployable (Martin Fowler [2])

3) globally-aware

Having an API Gateway makes them follow none of these meaningfully, as:

1) the services are collaborated _upon_ rather than doing so with each other (see Clump[3], not itself a bad idea)

2) updating a microservice will many times require a redeploy of the API gateway and for everyone to update their connections to it

3) any functionality you put in the gateway becomes encapsulated in a way tailored to application-global needs, which is pretty inimical to modular components, so you'd better not talk through the gateway except where you absolutely must!

Having orchestration/aggregation services as buro9 mentions in a sibling post is one good solution, satisfying all of those three points much more cleanly.

The danger arises when you start to think of your gateway(s) as layers in front of your system rather than just more microservices in it.

[1]: (context) https://vimeo.com/118895501#t=48s

[2]: http://martinfowler.com/articles/microservices.html

[3]: http://getclump.io/

I mostly agree with this.

I consider services to fall into two groups:

1. Core/Technical services that are the master record for data and are responsible for data integrity, notifying others of changes, audit, etc... but ultimately store the data and the schemas of a piece of data, handle caching.

2. Composition/Orchestration/Business services that sit in front of the core services, and these contain business logic and when they operate on lists they really operate on IDs and do that ESI merge thing composing their collection from multiple calls from the core service.

The more I work on services the more I find this separation and layering of services extremely useful. It helps massively simplify the services that interact with data stores, and allows for quick development of new composition services to handle new needs of the business.

> FWIW, I've found that building a robust and deep "API Gateway" is the key to making SOA/Microservices work. Otherwise, you end up with duplication and latency.

The risk here is that the API gateway gets too big, and its gravity starts attracting more and more functionality, until you have a brand new monolithic application.

I like the gateway approach, but generally I want to have multiple gateways, each serving as a "Microservice Facade" for a particular application or small set of applications. New applications get new Facades.

There ends up being some duplication across the facades, but basically I think "so be it". As long as the core services are factored out and own their business logic, I don't mind if the consuming applications have some duplication.

This is really interesting. Would you consider writing a more in-depth post on this? I'd love to read it.
If you mean the SSI: http://openmymind.net/Practical-SOA-Hydration-Part-1/ http://openmymind.net/Practical-SOA-Hydration-Part-2/

I'm playing with it again on a new project, with a twist. Each item can be heavily personalized. Sticking with the ecomm example, the virgin product might look like

    {
      "id": "434p",
      "name": {"en": "..."},
    }
But we want to expand that, per user, with stuff like:

    "liked": true, 
    "bought": "22-1-2015"
We don't want to burden the clients with having to make multiple calls. I'm still working it out, but the services will continue to just return a list of product ids, and the API Gateway will now hydrate both the product and the personalized pieces. Something like:

   res = upstream(req)
   ids = extractIds(res.Body)
   products = getProducts(ids)
   personalized = getPersonalized(ids, currentUser)
   reply(merge(products, personalized))

Not critical, but worth pointing out that, for me, the API Gateway acts like a gigantic product cache with _every_ product in-memory. When a product changes, it gets an event and updates its cache. It isn't really a "cache", since there's never a miss. Trying to figure out if I can do the same with personalized data. (Even if you have tens millions of product, you can easily store it in memory).
Awesome! Thanks :)
Thanks, Noel!