Microservices in practice: Architectural Pattern Languages. ludotheca-share-mesh

MarcoMarco
6 min read

Github repo: https://github.com/marco13-moo/ludotheca-share-mesh

Architectural Pattern Language

The microservice architecture pattern language was chosen in order to guide development of the resource-sharing system in order to meet the architectural decisions and characteristics of microservices [3:23]. This language is divided into 3 pattern layers being:

  • infrastructure

  • application infrastructure

  • application

Each layer comprises a multitude of groups and further sub-patterns [3:24]. Furthermore, an additional layer, the communication patterns layer, forms part of both the infrastructure and application infrastructure layers.

Architectural Decisions Made/Design Principles Chosen within the Context of the Architectural Pattern Language

Application Patterns

Decomposition By Sub-Domain Pattern

Resolves decomposition issues

  • Decomposition by subdomain is the process of scoping services in accordance to Evan's domain-driven model. [3:23] This entails defining the scope of a domain model, known as a bounded context. Once defined, the domain can be divided into sub-domains. Such a process may be recursively executed till a specified level of granularity is reached.

Database Per Service Pattern

Resolves issues in achieving the loose-coupling of microservices

  • Each service was provided with its own datastore. This illustrates loose-coupling of each service as well adherence to API-only communication and services owning their own data. [3:12].

Saga Pattern - Orchestration vs. Choreography

Resolves data consistency maintenance

  • Orchestration Saga Pattern was chosen.

  • If there is a presence of transactions that span multiple services owning their own database- the saga pattern may be used in order to maintain data consistency across microservices [3:111].

  • The choreography-based saga pattern is instantiated with a sequence of local transactions co-ordinated via asynchronous messaging.

  • The orchestration-based saga entails controlling microservice elements in a coordinated manner.

Testing

  • Unit testing was integrated as sociable test units in order to test both the microservice's internal service subdomain, it's dependencies as well as it's relation to the repository subdomain [3:308] .

Application Infrastructure Patterns

Cross-cutting Concerns Pattern

  • The resource-sharing system implements a microservices chassis pattern.

  • The microservices chassis pattern is defined as a collection framework that enables rapid microservice construction as well as cross-cutting concerns such as health checks and externalized configurations [3:379].

  • This pattern and framework suite was used as the Spring family adheres to the objective criteria of using a conservative technology stack whilst being familiar to students taking software architecture and engineering.

Security Pattern

  • Although security is often considered an architectural characteristic for microservices, the environmental scope that this specific set of microservices will be used in, does not require the security characteristic to be of high priority.

  • As simplicity and minimization of dependencies was favoured for this project, items that adhere to the security pattern such as access tokens were not implemented. As this system is based on teaching core microservice principles while providing as minimal configuration overheads as possible. Authentication mechanisms would be deemed detrimental to this criteria.

Observability Patterns

Provides aid for application monitoring in production environments

Health Check API Pattern

  • This provides an additional diagnostic tool for the microservices architecture whilst running in production, allowing developers to observe if a microservice has failed unexpectedly or is taking a while to deploy.

Log Aggregation Pattern

  • Log aggregation pattern refers to the aggregation of logs within a searchable and centralized database [3:368].

Distributed Tracing Pattern

  • The distributed tracing pattern refers to each external request being recorded by a central server as a flow from one service to the next via a uniquely assigned ID [3].

Application Metrics Pattern

  • The application metrics pattern provides services to report metrics to a centralized server for alerting, aggregation and visualization [3].

Client-Side Service Discovery Pattern

  • Resolves discovery of services on the network.

  • Provides services to reference URLs as opposed to dynamically changing IP addresses.

  • Netflix Eureka adheres to an application level service discovery pattern suite, being a combination of both:

    • The self-registration pattern, where an instance of a service registers itself with the service registry [3:82],

    • A client-side discovery pattern, where the service client retrieves available service instances on the network and load-balances across them [3:83].

Infrastructure Patterns

Server-Side/Platform Provided Service Discovery Pattern

  • Resolves discovery of microservices on the network.

  • Provides services to call instances belonging to the specified microservice name as opposed to a specific singular microservice instance via an IP address.

  • Prominent examples include Kubernetes Native Service Discovery.

Deployment Patterns

  • Each service was deployed according to the Service as a Container pattern for production runs.

  • Microservices are deployed as image containers into production, achieving fault isolation.

  • Each microservice instance belongs to their own container.

Communications Patterns

Transactional Messaging Pattern

  • A transactional messaging pattern was not implemented.

  • Transaction messaging is needed when a service requires message publishing as part of a transaction that updates the database [3:97].

  • As communication between all services are of a synchronous style, there is no need to apply such a pattern.

Communication Style

  • Inter-process communication is provided using the unified API set over HTTP in a RESTful manner. This aligns with the technology stack used within the CS5031 module.

  • All communication is based upon a synchronous style as it eliminates the need for an additional message broker.

  • It further provides students with immediate feedback via HTTP response codes or human-readable JSON payloads, helping aid the exploration and development of microservices [3:67].

Reliability - Circuit Breaker Pattern

  • A circuit breaker pattern is a remote procedure invocation proxy, rejecting invocations for a timeout period after a set of consecutive failures exceeds a specified threshold [3:78].

External API pattern

  • Allows an entry-point into the architecture, minimizing the port numbers and IP addresses needed to interact with the application.

  • Allows for faster public-facing API redesign.

  • It further provides for authentication ability for the application, reducing evolution costs if authentication is chosen to be added in the future [3:259].

  • The Spring Cloud API gateway allows for an additional API composition pattern, whereby one client request via the gateway may invoke multiple API calls to a variety of microservices through the use of request handlers.

Design Decisions Outside Architectural Pattern Language Scope

Kubernetes

  • Kubernetes was used as a container orchestration tool to automate the deployment and management of the microservices application. For further reading about Kubernetes infrastructure, please see appendix D.

API-First Design

  • The unified API contract was first specified following service decomposition.

  • The application adheres only to a RESTful API contract.

  • The following design principles were followed [7]:

  • Acceptance/Response in JSON

  • Gracefully handle errors by returning standard HTTP status codes

  • Nouns were used to identify the microservice being called in endpoint paths. (ie, GET /book/year/1997 gets all books published in 1997)

0
Subscribe to my newsletter

Read articles from Marco directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Marco
Marco

Senior DevOps Engineer exploring the world of distributed systems