13

We're in the process of migrating a monolithic application to microservice architecture. Due to some regulatory requirements, we have to keep client's data from different countries in separate (country specific) databases. I.e US db for US customers, UK db for UK customers...

The following designs that we are considering are as follows:

Option 1: A multi-tenant application with hibernate multi-tenant support that can be scaled to N number of times dependending on demand (think of kubernetes pods). A single instance of this application will be able to connect to all databases.

Option 2: Deploy 1 microservice instance per country database. With an API gateway in front of them routing traffic

If you were to design this type of system, what would your choices be?

  • 3
    I think it's going to depend on what your specific functional and non-functional requirements are. – Robert Harvey Mar 31 '17 at 4:23
  • Different databases but the same instance is reading it? Doesn't that violate the regulatory requirement too? – Jimmy T. Apr 2 '17 at 13:11
  • Option 1 doesn't seem too aligned with the Microservices architecture style. – Laiv Apr 9 '17 at 19:43
  • You mention Kebernetes but it's not clear whether you are using containers or not. If you are doing this with Docker (for example) you would simply create an app that connects to a database. Then when you startup the container and specify the connection details via parameters and/or configuration. Having one application that connects to many like databases only creates potential issues. It doesn't add anything good to the design. – JimmyJames Apr 20 '17 at 17:06
4

I think option 2 is not a bad one, but may not be needed. Micro services are for letting you deal with the needs of multiple applications.

A big factor here, is if there is any difference between the two schemas, and if there ever will be in the future.

Usually, I think using interfaces for repositories is unnecessary; however, it might be worth the effort in this instance. Repository factories will be important for you.

My issue with option 1 is that it is too specific. You should be able to go from the setup which you described, to two separate instances each pointing to its own DB easily. The application should NOT CARE WHERE IT IS GETTING ITS DATA FROM.

While the schema does not differ for your two different database, you can have one repository easily deal with both, without the application knowing the difference:

public class MyEntityRepository : ISavesMyEntity, IGetsMyEntity
{
    public MyEntityRepository(string connectionString)
    {
       _connectionString = connectionString;
    }
}

public class MyEntitySaverFactory
{
    public ISavesMyEntity GetSaver(User user)
    {
        if (user.IsUK)
            return new MyEntityRepository(Config.Get("UKConnString"));
        if (user.IsUS)
            return new MyEntityRepository(Config.Get("USConnString"));
        throw new NotImplementedException();
    }
}

//USE
ISavesMyEntity saver = factory.GetSaver(currentUser);
saver.Save(myEntityInstance);

If the DB schemas ever become disparate between the US and UK, then you would then split the functionality into two completely different repositories. This would be easy, since all you would have to do is change your factory.

  • 1
    I don't get why you need this factory. Why not just pass in the path to the configuration details on startup? With this you need to modify the code every time you want to add a new region/country. – JimmyJames Apr 20 '17 at 17:08
  • 1
    The issue here is not dealing with users in seperate countries... it is dealing with different databases. what if there have different schemas? Why should the consuming class be responsible for figuring out where to get the DB connection string? – TheCatWhisperer Apr 20 '17 at 17:30
  • I don't know what you mean. Nothing in the code should be responsible for 'figuring out' where to get the connection string. It's configuration. I don't see why this is any different than using configuration for QA databases vs. production. You don't put if statements in code for that, do you? – JimmyJames Apr 20 '17 at 18:16
  • This is one application talking to two databases. – TheCatWhisperer Apr 20 '17 at 18:39
  • I think you misunderstand the problem: "we have to keep client's data from different countries in separate (country specific) databases" There is no requirement for a single application "instance" to talk to two databases. I doubt it's just two DBs. The OP probably meant "e.g." when they typed "i.e." – JimmyJames Apr 20 '17 at 19:57
0

I would go with the second option, it gives less friction in development and deployment.

This will allow for better scalability and availability and better zero downtime deployment options, as you distributed your app to 1 (or at least one) instance per region as opposed to at least one for the whole world.

As the requirements change you might have more region specific business logic and possibly data changes as well, I would try and split the code and it's data per region, and avoid sharing region specific business logic (you may end up sharing some core code).

Make sense?

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.