microservices with spring network

Microservices with Spring Boot and Spring Cloud

If you’re a Java developer, you certainly know about the Spring Framework. Spring provides  a lot of functionality which covers almost all aspects of web and enterprise application development. One aspect I’m going to cover in this article is development of microservices with Spring Boot and Spring Cloud. This won’t be another tutorial on how to implement microservice, but rather a high-level overview of features that come with Spring and help speed up development and boost productivity.

Spring Boot is great platform for developing RESTful web applications, like I presented earlier in another post about developing REST APIs with Spring Boot. On top of Spring Boot, Spring team created another project called Spring Cloud, aimed specifically to developing microservices.

Developing microservices with Spring Cloud

Spring Cloud provides out of the box support for most common usage patterns used in microservices development. It integrates with popular open source libraries such as Netflix OSS and cloud providers like Pivotal CloudFoundry, AWS and others. By leveraging these tools and libraries, you can quickly build and deploy microservices on most commonly used platforms. For example, Spring Cloud supports the following use cases:

  • Distributed and versioned configuration
  • Service registration and discovery
  • Routing and edge services
  • Inter-service communication
  • Load balancing
  • Circuit breakers
  • Distributed messaging

and many more things. In the following sections, I’ll describe each of these use cases and how Spring Cloud helps with implementation. You might want to grab a coffee before you keep reading, this might take a while :-).

Configuring microservices with Spring Cloud

In highly dynamic and distributes systems like microservices, there must be a centralized place for configuration management. In traditional, monolith applications, configuration is usually stored in files. But, in microservices, this is just not feasible. These systems can grow to hundreds of services and thousands of instances, and having configuration files deployed with each instance quickly becomes cumbersome. Usually, in these systems, there is a dedicated service which provides configuration settings to other services.

In addition, services must run in different environments, like development, testing and production. Since distributed systems are highly automated, there must be a way to separate configuration for these environments, so deployment tools can pick up configuration settings quickly.

Spring Cloud provides a configuration server component which acts as a centralized point for all configuration related tasks. This server is simply a Spring Boot web application with some specific annotations and dependencies. Configuration server supports various storage backends for configruation, and by default uses git. When server starts, it provides endpoints to which clients can connect and pick up required configuration entries. These are usually server in JSON format.

On client side, each service is annotated with @EnableDiscoveryClient  annotation, which adds capability to request configuration from config server. One of the configuration parameters that must be deployed with each service is the URL of configuration server. When client service starts, it automatically connects to configuration server and picks up configuration parameters it needs. You can find an example of client and server configuration in one of the previous posts about microservices registration, discovery and configuration.

As I mentioned, configuration server uses git as a default backend for configuration storage, although it can also use plain files. Using version control system like git is preferred, because it allows tracking changes, easy rollback and enforces accountability  for configuration changes.

Storing sensitive configuration parameters

Usually, some parts of the configuration are security sensitive, such as user passwords, encryption keys and API keys. Configuration server can handle encrypted values, which are denoted by {cipher}  prefix before parameter value. For example, this sample contains database username and password:

When clients request this value, server will decrypt it before sending it. It is also possible to do the encryption on client. From security point of view, this may be a better option, in order to avoid sending plain text over the wire.

Another option for storing sensitive information is Spring Vault. This is client side component which adds support for reading secret configuration from Hashicorp Vault. Vault is a secure storage for sensitive information like passwords, security keys, certificates etc. It adds a layer of security in the system by avoiding the need to store sensitive data in text files.

By using Vault in addition to configuration server, you can create highly secure and robust system for storing, management and distributing properties.

Service registration and discovery

In highly dynamic distributed systems, services can go online and offline in any time. That’s why having automated way to track services is extremely important. One of the most popular tools for this task is Netflix Eureka, which provides robust support for locating services, performing load balancing and failover.

When developing microservices with Spring Cloud, using Eureka is extremelu easy, only requires adding single annotations to client and server. I won’t got into details about it here, but if you are interested, you can see a sample code in one of the previous posts in series of developing microservices with Spring Cloud.

Because service registration and discovery is extremely important for correct functioning of the system, it is really important to have resilient and highly available Eureka server. One way to implement this is to have multiple instances of Eureka and have each instance register with each other. This is the default behavior of Spring Eureka server, and all you need to do is provide URL of all instances in Eureka configuration file.

When you create Spring Cloud application as Eureka server, you also get a management interface and dashboard. Bellow is the screenshot of this interface:

microservices spring cloud eureka ui

This GUI shows all registered services, their status, availability zones etc. By clicking on individual service links, you can get more information about them.

Routing microservices with Spring Cloud

In microservices architecture, an edge service, or API gateway is an entry point into system for outside clients consuming services. Edge service is used as a router for incoming requests. For example, client request to endpoint /user/profile  might cause edge service to trigger execution of large number of services to complete the request. In a way, edge service can be compared to a reverse proxy. This pattern is nicely explained in Chris Richardson’s article about API gateway pattern.

For this purpose, Netflix has developed Zuul, an edge service that had many more features. In addition to routing requests, Zuul also provides load balancing, monitoring, security etc. Spring Cloud also provides support for using Zuul for routing. Common use case is to set up Zuul as reverse proxy in front of your microservices, and use it for routing requests. For that goal, Spring Cloud provides @EnableZuulProxy  annotation. When you annotate Spring Boot application with this annotation, it adds support for configuring routes used to invoke target microservices. For hands-on example of this, you can check out this post about developing microservices with Spring Cloud and Zuul.

Service communication and circuit breakers

Services need to communicate with each other. Although this seems like a simple task to achieve, there are multiple issues that need to be taken into account. When you have a system which consists of a lot of moving parts, reliability of the system depends on reliability of individual parts. For example, these situations can occur at any time:

  • individual services can be down, due to software or hardware failure, network outage or any other reason
  • service performance may be degraded, thus causing timeouts and other failures in depending services

System must be prepared to handle these kinds of events gracefully. The last thing we want is that failure of one service cause cascading failures and bring down entire system. Luckily, Netflix has got us covered with Hystrix. Hystrix is a library which enables latency and fault tolerance management, thus improving resiliency of the system. It also implements Circuit breaker pattern to avoid calling services which are considered as failed.

Spring Cloud also provides bindings for Hystrix by using simple annotations. Short code snippet bellow shows how to use Hystrix with Spring beans:

By simply annotating method with @HystrixCommand , it’s execution is wrapped in Hystrix and managed through it. We can also specify fallback method which executes if Hystrix command fails. For more complete example, and additional options of Hystrix, please take a look at this post about microservices with Spring Cloud and Hystrix.

Monitoring with Hystrix Dashboard

When you use Hystrix for inter service communication, you get a monitoring dashboard for free.  This dashboard shows a lot of information related to execution and performance of individual service calls. An example is shown in the image bellow (image taken from fluxcapacitor)

microservices with spring cloud hystrix

This dashboard shows a lot of information related to individual Hystrix command. Each command is identified by it’s name, and the following information is available for each one:

  • status of circuit breaker (open or closed)
  • statistics of execution latency (mean, median, percentile)
  • error rate (as a percentage of  requests)
  • circle represents traffic volume and service health
  • line represents relative change of traffic in 2-minute interval

The best thins is, you get all of this automatically just by including Hystrix support in your microservice. There’s no need for additional code or configuration.

 

Load balancing in microservices with Spring Cloud

Load balancing is closely connected to the previous topic. Any given service can have multiple instances running at the same time, so there is a need to load balance calls to these services. Again, Netflix has us covered with Ribbon, client side load balancing solution. Ribbon can be used with Eureka to dynamically track service statuses and spread the calls to available services, thus reducing the load on individual instances.

Spring Cloud includes support for Ribbon, and also for another, declarative REST client Feign. Feign uses Ribbon by default, so it already comes with load balancing capabilities. Most common use case is to use Ribbon in conjunction with Eureka server.  In this configuration, Ribbon gets a list of service instances from Eureka. Ribbon supports different load balancing rules, and by default uses “round robin”. This means that each service gets called in turn. It is also possible to create custom load balancing rules.

The image bellow is a diagram how Ribbon is used with microservices (image is part of the presentation Scalable microservices at Netflix):

microservices with spring netflix ribbon

 

Using Feign as REST client further reduces the need for boilerplate code. To use Feign, you simply annotate your interface methods with specific annotations, and Feign uses those to infer what endpoints need to be called and with which parameters. For example, following code sample shows how you can declare a client that fetches data from configured endpoint.

Distributed messaging with Spring Cloud Bus

Spring Cloud Bus is a lightweight message broker for Spring Cloud applications. It can be used to broadcast messages like configuration changes and management instructions. For example, when you change some configuration parameter, you can broadcast the change and have all services reconfigure automatically. This way, you avoid the need for services to poll configuration server for changes.

Spring Cloud Bus can use AMQP or Apache Kafka as message broker implementations. There are starter packages available for both implementations. In order to have Spring Cloud Bus running, you need to have AMQP server (like RabitMQ) or Apache Kafka available. Then you just configure Bus to use that server as a transport.

In conclusion

In addition to the features described here, Spring Cloud comes with support for even more useful stuff. I’ve written about some of them in the series about of microservices development with Spring Cloud. Some of those features include logging and tracing with Sleuth, application metrics with Actuator and Dropwizard and so on.

If you are starting new project based on microservices, Spring Cloud would be a great choice for implementation technology. Even if you have existing project, you may consider writing new features with Spring Cloud. It should be easy to incorporate it into existing system, especially if you use Netflix libraries. You get the full power of Spring framework, bindings for frequently used tools and increased speed of development.