1

I recently encountered a microservice architecture with 50+ services communicating with messaging using publish/subscribe on a topic. I have previously worked with event based systems where each service creates and dispatches its own event, so I was suprised when I realized this(theese) system(s) were actually sharing a lot of message types.

Here's a short example from a fictional book store.

Message publishers

  1. The owner can publish new Book messages from the OwnerService.
  2. Publishers can publish new Book messages from the PublishersService.
  3. Writers can publish new Book messages from the WritersService.
  4. The ShelfService can publish BookPlacement messages
  5. The BookPriceService can publish BookPrice messages

Message subscribers

  1. The OwnerService listens for Book messages
  2. BookPriceService listens for Book and Price messages
  3. The ShelfService listens for Book messages to add to the shelf
  4. The SearchService listens for BookMessages, BookPlacement and BookPrice messages

To me, this seems like the messages being re-used are causing a few issues.

Each service persists all of the data in the messages they receive. Not only the data that service is interested in.

There are also dependencies within the services that require the messages to be received in a certain order. I.e. the BookPriceService requires a Book message before the Price message or the Price message is discarded.

Is it a design smell where multiple message publishers share the same message type? Would it be preferred to have each service publish its own message type?

Perhaps needless to say but all messages share the same Topic and are separated by message-type filters.

Related: Same Event types for multiple micro-services

3 Answers 3

7

Ehhh, maybe a little one. But the other end of the spectrum (dozens of messages all with the same payload) is much worse in my experience. Harder to grok, harder to maintain, harder to manage. Lots of non-DRY over-engineering.

I don’t care so much about the single topic. That has its benefits, though they’re limited. I don’t care so much about the full payload. That has a lot of benefits for dealing with out of order messages and concurrency.

What I might worry about is “wide” messages. Messages that are responsible for multiple things. Messages that had “just one more thing” tacked onto them.

And what I really care about is the temporal coupling you talk about (messages needing to be processed in order). That is a sign of a poorly designed system - one that will fall over and die since those sorts of problems tend to increase super-linearly with growth.

3

Yes I think it can be a design smell. For example:

I think the issue your example displays is a faulty separation of concerns. For example, when looking at your example, I have to ask some questions:

  • Does the Shelf Service only shelve books that are owned by the Owner Service?
  • Does it make sense for the Shelf Service to try to shelve books that were just released by the Publisher Service?

and more along those lines.

As I look at what you described, there are multiple services that deal with "Books". However, what might be really at issue is PurchasedBook, PublishedBook, etc.

Sometimes that separation of concerns can simply be managed by having separate queues. The "Book" message on the Purchased queue is inherently different than the "Book" message on the Published queue. You can route those queues between services and keep them as separate things.

Design Smell doesn't always mean Design Problem

A design smell isn't always indicative of a bad (i.e. failed) design. You have to go through and vet the design and make sure there are real problems that should be solved. For example:

  • Asynchronous systems cannot guarantee message order unless the same producer generates both messages. As long as two autonomous services generate the messages you cannot guarantee message order.
  • Is it clear where failures can be introduced, and are those failures by choice (i.e. design), or is it just something that happens sporadically.

If everything checks out, it isn't necessarily bad design, but at the very least a confusing one. If things are working, you might find that "fixing" the design will lead to system instability until you resolve all the edge cases.

0

If one is using a language that permits such a thing, one could include one specification for a shared data type, but then define multiple types that share that same specification. This would combine the advantages of using a shared data types (make it easy to change both simultaneously by changing the specification) and separate data types (make it easy to change one without changing the other by making a copy of the specification and making one of the data types use it rather than the original), at least unless or until it becomes necessary for the types to be split.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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