Pages

Tuesday, April 22, 2014

Micro Services vs OSGi services

Recently the topic of Micro Services has been getting a lot of attention. The OSGi world has been talking about micro services for a long time already. Micro services in OSGi are also often written as µServices, which I will use in the remainder of the post to separate the two concepts. Although there is a lot of similarity between µServices in OSGi and Micro Services as recently became popular, they are not the same. Let's first explore what OSGi µServices are.

OSGi µServices

OSGi services are the core concept that you use to create modular code bases. At the lowest layer OSGi is about class loading; each module (bundle) has it's own class loader. A bundle defines external dependencies by using an import-package. Only packages which are explicitly exported can be used by other bundles. This layer of modularity makes sure that only API classes are shared between bundles, and implementation classes are strictly hidden.
This also imposes a problem however. Let's say we have an interface "GreeterService" and an implementation "GreeterServiceImpl". Both the API and implementation are part of bundle "greeter", which exports the API, but hides the implementation. Now we take a second bundle that want to use the GreeterService interface. Because this bundle can't see the GreeerServiceImpl, it would be impossible to write the following code:

GreeterService greeter = new GreeterServiceImpl();

This is obviously a good thing, because this code would couple our "conversation" bundle directly to an implementation class of "greeter", which is exactly what we're trying to avoid in a modular system. OSGi offers a solution for this problem with the service layer, which we will look at next. As a side note, this also means that when someone claims to have a modular code base, but doesn't use services, there is a pretty good chance that the code is not so modular after all....

In OSGi this problem is solved by the Service Registry. The Service Registry is part of the OSGi framework. A bundle can register a service in the registry. This will register an instance of an implementation class in the registry with it's interface. Other bundles can then consume the service by looking it up by the interface of the service.  The bundle can use the service using it's interface, but doesn't have to know which implementation is used, or who provided the implementation. In it's essence the services model is not very different from dependency injection with frameworks such as CDI, Spring or Guice, with the difference that the services model builds on top of the module layer to guarantee module borders.



OSGi services are often called micro services, or µServices. This makes sense because they are "lightweight" services. Although there is the clear model of service providers and service consumers, the whole process works within a single JVM with close to zero overhead. There is no proxying required, so in the end a service call is just a direct method call. As a best practice a service does only a single thing. This way services are easy to replace and easy to reuse. These are also the immediate benefits of a services model; they promote separation of concerns, which in the end is key to maintainable code.

Comparing with Micro Services

So how does this relate to the Micro Services model that recently got a lot of attention? The obvious difference is that OSGi services live in a single JVM, and the Micro Services model is about completely separate deployments, possibly using many different technologies. The main advantages of such a model go back to the general advantages of a modular system:


  1. Easier to maintain: Unrelated code is strictly isolated from each other. This makes it easier to understand and maintain code, because you don't have to worry too much about code outside of the service.
  2. Easier to replace: Because services are small, it's also easy to simply throw a service away and re-implement it if/when requirements change. All you care about is the service interface, the implementation is replaceable. This is an incredibly powerful tool, and will prevent "duct taping" of code in the longer term.
  3. Re-usability: Services do only a single thing, and can be easily used in new scenarios because of that. This goes both for re-usability in different projects/systems when it's about technical components, or re-usability of functional components within a system.


Do these benefits look familiar when thinking about SOA? In recent years not much good is said about SOA, because we generally associate it with bloated tools and WSDLs forged in the deepest pits of hell. I loathe these tools as well, but we should remember that this is just (a very bad) implementation of SOA. SOA itself is about architecture, and describes basically a modular system. So Micro Services is SOA, just without the crap vendors have been trying to sell us.

Micro Services follow the same concept, but on a different scale. µServices are in-VM, Micro Services are not. So let's compare some benefits and downsides of both approaches.

Advantages of Services within a JVM

One advantage of in-VM services is that there is no runtime overhead; service calls are direct method calls. Compared to the overhead of network calls, this is a huge difference. Another advantage is that the programming model is considerably simpler. Orchestrating communication between many remote services often requires an asynchronous programming model and sending of messages. No rocket science at all, but more complicated than simple method calls.
The last and possibly most important advantage is ease of deployment. An OSGi application contain many services can be deployed as a single deployment, either in a load-balanced cluster or on a single machine. Deploying a system based on Micro Services requires significant work on the DevOps side of things. This doesn't just include automation of deployments (which is relatively easy), but also making sure that all required services are available with the right version to make the whole system work.


Advantages of Micro Services

The added complexity in deployments also offers more flexibility. I believe the most important point about Micro Services is that services have their own life-cycle. Different teams can independently work on different services. They can deploy new versions independently of other teams (yes this requires communication...), and services can be implemented with the tools and technology that is optimal for that specific service. Also, it is easier to load balance Micro Services, because we can potentially horizontally scale a single service instead of the whole system.

This brings the question back to scale of the system and team. When only a single team (say maximum 10 developers) works on a system, the advantages of Micro Services compared to µServices don't seem to weigh up. When there are multiple teams working on the same system, this might be a different story. In that case it could also be an option to mix and match both approaches. Instead of going fully Micro Service, we could break up an already modular system into different deployments and have the benefits of both. Of course, this adds new challenges and requirements; for starters, we need a remoting/messaging layer on top of services, and we might need to modify the granularity of services.

This article was mostly written as a clarification of the differences between uServices and Micro Services. I'm a strong believer of the power of separated services. From my experience building large scale OSGi applications, I also know that many of the benefits of modularity can be achieved without the added complexity of a full Micro Service approach. Ultimately I think a mixed approach would work best on a larger scale, but that's just my personal view on the current state of technology. 

13 comments:

  1. I guess we can convert OSGi services to Micro services through Apache Camel(http://camel.apache.org/)

    ReplyDelete
  2. Nice article! Very easy to comprehend. Thanks for sharing.

    ReplyDelete
  3. That was a very good one with clearly pointing out the differences.

    >> OSGi only deals with bundles and services running on the same VM << does it means that it runs like a Monolithic application running in VM ? If this one VM goes down, the entire application goes down ? Wasn't Distributed OSGi introduced for this purpose (am not sure about the maturity of D-OGSi)

    ReplyDelete
    Replies
    1. Yes, OSGi services run in a single VM, so if that VM crashes it's all gone.
      With Distributed Services you can work with services running in different VMs (on different machines), while keeping the same programming model. This also makes it easy to move services that run in the same VM to a deployment where the services run in different VMs (which would be a micro services architecture).

      You also make a point about the VM going down. Note that a distributed model (in any kind of technology) doesn't automatically provide better failover. Actually it gets worse, because networking can potentially fail.
      The deployment infrastructure needs to take care of that. E.g. when using something like Kubernetes, you would want to run multiple replicas of each component. This works the same for a distributed micro services architecture and a monolithic deployment however, so it's important to remember that micro services != higher availability.

      Delete
  4. Replies
    1. I think it would make more sense if you write another post that states the difference of architectures using OSGI VS dependency injection.

      Delete
  5. Hi Taha , thanks for your feedback. Can you explain a little what you mean by "vs DI"? I would think they are complementary but I curious about your ideas.

    ReplyDelete