This interview was done for our Microservices for Startups ebook. Be sure to check it out for practical advice on microservices. Thanks to Oleksiy for his time and input!
Oleksiy Kovyrin is Head of Swiftype SRE. Swiftype is the leading platform for Site Search and Enterprise Search that powers search for thousands of enterprises and websites. Swiftype is an Elastic company.
For context, how big is your engineering team? Are you using microservices and can you give a general overview of how you’re using them?
Our team is relatively small. We have about 20 people in total. Three focus on technical operations, and the rest are engineers and designers. Our main application is a multi-functional monolith (deployed in different configurations to perform different tasks), but a number of its functions have been extracted into microservices over the past few years: secrets management, asynchronous content processing (business-specific), etc.
Did you start with a monolith and later adopt microservices? If so, what was the motivation to adopt microservices?
We started with a monolith and are still heavily invested in building out and maintaining a large central application containing most of our core business logic. The application is structured in a way to support adding and independently maintaining different APIs relying on a very mature set of internal abstractions for common functionality like authentication, access control, database access, logging, etc. APIs within the monolith application are used by different business applications and could very well be considered separate services.
Aside from the main app, we have a number of highly-specialized microservices - dedicated applications handling very small number of tightly-focused tasks. Those have been introduced at different times of the main application lifecycle and with different purposes, but usually the reason behind their development was at least one of the following:
- Different platform requirements – our main application is a Ruby app. That brings with it a lot of very useful features like approachability and very mature ecosystem of libraries, etc. Unfortunately, there are cases when Ruby ends up not being the best tool for the job and we use different technologies to implement more efficient services. One of the most popular options here is JRuby - Java-based implementation of Ruby that gives us real multi-threaded concurrency without the global interpreter lock and much more mature memory management model.
- Shared components – a few of our internal microservices have been deployed as a part of the common services infrastructure and are used by multiple business applications to implement things like secrets management or authentication.
- High specialization – a couple of our microservices (or, rather, dedicated applications separate from the monolith) have been developed mostly because they had a very clean and small API for interacting with the main application and their usage of dedicated backend databases, queues, etc made them perfect candidates for splitting off from the monolith.
How did you approach the topic of microservices as a team/engineering organization?
Most of the microservices in our infrastructure have been introduced organically. The team felt like it made sense to split a component off from the monolith and we would make a call on it.
In terms of introducing new technologies into the stack, we have a very strict internal policy to limit the size of our stack. We deliberately choose “boring technology” and try not to introduce new pieces until we are absolutely sure the task could not be solved by an existing component. One important issue we are very aware of when it comes to introducing microservices is their observability and management in production. Each new service added into the infrastructure increases the amount of resources you need to operate it. This is one of the most important issues we consider when making a call on splitting functionality from the monolith, and limiting the amount of different technologies in your stack helps a lot with streamlining deployment and operations of multiple services.
Have you broken a monolithic application into smaller microservices? If so, can you take us through that process?
Based on our experience, we tend to develop our features within the main monolith application where we have access to a lot of important and very mature components like auth, database access layer, etc. If we feel that a feature should be extracted into a dedicated service, it is intentionally developed as an isolated API within the monolith and then, when it makes sense for the team (see the reasons for introducing microservices), we split it into a separate repository/application/service.
How do you determine service boundaries?
One of the main foundational principles we use when developing new services is that they should not cross database boundaries. Each service should rely on its own set of underlying data stores and should be the only entry point into that data store from the business logic layer. This allows us to centralize access controls, audit logging, caching logic, etc within our applications and limit the scope of database access down to a single application. Focusing on database relational model helps with identifying potential components that could be easily deployed as separate services – if a subset of your database tables/collections has no or very few connections to the rest of the dataset, it is a strong signal that component could be isolated into a separate API or a separate service.
How have microservices impacted your development process and your ops and deployment processes?
As I mentioned before, every time we consider introducing a new service, we have to consider the operational cost of doing so. Each new service adds to the complexity of the infrastructure and makes it a bit harder to reason about service relationships within the system. One of the biggest wins in operating our infrastructure was a strong focus on standardization across all aspects of the development and deployment process. We have introduced libraries, frameworks and systems for configuration management, secrets encryption, vulnerability management, CI, deployments, monitoring, logging, etc. The more we standardized that common functionality, the easier it became to deploy and operate additional services.
How have microservices impacted the way you approach testing?
Turning a feature into a microservice inherently forces us to standardize its external interfaces (APIs) and it makes it much easier to test it in isolation. This means much faster CI builds, tighter feedback loop for engineers which results in faster development cycles. One important issue we have to keep in mind while working with microservices is API stability and API versioning. To avoid breaking applications depending on a service, we need to make sure we have a solid set of integration tests for microservice APIs and, in case of a breaking change, we have to provide a backwards-compatible way for clients to migrate to a new version at their own pace to avoid large cross-service API change rollouts.
How have microservices impacted security and controlling access to data?
Introducing microservices with their own data stores allowed us to reduce the scope of our database access and application credentials. Using service-level access controls gives us more flexibility in ways we want to control access: in some cases a shared secret is enough and for some services we can implement very sophisticated systems with token authentication, audit logging, etc.
Have you run into issues managing data consistency in a microservice architecture?
We never allow cross-service database access, so all of our consistency controls are performed within the service that “owns” the database. In some cases, this leads to intentional denormalization of the dataset to ensure data consistency within a specific database, but we accept that as a feature because it makes the service less reliant on external dataset dependencies.
Thanks again to Oleksiy for his time and input! This interview was done for our Microservices for Startups ebook. Be sure to check it out for practical advice on microservices.