Few notes on Microservices
- At February 17, 2020
- By Alexander Yermakov
- In Architecture
0
I got a notification email from Medium.com saying that one of my comments on Microservices related article was attracting attention. It’s been a while since I’ve made that comment, so I’ve reviewed it and figured it makes sense to copy it to my personal page for reference sake.
With that comment I wanted to remind about the importance of SOA and indicate that various implementation patterns should be thought out, not simply adopted and followed just because someone else did it this way.
Read More»Sizing your Microservices
It’s common to hear that “microservice should be small” or “microservice should not be too big”. Well, this is not a very precise metric to go by. Very often teams start creating tiny executables each dealing with a very small concern, and sooner rather than later they run into lots of issues – tight coupling between microservices, distributed transactions, nightmarish development and release process, etc.
To be able to figure out what’s the right size for your microservices we need to go back to the fundamentals – in this case Domain Driven Design and its concepts of Bounded Context and Aggregate. We have already discussed microservices boundaries, and the sizing comes as a flip side of that discussion.
Once we have done a first pass at analyzing our domain model and have some rough bounded context identified, we are ready to look deeper – at DDD Aggregates, which would be our smallest possible releasable and deployable artifacts. We shouldn’t go smaller than a DDD Aggregate as that is our primary way to ensure transaction consistency in a given bounded context. On the flip side, should we go that granular with all of our microservices or should there be more coarse sized microservices?
My recommendation:
- Analyze the bounded context of interest and identify all of it’s aggregates – this would provide you with a list of potential releasable components
- Bounded Context analysis is an iterative process, so identification of aggregates will be happening over the course of system development as business domain understanding is growing, implementation of business processes is progressing.
- Determine which of the aggregates have their very own scalability, availability, security, etc. non-functional requirements – these, most likely, will become standalone microservices
- Determine which aggregates can comfortably co-exist in a single releasable and executable module – their scalability, security, availability, etc. non-functional requirements are similar and they wouldn’t affect each other too much
- In some cases we can have all aggregates (complete bounded context) in a single microservice – nothing is stopping us from doing that, really
- Take into account team ownership over bounded context. In most cases I would recommend having a single team own a bounded context for many reasons, however if there is more than one team involved – that would introduce another dimension of which components should be independently developed, released and managed.
Since we are building highly decoupled, autonomous components, the following set of checks may prove to be helpful to validate the breakdown:
- Transactions are not split between microservices – each request is processed and results in a persisted state change within the boundaries of a single microservice
- Eliminating distributed transactions
- Each microservice can be developed, versioned, released, scaled independently
Cross service communication in SOA
Creating a distributed software system based on Service Oriented Architecture (with Microservices implementation technique as a possible approach, more on this here) very quickly presents a question of communication between the services in the system. Communication choice may greatly affect non-functional requirements such as stability, availability, reliability, maintainability and other “-abilities” of the system.
To increase your chances of success it is important to understand that SOA based software systems require communication that promotes autonomy, spatial and temporal decoupling, reliability.
Let’s look at a point-to-point (direct) communication pattern, which often is promoted by various vendors and Microservices evangelists. The premise is very simple – create microservices that “do something small” and let them talk to each other via some sort of an RPC protocol (underlying technology doesn’t really matter). Let’s look at how that behaves and quickly identify potential pitfalls with such approach (see video below):
As you can see, there are few major issues with such communication style:
- Spatial coupling – requires services to be aware of each other, and able to reach out to each other
- Temporal coupling – requires services to be present at the same time in order to ensure successful operation
- Failure of a single component may take down most if not all of the system, causing cascading failures and unavailability of functionality to customers
- Development and deployment coupling – high probability of a change in one service causing cascading changes in other services, complex orchestration during development, testing and deployment into production
- High probability of introducing distributed transactions for situations where services boundaries are not properly defined
The disadvantages are quite obvious yet there are a lot of projects that default to this style of communication with engineers blaming the failures (caused in part by this choice) on selected implementation technique.
Now, if we consider services boundaries and the factors that come from that, we quickly realize that our needs for cross-service communication are greatly reduced – our business transactions are encapsulated within a single module that works or fails on its own, with no dependency on anything else. This means – a service never needs to reach out anywhere outside of its boundaries to fulfill its purpose.
Once we consider such service autonomy, the communication needs change dramatically. This is where Event Driven Architecture comes into picture and the synergy of SOA and EDA produce a powerful combination – ability to notify the system about a change in a service’s state via events, which promotes much lower coupling between components.
Let’s look at a pretty standard sequence of steps happening in such environment:
- A business transaction gets initiated via a request from a user or another component / system
- A service fulfills a business transaction, which results in the change of its state.
- The state change is announced – anyone interested in this specific change gets a notification with details of the change
To enable EDA we need to have an infrastructure that provides a mechanism to publish and consume notifications. One of the most obvious choices in this situation is a message broker or a service bus.
The benefits of such approach:
- Service autonomy is much stronger promoted due to constrains imposed by communication style
- Spatial coupling is no longer present – services don’t need to know about each others location
- Temporal coupling is eliminated – there is no need for one service to be running at the same time as others
- Failure of a single component leads to a degraded system performance, not a cascading failure of multiple components
- Development time coupling is greatly reduced, deployment coupling is virtually eliminated
- Distributed transactions are still possible as they are a result of an incorrect services boundaries, however this communication style makes them more obvious and visible, thus allowing for design corrections
What are the most obvious drawbacks of introducing messaging into the mix? Well, there are at least the following:
- There is another technological artifact to deploy, monitor, maintain, which really means extra cost.
- If your organization doesn’t have ESB (message broker) this would be a new piece of technology
- Monitoring tools and processes to ensure issue resolution
- Communication pattern requires different ways to respond to failures – dead letter queues, component recovery, etc.
- This is a compromise to enable overall greater system availability and reliability
- Different programming mindset and model
- Really is needed regardless to ensure successful design and implementation of an SOA based distributed software system
Team structure for successful distributed software system implementation
Goals
Development of complex distributed software systems is not an easy task that requires quite a lot of investment. So, why do it? Here are some of major business reasons:
- Improve business agility – time to market for products, features, fixes
- Shorten time to market by releasing small and often
- Increase velocity by delivering many features all the time
- Decrease investment into software development
- Decrease wasted effort, time
- Simplify and improve the maintenance of the codebase, which accounts for the biggest chunk of system cost
Problem
Most software systems are built as monolith – a very interconnected, interdependent collection of components and modules, which increase complexity of the implementation with time, while hurting business agility. With the move to distributed system development it is crucial to understand how not to fall into the same trap – there is a lot of negative feedback from teams trying microservices and running into cross-service dependencies, issues with data ownership where one service does something to the data of another service, distributed transactions, etc.
One of the aspects that may not be overlooked when going into distributed software development (microservices as a potential implementation technique) is team structure, source code organization and ownership.
Most engineers and teams are used to organize their team structure following layered approach. So you end up with DBAs who rule relational data stores, Middle Tier team(s) who work on implementing business logic and maybe even application logic (unless that’s another layer that’s managed by other team), Front-end team(s), Integration teams, etc. You get the picture.
What is the normal development and release process with such team organization? It is heavily reliant on cross team coordination of schedule and implementation, various integration efforts, testing and QA, “over the fence” sort of mentality that becomes a real issue in any non-small organization. What are the chances of business ability to release small and often? Quite low as you understand.
Solution – Feature Teams
Over the past few years microservices became a very popular buzz word that attracted a lot of engineers and business people alike for these exact reasons – promising to deliver development experience that addresses business needs of agility, cost and value.
Once your organization is in a distributed software realm it really needs to start some major re-organizational efforts. Development teams can no longer be implementing bits and pieces of the functionality asked by the business – they really need to become self sufficient, autonomous and own the full vertical of the implementation of a feature. Without such re-org an organization is simply not going to be successful in development of any complex distributed software system.
Development must revolve around features – top to bottom, so one team can start it, work on it independently, complete and deliver it. A single team owns that feature. That sense of ownership is a great positive for everyone – business can expect teams to do their best to make it work as the feature implementation is the reflection of their professional abilities; development teams take pride in their work, feel a sense of accomplishment, deliver real, tangible value to the business.
Team structure should be based on features. A single team owns and builds code for front-end, middle tier, integrations, back-end. They own it all, they don’t ask anyone else to do their part in order for this team to be successful. And this brings us to another point – how a team can be autonomous, independent? What if the feature they are tasked to build needs some other service? Well, it’s time to look at the foundation of distributed software systems – Service Oriented Architecture (more here). It is this architectural style that gives us a concept of autonomy, ownership and encapsulation – an SOA Service. So, if a team owns a Functional SOA Service implementation, they become really autonomous, independent and able to deliver features asked of them. Each feature, most likely, is going to be an implementation of a DDD Aggregate that belong to the Functional Service the team owns. There is no need to involve any other team – even when consuming another service’s contract the coupling is much lower and promotes independence.
KeePass on Linux. 2018 edition.
- At March 01, 2018
- By Alexander Yermakov
- In Linux Software
0
It’s been couple of years since I’ve switched to Linux. I’ve been running Ubuntu for most of these two years after having too many stability related issues with Mint. When I switched over from Windows I was missing one critical piece of software that, I believe, everyone should use – a password manager. I’ve been a long time user (many, many years) of KeePass, an open source password manager, that served me really well. With the switch to Linux I had to go through some fun of building a version of KeePassX from sources (more on that here). The software was OK, nothing to brag about. It’s a bit clumsy, a bit outdated, got some bugs. And, unfortunately, it seems as nobody really maintains it.
Fast forward to 2018 and I’ve almost fully switched to KeePassXC, which has a much better UI, more feature rich, has active members working on it. And I haven’t run into any bugs, yet. Hopefully the guys behind the project continue their great work and users such as myself can enjoy the software.
Microservices. The boundaries.
One of the problems with designing and implementing a distributed software system using microservices implementation technique is figuring out the boundaries of microservices. And, indirectly, the size of these artifacts.
What happens if the boundaries are incorrect? You get coupling between various components (microservices) – both spatial and temporal. Such coupling can undermine a lot of implementation and delivery aspects. Some of these include inability for one team to fully implement a feature due to a dependency on some other service that implements something they require, inability to release without coordination with other teams, issues when releasing interdependent components may and will result in instability, loss or corruption of data, emergence of distributed transactions, etc. Many tried, many failed and questioned the concepts rather than their misunderstanding or mistakes.
So, is the concept flawed? Is there something that can help us deal with such issues? As always we need to start with the foundation. In this case our main foundational concept comes from Domain Driven Design – an Aggregate.
If you don’t know what Domain Driven Design is, or have a very basic, high level knowledge of it, it is crucial for you to start digging deep and wide, over and over, to start understanding what it’s all about. It is a philosophy of successfully modeling complex business domains and implementing those in software. There is a lot written on the subject and I would recommend to keep reading.
An aggregate is a very important, yet somewhat elusive concept that takes time to fully grok. At it’s core DDD Aggregate ensures the boundary for transactional consistency. When a transaction completes all entities represented by an aggregate must be in a consistent state – any business rules governing the state must be met, the data must be fully stored in a data store and the aggregate should be fully available for any other use case. From the implementation point of view, an aggregate is one or more classes representing an entity(-ies) that govern the state and the rules associated with it.
With the concepts of DDD Aggregate in mind we can now approach the sizing of a microservice and define its boundaries. Approaching the design thinking about the business process that drives the implementation we really localize the scope of change, encapsulate the logic and state. The implementation become autonomous, we remove any potential for cross-service requests, complex orchestration goes away, unnecessary generalization of code is not a factor anymore. The codebase becomes simpler, more robust, easier to reason about. It is easier to test, easier to maintain all of which really yields greater business agility – exactly what business asks of engineering.
So, why do people run into issues we’ve mentioned at the beginning of this post? It usually happens when implementation is based on technical concerns or driven by popular but often superfluous concepts such as code reuse, DRY, generalization, centralization of some logic. With this the chances of incorrect breakdown of business process into reusable parts may and will result in the issues that lead microservices solution to become overly complex – invalid services boundaries, coupling between services, emergence of distributed transactions, dependencies on other components and teams, lack of agility. Pretty much everything that the concept promises to solve and the reason you’ve decided to adopt it in the first place.
Disclaimer: I am a strong believer that microservices is an implementation technique, not an architectural style. As such, without proper foundation it most likely will cause more harm than good. More on this here.
Microservices without fundamentals
Couple weeks ago an article was brought to my attention. An article with a catchy title – “The Death of Microservices Madness in 2018”. Since I am greatly interested in software architecture for distributed software systems such statements are definitely too bold to be ignored.
One of the biggest misconceptions about Microservices I’ve observed is that people accept the idea as something holistic, self-contained and self-sufficient. In reality, Microservices is just an implementation approach for distributed systems architected and designed according to much wider concepts – Service Oriented Architecture, Event Driven Architecture, Domain Driven Design. Looking at microservices in a disconnect from these architectural styles is a mistake that will become costly and may lead to an ultimate failure. More on this here.
Read More»Microservices as a self sufficient concept
Over the past few years microservices became a very hot topic in development communities. More and more people talk about the approach and attempt to build large software systems according to various patterns published by enthusiasts. The buzz words (and buzz concepts) are a big driving force in software development, which in a lot of cases results in failures, as people simply don’t research and learn the subject deep enough to be able to make informative decisions. I think one of the concepts suffering from such high level approach is distributed systems development, which some are trying by going with microservices model.
I am greatly interested in software architecture for distributed enterprise-level systems and I believe that microservices concept has not only been greatly misunderstood by many, but also is flawed in the way it is presented – as a self sufficient “architecture”. However, microservices is merely an implementation approach and without proper fundamentals will not magically lead you to success. What are those fundamentals you may ask? Well, read on – this is not going to be very long, even though each of the fundamentals is a very large subject.
Read More»Aeon MQ7 Kodi и русские шрифты
- At February 13, 2018
- By Alexander Yermakov
- In HTPC, Kodi
0
Одним из больших улучшений медиа системы на основе Kodi является возможность изменять внешний вид с помощью разнообразных skin-ов. Я использую Kodi / XBMC вот уже много лет, и на протяжении долгого времени моей любимой skin остаётся Aeon. На данное время (начало 2018 года) последней версией является Aeon MQ 7, которую разрабатывают активисты в Бразилии. К сожалению, по умолчанию, русский язык толком не поддерживается – есть возможность выбрать шрифт, отображающий русский язык в основных меню, однако этот шрифт сильно отличается на оригинального, и не работает в некоторых экранах.
Мне попался архив с русскими шрифтами для Aeon MQ 7 – Aeon MQ7 Russian fonts
Для установки этих шрифтов, вам надо заменить оригинальные шрифты с тем же именем в папке /kodi/addons/skin.aeonmq7/fonts. Я использую LibreElec, на основе Linux, так что эта папка находися в домашнем каталоге пользователя root (вам надо подключиться по ssh и переписать шрифты в данную папку).
После установки шрифтов зайдите в настройки и выберите “стандартные” шрифты для skin – после этого интерфейс обновится и будет использоваться шрифт с поддержкой русского языка.
Windows update breaks GRUB on dual boot machines
It’s pretty widely known that major Windows updates may affect dual boot machines. This is what I’ve run into with my dual boot machine – Windows decided to install a major update and in doing that broke GRUB that managed my boot options.
Few google searches later I’ve run across many ways of addressing the GRUB issue, which seem to be stemming from various failures.
What I was greeted with was GRUB command line with the following message:
error: file ‘/grub/i386-pc/normal.mod’ not found
and the prompt:
grub rescue>
In short, the following is the sequence of steps I needed to take:
- First, run this command to see the list of disks and partitions:
ls
- You’ll get a list of devices and partitions in the form of: (hd0), (hd0,msdos1),etc.
- Most likely your GRUB root partition is on (hd0)
- You need to figure out which partition that is.
- Run the following command:
ls (hd0,msdos0)
- If you get “error: unknown filesystem”, then move onto the next partition –
ls (hd0,msdos1)
- If you get “Filesystem is ext2” then you found one of Linux partitions – you may have more than one on a single drive, obviously. Most likely your root partition is the one with the smallest index.
- Run the following command:
- Run the following commands to run GRUB (assuming your root partition is msdos1):
set boot=(hd0,msdos1) set prefix=(hd0,msdos1)/boot/grub insmod normal normal
- At this point you should see your GRUB screen, which allows you to pick the OS to boot.
However, this is not all. Following these steps you won’t “fix” the issue – you’ll just manually run GRUB. To permanently fix the issue and make sure you don’t have to follow these steps on every single boot. Assuming your root partition is on /dev/sda, run the following (note that it’s all about the device, not a partition on it):
sudo grub-install /dev/sda sudo update-grub
So, at this point your system should be back to normal.
One more comment – if you run into this while upgrading Windows to the next major version, it doesn’t make sense to finalize the fix until Windows is done with its reboots (it does it few times during the upgrade), as it may damage GRUB again.