Edge service design. The concept of an edge service can be… | by Oted | GRID Esports
Edge service design
4 min read · Aug 19, 2021
The concept of an edge service can be quite vague. Many recent resources online speak of routers, load balancers and other client-facing services; whereas others merely mention the practice of putting processing hardware closer to data sources. Therefore let’s start this post by defining what we mean by an edge service at GRID:
“An edge service is any component in a system that sits at the border and communicates to external parties.”
Since this definition is quite broad, it can apply to microservice architectures but just as well to a low-level interfacing component talking to a humidity sensor in an IoT device for instance. For the purpose of this article though, we’ll limit ourselves to edge services that are responsible for ingesting raw esports data ( input edges) and externalizing enriched and transformed data to downstream consumers ( output edges). While the services at both ends are very different in implementation and purpose, the design principles behind them are actually very much alike.
Design Principles
On the GRID, esports data arrives in many shapes and forms depending mostly on which game it is for, as well as on the nature and source of the data itself. Naturally, different steps have to be carried out to transform this raw data into what we want to deliver to systems consuming our data, be it external or internal. At GRID, we avoid carrying out any transformations at the edge, and as we will see below, there are great benefits by doing so.
Simplicity
While it might sound obvious, the first design principle we strive for when designing edge services is simplicity. The services at the edge should have no idea what kind of data they are dealing with. No business logic resides here, we only want to ensure data is passed on (and persisted) in a timely manner.
Imagine an input edge service which receives data from a third party and immediately tries to extract some of the data. If the third party now changes the data format, our service could potentially be broken. If we instead perform these tasks further downstream, not only is the data safely persisted first, but any broken service downstream can be updated and the data can be re-processed. If this were to happen at the edge, the data would be lost forever.
Statelessness
Stateless services reduce the complexity of the application and hence conform with the simplicity principle above. Moreover, they are easier to scale to efficiently handle a varying data load.
Within our systems the load on the input edges can vary greatly depending on the nature of the data for a specific game, but also on the amount of content that is ongoing at the time. This can result in substantial fluctuations in data load throughout a relatively short amount of time.
Similarly when we have a content ongoing, more consumers are reading our processed data at the output edges. In a typical microservice architecture this fluctuation is handled by scaling up or down the amount of service replicas. In a stateful application however this is more complicated since it has to share its state with the other replicas. By having stateless edge services, we don’t have to care about persistence or concurrency issues.
Isolation
Let’s say an edge service would call another service to validate the data it received. All of a sudden there is a direct dependency on the uptime of this other service. Any downtime of either service will now result in unrecoverable data loss.
Therefore it is important to rely on as few other internal services and components as possible in order to ensure performance and uptime at the edge. Naturally there always have to be some external dependencies. At GRID for instance, we commonly keep the dependencies of our edge services limited to Kafka alone, as a means to transport and persist our data.
Summary
As we’ve seen above, adhering to these principles brings the following important benefits:
- maximum uptime
- minimal data loss
- ease of scaling
Additionally, edge services become easier to debug and test since they are very lightweight and isolated. Upon adding thorough instrumentation and logging to these services, we can now easily determine if a data issue is internal or external. By also putting timestamps and correlation IDs on each data message received at the edge, we are able to get a clear overview of the path the data is or isn’t taking through our architecture.