1

We're developing some C++ application that analyses strings using some data. The data is large (a few gigabytes) and takes a significant amount of time to load into memory, and timing, as well as stability is crucial for the application.

We're currently discussing the option of splitting our monolithic application into some kind of a "master/slave" relationship, where the "master" would get a string to process, run it through various processes, and return the information back to the user.

Each "slave" would be an executable that is being called and it communicates back to the "master" when it's done.

The "master" would act as a daemon and run in the background continuously, listening to new requests and processes them accordingly. It would also be in charge of initially loading the data into a shared memory space where the rest of the executables would get their information from (read only) and manipulate the input string accordingly.

The data regarding the specific string being processed would be written into an another shared space, or possibly a memory-mapped file, and as it's being processed linearly by each "slave", so write protections shouldn't be really a concern, since for each job there would be only 1 slave accessing it at any time.

Other than harder debugging of the shared memory stuff, what are the problems I am overlooking with this approach?

  • 4
    It's not clear to me why you're suggesting multiple executables rather than a single executable with multiple threads, which should be much easier to manage. Could you elaborate please? – Gus314 Feb 21 at 13:54
  • @Gus314 for stability sake. currently, if some fatal error (crash, infinite loop, etc) happens in one of the threads, the whole system goes down with it. If we make each thread into a separate executables, we don't really need to care much about what's happening there, and a crash wouldn't bring down the whole system. – johndoe123321 Feb 21 at 14:54
  • @johndoe123321 Wouldn't the master process still be a single point of failure? – Robbie Dee Feb 21 at 15:02
  • @RobbieDee the master process is only there to communicate with the user (listen to requests & send final response), load the initial data to the shared memory, and finally, call the slaves into work when they're required. Of course, if this one crashes it will bring the whole thing down with it, but with such minimal functionality we can contain it more easily. – johndoe123321 Feb 21 at 15:05
  • 4
    It sounds like you're currently debugging something that is prone to crashes and infinite loops with real, long-running data of several gigabytes. Splitting into multiple executables is masking the real problem you're facing and, if that's your current test strategy, is likely to lead to a whole heap of extra trouble. Is there a good reason you can't take a step back and design quick, light unit tests to root out these infinite loops and crashes before moving further? – Gus314 Feb 21 at 15:11
1

It seems based on the tags you're interested in two aspects:

  • Memory
  • Performance

I'd say that if the operations the slaves do are pretty self-contained and there is not much communication between master and slaves, the performance aspect will be fulfilled by your master/slave approach. Obviously you'll need to feed all of the data to a slave, but then again the master will have to get the data somehow, and master-slave communication isn't slower than master-datasource communication.

About memory: if the slaves have to allocate lots of memory that will be subsequently freed, it actually might be beneficial to terminate the entire slave process after the operation. If you perform everything in the master, the heap will eventually become fragmented. It may also be the case that the malloc() library can't free all memory back to the operating system, because there is some tiny bit of memory in use inside a massive arena malloc() has mmap()'d.

Also, as you noticed, C++ isn't a safe language and crashes do happen. By having less operations in one application, it might be simpler to investigate core dumps. It's also better design to isolate crashes to a smaller application than to have a huge monolithic application.

Go for it! The Unix philosophy is that one program does only one thing, but does it well. It's a good philosophy. Recently, another term has emerged for this kind of architecture: https://en.wikipedia.org/wiki/Microservices

0

I would suggest looking first for ways how to prepare large data to be crushed in an efficient way. You should look into various techniques or tools that you can find on the internet. If you are doing everything from scratch you might need to return to the design and look into:

  • How the data is being parsed, maybe you need to segment and create a thread pipeline for each segment; (I do not see the problem if you are dealing with strings);
  • Try to reuse the same memory block, meaning that you will need to create a structure; If you to go a little deeper you can try to create your own class template.
  • The concept of Master/Slave is more for used redundancy, what you want to say is a kind of launching child process.

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.