1

Imagine a large node.js app with a multi-purpose api for mobile and frontend with a serving static files, with a websocket server, lot of cron jobs and workers. Basically I can horizontally or vertically scale a whole app, use a load balancer and so on.

But from a perspective of a business logic, whole app is one big "bundle" where some parts are used more than others, also some parts have bigger impact on a performance of app than another. For example, mobile API may be used 100x more than some cron which starts 1 time per hour to make some cleanup. So is it necessary to scale whole app?

Isn't it better to scale app to separate modules and scale only needed? For example

  • mobile api
  • FE api
  • crons and workers
  • websocket
  • whatever...

If so, what is proper way to handle business logic? There is a parts of code I would need in every submodule of application, for example database models, migrations (seeders?), maybe I would need some general functionality, like some specific utils functions or enum definitions. So I can create git submodules for them, but there is risk it will be too much complex to handle 4-6 git repositories with a 2-4 git submodules and handle whole app in multiple environments (dev, stage, uat, prod). Are there some others caveats of this approach? Or is it unusable?

I dived into waters of internet and searched for some resources for example node.js best practice, scaling node.js, scaling node.js, good scaling practice but it not fully answered all my questions.

  • 3
    If you haven't read about microservices or Domain-Driven-Design, you might find those perspectives helpful when thinking about this. Many of the considerations for Node would be independent of the language and runtime, and in particular many of the questions you raise or imply exist for nearly any large-scale application, so general architectural advice should be helpful. – Will Cain Jul 25 '19 at 21:41
2

I believe that there's no one right answer for every scenario, and you don't have enough information here for someone to give you a complete answer, but what I can give you is a way to think about your problem that will hopefully help you answer your own question for your specific application.

First, you need to look at your monolithic project and figure out what parts of it are actually better as applications and which part are better as libraries.

What do I mean by that? Well, an application is something that you can reasonably conceive of as something that would be running independently, doing some kind of "job". Maybe that "job" is listening for and responding to network events (e.g. a REST API request). Maybe that "job" is watching the clock and performing some tranche of work (e.g. a cron job that re-indexes your database periodically or processes email notifications).

A library, by contrast, is a chunk of code that you want to allow to be reused by multiple applications. That might be your business logic, validation logic, a security framework, etc.

Each of these "things", whether they are applications or libraries, should be versioned as a Node module and stored in their own git repositories, and published to your company's artifact repository each time you make a release that you want adopted (e.g. artifactory, or your self-hosted NPM, or the public NPM if you're open sourcing it).

Your libraries, then, are referred to in your applications (or, conceptually, in other libraries) via your package.json, and drawn in using the npm infrastructure. Your applications, in contrast, are built and deployed as packages that become running processes somewhere, maybe as individual docker containers or using systemd on a Linux box, etc.

As you scale, then, you're really just replicating your applications horizontally based on how much they're getting used. Again, what's the right "size" for each is something that is really more art than science, but the rule of thumb is to make it as small as possible, and no smaller.

2

As noted in discussions at the recent O'Reilly Software Architecture Conference, it is easier to split services than to join them. So although you raise questions about independent scaling that may indicate a microservices architecture, you may also benefit from erring on the side of one ("monolith") or a small number of services to begin with. If you start with multiple services, you'll have overhead of data management, message passing, and service orchestration (Kubernetes?) that you otherwise would not with a monolith.

If you do break apart services, your bullet list of "mobile api..." looks like a good start. Consider "bounded context" from Domain Driven Design.

What database(s) are you considering? Can you live with the performance of a vanilla SQL database (i.e. CA or CP in CAP)? If so, that's a simple, well-blazed trail. If you go this route you would not really benefit from microservices because your services share a single database anyway. If instead you can tolerate eventual consistency (AP from CAP) and thus choose to go with a common distributed NoSQL database (e.g. Cassandra), that is more amenable to a microservices architecture, with each service responsible for its own data (e.g. Cassandra keyspace), and you can use a message layer such as Kafka to communicate state changes across services. Distributed databases are generally more difficult to administer and also (due to message passing and denormalization) to write services for. Does that matter to you?

Regarding shared libraries, that is definitely a tried and true way to reduce effort across service implementations. Having npm module, possibly repo, per library is a good idea.

From a pragmatic standpoint, to get started on all this, a couple ideas: You could try a monolith with the understanding that to scale you might have to split it apart later. Or you could try your hand at like 2 really simple services and try following the microservices pattern and see how you like it before committing. How to choose? The first could probably get you to a demo faster. The second might save you time in the long run -- if you make a good decision on how to break down your services (that isn't trivial to do). The first is probably lower risk.

  • I think what the OP is talking about is an existing application that is already built as a monolith, and how to get started in splitting it apart. I didn't pick up on the explicit desire to become a real microservice architecture, just a desire to being able to make more granular scaling choices. – Paul Jul 26 '19 at 0:12
  • I basically looking for way, how to handle new projects in future. I have plenty monolith projects but also some microservice bases (also use docker everywhere). In my point of view, microservices are too complex to handle, but maybe my approach is wrong, thats the point of a question. Truth is, if I would use a noSQL database, it would make my live easier, but 90% of my projects requires a relation database. – l2ysho Jul 26 '19 at 5:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.