This documents describes the architecture and design of Creo in detail. It covers the generation process step by step starting from generating an application graph to outputting the source code of applications.
Creo represents the topology of a microservice application as a directed, acyclic graph (DAG).
In order to generate an application, we construct a random DAG based on the user-provided configuration.
Consider the following topology
section of a AutoPilot generation configuration:
topology:
services: 3
endpoints: 6
inter_service_calls: 4
According to this configuration, the generated application should comprise 3 microservices with a total number of 6
endpoints. That is, the average number of endpoints per service is
Creo's application model constructs microservice applications as a bottom-up approach. That is, we start by first generating the endpoints, then adding the inter-service calls between endpoints, and finally aggregating endpoints into microservices. In our model, we represent the endpoints of the microservice application as graph vertices. That is, in our example we first add 6 vertices to our DAG, since the number of endpoints is 6.
Next, we need to generate the graph edges. In our model, graph edges relate to the interactions between to endpoints.
That is, a directed edge from vertex
In Figure 2, the gray edges represent all possible edges, while the black edges correspond to the actual generated edges. As can be seen in the figure, when a request reaches endpoint 1, it will call endpoint 2 and endpoint 3 before returning a response. In turn, endpoint 3 will also call endpoint 4 on receiving the request from endpoint 1 and will return its response to endpoint 1 after receiving a response from endpoint 4. With this, we model the dependency structure of endpoints typically found in microservice applications. Similarly, endpoint 6 calls endpoint 5 before responding to its incoming network requests. In the following, we will only depict the generated edges, such that the figures stay well organized.
At the moment, the endpoints in our application are only related via their network call dependencies.
However, the relation to microservices is still missing. In this step, we will color the graph to group endpoints into
microservices. Vertices (i.e., endpoints) that have the same color will belong to the same microservice.
We ensure that the found coloring of the graph is proper, that is if two vertices
Figure 3 depicts a possible coloring for our application graph. We also rearranged the vertices into layers to better illustrate the inter-service calls among the endpoints of the application's microservices. In our example, the orange microservice has two endpoints, i.e. endpoint 1 and endpoint 6. The yellow microservice comprises the single endpoint 3, while the magenta microservice has the most endpoints, i.e. endpoint 2, endpoint 4, and endpoint 5. With the colored graph, we generated a full representation of the microservice application topology. However, the application workload is still missing from this representation. Hence, we will assign the workload in the next step.
Lets consider the following service types configuration:
service_types:
# CPU-intensive microservice (s1)
- fraction: 50
properties:
- label: CPU
fraction: 100
bucket: HIGH
# Outgoing network-intensive microservice (s2)
- fraction: 50
properties:
- label: NETWORK_TRANSMIT
fraction: 100
bucket: HIGH
The configuration consists of two service types. The first service type - let's call it