NetKernel, a 1060 Research product, provides a framework for building multiscale microservice architectures, in part by providing a unifying address space for binding resources.
There is a widespread tendency amongst those building PaaS and IaaS applications to re-factor their codebases into components known as microservices, which can scale elastically independently of each other. In some senses, this is service-oriented architecture (SOA). However, the interfaces tend to be looser, with:
- Loose data typing, particularly on the consumer side of the API (the producing side passes an object, and the consuming side looks at it and works out how to translate it into something it can deal with)
- Loose coupling, typically via HTTP using the REST paradigm and without the centralized choreography that was layered into the WS-XXX SOA models.
From the perspective of development teams, there are many good reasons to go down this route. It encapsulates development into each microservice, it doesn’t require all microservices to be written in the same programming language, and it can in principle enhance reusability. It also fits well with the cloud—with HTTP, elastic scaling, load balancing, caching, proxies, polyglot persistence, etc.
NetKernel, however, takes the idea of microservices a step further by posing the question, “What happens if we make everything a microservice?” In conventional REST, the HTTP methods (POST, PUT, GET, and DELETE) applied to resources are standardized, but the way that resources are addressed is not. In a URL such as http://m.d.tld/xxxx/yyy, there is a discontinuity whereby the historic notions of machine and filesystem collide. Things to left of the third “/” are resolved by the domain name system (DNS); things to the right are resolved by the web server or the application. They are typically structured in a tree inspired by the Unix filesystem, but in fact there are no real rules, and the way this works isn’t actually prescribed in REST.
One common approach is to define resources as chains of name/ID pairs, reflecting some traversal of a graph of resources. However, since most resources are arranged in connected graphs, not trees, the path tends not to be unique, meaning that the same resource can be addressed in multiple ways, making it hard to cache. Furthermore, the path to an object tends to be quite brittle, because it doesn’t relate to any particular attributes of the object itself.
There’s a certain affinity for neologisms in the NetKernel documentation that can be quite obfuscatory; indeed, it doesn’t even use the standard POST, PUT, GET, and DELETE, but has its own verbs meaning more or less the same things. However, the key thing that NetKernel introduces beyond conventional microservice architecture is a uniform approach to the naming of resources that does away with historic notions of machine and filesystem. In this approach, there is no longer a concept of a domain; rather, there is an arbitrary structure of namespaces within which endpoints (i.e., microservices) declare the resource patterns that they are prepared to bind to. So, if you want to get a particular resource, you describe it with a combination of a namespace and a string, and any microservice within that namespace that can bind to the string will return the resource to you. There is also syntax within the resource locators that allows them to be chained (e.g., get me this resource, post it to this resource, post the result to this other resource, and give me the result), and the resource locators can be normalized before they are resolved, allowing them to be cached at any point in the architecture.
Clearly, you can’t use DNS to resolve the resources that are specified in a NetKernel environment. The resolution is performed within NetKernel itself, which is a Java application. The microservices can be run in many different languages; it is only the namespace resolution that runs in the kernel. The idea is that very small transformations can be expressed as microservices, because the resolution and execution process is claimed to be very fast, such that it doesn’t significantly impact performance. Further, there is inherent caching at all scales in the architecture, which means performance that otherwise would have been lost through repeated computation tends to be recovered.
The architecture is scale-invariant. You can have large existing application components embedded as microservices, you can have very small microservices, and you can compose multiple small microservices and expose them through a single higher-level microservice.
NetKernel also has mechanisms for dealing with the loose typing problem through automatically identifying and applying transformations to the objects being returned. For example, a consumer may require a JSON representation, and a producer may produce an XML representation of the same object. Within the namespace, a transrepresentation microservice may be registered which is capable of transforming from one to the other. The kernel will automatically introduce it into the pipeline between producer and consumer.
Obviously, once outside NetKernel, the resource location doesn’t work. So, NetKernel defines transports, which are essentially bindings between conventional URLs and the NetKernel resources. They allow you to, for example, interact with the application via a web browser in the conventional way.
NetKernel is a distributed Java application designed to run at multiple scales from a single core on a single CPU up through multicore architectures, multiprocessor architectures, and loosely coupled infrastructures such as the cloud. Within a NetKernel deployment, there is no need to consider physical layout; the namespace resolution takes care of the partitioning and performs caching as required. The whole thing is stateless (apart from those microservices that use external persistence), so it load balances and has some fault tolerance.
NetKernel is licenced per JVM for enterprise deployments and is available in an open source version. It embodies a number of interesting ideas in microservices in a much purer form than they are generally applied. It is described as “Resource Oriented Computing,” which can be thought of as a design pattern for which NetKernel is a framework.
It is worth spending some time investigating the product—at the very least, you will be exposed to these ideas.