tkruthoff

tkruthoff

Is an app with 3000 Microservices a fit for Elixir/OTP over Kubernetes/GRPC

Elixir and Phoenix are awesome and I’m hoping I can use them on my next project, however I’m an Elixir/OTP newbie and I’m not finding real examples of how Elixir apps with lots of moving parts are written, maintained and deployed.

For context, elixir-in-times-of-microservices by Jose is what first peeked my interest and I’ve bought/read every Elixir book I can get my hands on and this what we’ve come up thus far:

Umbrella OTP App containing:
API: phoenix and ecto serving REST and GraphQL – originally ecto was in separate app called DB, but then we settled on the API (and not the DB) is what the other apps/services interface with
FrontEnd: Main webapp our customers use (phoenix)
Admin: Backoffice webapp for staff (phoenix)
Integrations: This is where things go off the rails, we injest and transmit data, mostly in XML via HTTPS with over 3000 sources. An App per seems out of place, in most cases we have a REST or Soap client that listens to a queue and takes action, much like a background task. A lot of them will also spin up a GenServer per source (and this should be singleton across the entire cluster) and poll the source for data. We need to be able to control start/stop/pause per source as the sources like to add/remove data elements from time to time, best scenario would be able to update and deploy new code for a source without affecting the rest of the system. So we are thinking most of the 3000 integrations will be a Supervisor, with a GenServer (receiver) and a Module (sender).

Historically, each source ran as a windows service on a beefy single box, manually deployed, paused and updated separate from the web apps. (new services will run on Linux) The benefits/joy of being able to pull up :observer and peer into the source processes with state, or to remote iex and tinker would be epic.

Is anyone doing something like this in production that is willing to share how they structured the many integrations and deploying and upgrading a system like this. It’s possible we could be a trailblazer, but an existing production story would be invaluable.

Thank you

Most Liked

NobbZ

NobbZ

With 3k services this would result in 3k nodes, which would mean roughly 9M node-interconnections, since the BEAM wants to interconnect all nodes with each other. This won’t work well. You need to replace the messaging by another mechanism that does not require the full mesh.

Also you’d load the BEAM 3k times, while by putting some if not all of those modules alltogether on a single bare machine without docker, you can still update the modules one by one…

sasajuric

sasajuric

Author of Elixir In Action

Running 3000 services in a single BEAM node should not be a problem. You basically start one (or more) processes per each service, and that’s it.

The second part of your requirement is indeed tricky. If you can afford to restart everything, your life will be much simpler. If not, then you must enter the realm of code reloading. Some basic instructions are available here.

In some simpler cases, this might work out of the box, If you actually have 3000 different modules (which I somehow doubt, but who knows ¯\(ツ)/¯ ), and cache previous release builds on the build server, then I think (not 100% sure though) that distillery will be able to detect the change and generate a correct appup automatically.

In more complicated cases, you might need to hand code an appup file. You can find some basic examples here. As far as I understand, appup is quite flexible. Among the low-level instructions there is apply which allows you to invoke a series of functions in an arbitrary order, so I it should be possible to do perform any kind of upgrade logic, no matter how complex it is.

peerreynders

peerreynders

I think that article was triggered by an earlier StackOverflow topic - where I found that one particular passage stood out:

So far I haven’t talked about microservices. That’s because, up to this point, they don’t really matter.

i.e. building (potentially distributed) applications with Elixir/OTP can leverage some of the benefits associated with microservices architecture without having to accept the overhead of supporting microservices architecture - but that doesn’t mean Elixir/OTP solutions necessarily would classify as realizations of microservices architecture - and that’s OK because microservices architecture isn’t supposed to be an end in itself. Meanwhile there are lots of principles that microservices architecture is based on that can also benefit Elixir/OTP solutions.

Of your post, to me, this immediately stood out. Because this kind of implies that at least on a conceptual level you currently have 3000 “beefy single boxes” processing your sources and yet:

An App per seems out of place,

… which kind of sounds like what you are doing right now. From my current research, still incomplete and ongoing - so I’m sure somebody will correct me if I’m wrong:

  • Node: An executing Erlang run-time system (ERTS) which can communicate with other Erlang run-time systems.
  • While a single hardware server (or virtualized OS) can run multiple Nodes, a Node itself cannot be distributed.
  • Given that a Node executes an ERTS and that a Release includes an ERTS it seems that a Node can at most run one Release (???)
  • While a Release can include multiple “applications” it seems to only support one primary application while the remainder are simply included applications. Therefore a Release seems to only support one supervision tree (???). So far my search for a release supporting multiple primary applications and supervision trees has come up empty.
  • The point being is that a Node is executing one single primary application and it’s supervision tree.
  • It would be tempting to equate (one Node == one microservice) - but that overlooks the level of isolation and decoupling that is possible within the same supervision tree.
  • While the Node itself can’t be distributed, the application executing within it can spawn processes on other Nodes - though design-wise I would prefer an explicit (primary) application spawning and managing processes on that second Node on behalf of the first Node.

Essentially it seems the current starting point of your “Windows service” (per source) is roughly equivalent to a single primary application on a dedicated Node.

Now I suspect it’s unlikely that cramming all 3000 sources into one single Node/Application is that great an idea either - given that a single Node doesn’t distribute - so it’s more likely you are looking for an application that can be deployed on to multiple distinct Nodes, each Node listening to any number of sources via configuration - which all forward their pre-processed/normalized results to yet another Node which executes the application that concentrates/aggregates the results.

Where Next?

Popular in Questions Top

baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
fireproofsocks
I’m working on defining a simple Ecto schema for a table (in PostGres), but I don’t see where I can define a column as NOT NULL. Conside...
New
johnnyicon
Hi all, I’ve just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I’m trying to use Postgres...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
JulienCorb
I am trying to implement my new.html.eex file to create new posts on my website. new.html.eex: <h1>Create Post</h1> <%= ...
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
dblack
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar. I p...
New
PeterCarter
There are pre-rolled solutions for other frameworks that do work. However, Phoenix does not seem to have these. Have people had good expe...
New

Other popular topics Top

aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
marius95
Hello everyone, I try to use an Javascript Event Handler in my root.html.leex file. Therefore I created a function in the app.js file: ...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? Ecto.Repo — Ecto v3.14.0 has exampl...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
aesmail
Hello guys, I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement