How does data denormalization work with the Microservice Pattern?

前端 未结 4 501
后悔当初
后悔当初 2021-01-29 19:16

I just read an article on Microservices and PaaS Architecture. In that article, about a third of the way down, the author states (under Denormalize like Crazy):

4条回答
  •  难免孤独
    2021-01-29 19:27

    This is subjective but the following solution worked for me, my team, and our DB team.

    • At the application layer, Microservices are decomposed to semantic function.
      • e.g. a Contact service might CRUD contacts (metadata about contacts: names, phone numbers, contact info, etc.)
      • e.g. a User service might CRUD users with login credentials, authorization roles, etc.
      • e.g. a Payment service might CRUD payments and work under the hood with a 3rd party PCI compliant service like Stripe, etc.
    • At the DB layer, the tables can be organized however the devs/DBs/devops people want the tables organized

    The problem is with cascading and service boundaries: Payments might need a User to know who is making a payment. Instead of modeling your services like this:

    interface PaymentService {
        PaymentInfo makePayment(User user, Payment payment);
    }
    

    Model it like so:

    interface PaymentService {
        PaymentInfo makePayment(Long userId, Payment payment);
    }
    

    This way, entities that belong to other microservices only are referenced inside a particular service by ID, not by object reference. This allows DB tables to have foreign keys all over the place, but at the app layer "foreign" entities (that is, entities living in other services) are available via ID. This stops object cascading from growing out of control and cleanly delineates service boundaries.

    The problem it does incur is that it requires more network calls. For instance, if I gave each Payment entity a User reference, I could get the user for a particular payment with a single call:

    User user = paymentService.getUserForPayment(payment);
    

    But using what I'm suggesting here, you'll need two calls:

    Long userId = paymentService.getPayment(payment).getUserId();
    User user = userService.getUserById(userId);
    

    This may be a deal breaker. But if you're smart and implement caching, and implement well engineered microservices that respond in 50 - 100 ms each call, I have no doubt that these extra network calls can be crafted to not incur latency to the application.

提交回复
热议问题