14

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?

4
  • 3
    I think it's going to depend on what your specific functional and non-functional requirements are. Mar 31, 2017 at 4:23
  • Different databases but the same instance is reading it? Doesn't that violate the regulatory requirement too?
    – Jimmy T.
    Apr 2, 2017 at 13:11
  • Option 1 doesn't seem too aligned with the Microservices architecture style.
    – Laiv
    Apr 9, 2017 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, 2017 at 17:06

3 Answers 3

5

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.

7
  • 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, 2017 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? Apr 20, 2017 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, 2017 at 18:16
  • This is one application talking to two databases. Apr 20, 2017 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, 2017 at 19:57
1

I would prefer Option 1 as this would make the application completely stateless. The db Url mapping can be passed as a part of configuration. Making the application stateless would mean easier failover and easier routing (load balancing). Option 2 would require application to be aware of region. For e.g. If one of your instance goes down, You cannot simply route the requests of that country to other instances. You need to have another instance speciifically to takeover the instance which went down to provide HA and your gateway has to be made aware of that. Think about doing this for all countries. Although there are other factors which might affect your decision making

  1. Have you deployed the applications in different region to cater latency problems from each country. In that case you should go for Option 2.
  2. Does your application have many features which are specific to a country/region or If you are planning to build more features/customizations specific to some countries only. In that case having multiple microservice per country can reduce your impacted customers in case of a release upgrade (Option 2).
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 and acknowledge that you have read and understand our privacy policy and code of conduct.

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