Learnitweb

Spring Cloud Netflix

1. Introduction

Spring Cloud Netflix provides Netflix OSS integrations for Spring Boot apps through autoconfiguration and binding to the Spring Environment. By using a few straightforward annotations, you can easily activate and configure common patterns within your application, enabling you to build robust distributed systems powered by reliable Netflix components. These patterns include Service Discovery (Eureka).

An embedded Eureka server can be created with declarative Java configuration. Eureka instances can be registered and clients can discover the instances using Spring-managed beans.

2. Service Discovery: Eureka Server

2.1 How to Include Eureka Server

To include Eureka Server in your project, use the starter with a group ID of org.springframework.cloud and an artifact ID of spring-cloud-starter-netflix-eureka-server.

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

2.2 How to run a Eureka Server

To run a Eureka server, add @EnableEurekaServer to the main application class.

@SpringBootApplication
@EnableEurekaServer
public class Application {

    public static void main(String[] args) {
        new SpringApplicationBuilder(Application.class).web(true).run(args);
    }

}

The server features a homepage with a user interface, along with HTTP API endpoints for standard Eureka functionalities accessible under the /eureka/* path.

2.3 High Availability, Zones and Regions

The Eureka server operates without a backend store, relying on service instances in the registry to send periodic heartbeats to maintain their registrations, which allows everything to be handled in memory. Similarly, clients maintain an in-memory cache of Eureka registrations, enabling them to avoid querying the registry for each service request.

By default, each Eureka server also acts as a Eureka client and needs at least one service URL to discover a peer. If no URL is provided, the service will still run and function but will generate extensive log entries complaining about the inability to register with a peer.

2.4 Eureka server standalone mode

In standalone mode, the Eureka server operates independently without connecting to peer servers. This is useful for development or testing environments where a single instance is sufficient. Since there are no peers, the server doesn’t attempt replication or rely on a backend store, handling registrations and heartbeats entirely in memory. Logs may contain warnings about missing peer configurations, but the server remains fully functional.

application.yml (Standalone Eureka Server)

server:
  port: 8761

eureka:
  instance:
    hostname: localhost
  client:
    registerWithEureka: false
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

Notice that the serviceUrl is pointing to the same host as the local instance.

2.5 Peer Awareness

Eureka can be made even more resilient and available by running multiple instances and asking them to register with each other. In fact, this is the default behavior, so all you need to do to make it work is add a valid serviceUrl to a peer, as shown in the following example:

application.yml (Two Peer Aware Eureka Servers)

---
spring:
  profiles: peer1
eureka:
  instance:
    hostname: peer1
  client:
    serviceUrl:
      defaultZone: https://peer2/eureka/

---
spring:
  profiles: peer2
eureka:
  instance:
    hostname: peer2
  client:
    serviceUrl:
      defaultZone: https://peer1/eureka/

In the preceding example, we have a YAML file that can be used to run the same server on two hosts (peer1 and peer2) by running it in different Spring profiles. You could use this configuration to test the peer awareness on a single host (there is not much value in doing that in production) by manipulating /etc/hosts to resolve the host names. In fact, the eureka.instance.hostname is not needed if you are running on a machine that knows its own hostname (by default, it is looked up by using java.net.InetAddress).

You can configure multiple peers in a Eureka system, and as long as they are interconnected through at least one link, they will synchronize registrations seamlessly. This setup ensures resilience, allowing the system to withstand “split-brain” scenarios, whether the peers are within a single data center or distributed across multiple locations.

2.6 When to Prefer IP Address

In some cases, it is preferable for Eureka to advertise the IP addresses of services rather than the hostname. Set eureka.instance.preferIpAddress to true and, when the application registers with eureka, it uses its IP address rather than its hostname.

If the hostname cannot be determined by Java, then the IP address is sent to Eureka. Only explicit way of setting the hostname is by setting eureka.instance.hostname property. You can set your hostname at the run-time by using an environment variable for example, eureka.instance.hostname=${HOST_NAME}.

3. Service Discovery: Eureka Clients

Service discovery is a fundamental aspect of microservice-based architectures. Manually configuring each client or relying on conventions can be challenging and prone to errors. Eureka, developed by Netflix, serves as a Service Discovery Server and Client. The server can be set up for high availability, with multiple instances replicating the state of registered services across each other.

3.1 How to Include Eureka Client

To include the Eureka Client in your project, use the starter with a group ID of org.springframework.cloud and an artifact ID of spring-cloud-starter-netflix-eureka-client.

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

3.2 Registering with Eureka

When a client registers with Eureka, it provides meta-data about itself such as host, port, health indicator URL, home page, and other details. Eureka receives heartbeat messages from each instance belonging to a service. If the heartbeat fails over a configurable timetable, the instance is normally removed from the registry.

Including spring-cloud-starter-netflix-eureka-client in your application’s classpath enables automatic registration with the Eureka Server. To achieve this, you need to configure the application to locate the Eureka server, as illustrated in the following example:

application.yml

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

In the example above, defaultZone acts as a fallback magic string that specifies the service URL for clients without a specific preference, making it a convenient default configuration.

The default application name (that is, the service ID), virtual host, and non-secure port (taken from the Environment) are ${spring.application.name}, ${spring.application.name} and ${server.port}, respectively.

Adding spring-cloud-starter-netflix-eureka-client to the classpath transforms the application into both a Eureka “instance” (registering itself) and a “client” (querying the registry to find other services). The instance behavior is controlled by eureka.instance.* configuration keys, but the defaults generally work well as long as your application specifies a value for spring.application.name, which serves as the default Eureka service ID or VIP.

3.3 Disable Eureka Discovery Client

To disable the Eureka Discovery Client, you can set eureka.client.enabled to false. Eureka Discovery Client will also be disabled when spring.cloud.discovery.enabled is set to false.

3.4 Status Page and Health Indicator

The status page and health indicators for a Eureka instance default to /info and /health respectively, which are the default locations of useful endpoints in a Spring Boot Actuator application.

3.5 Eureka’s Health Checks

By default, Eureka uses the client heartbeat to determine if a client is up. Unless specified otherwise, the Discovery Client does not propagate the current health check status of the application, per the Spring Boot Actuator. Consequently, after successful registration, Eureka always announces that the application is in ‘UP’ state. This behavior can be altered by enabling Eureka health checks, which results in propagating application status to Eureka. As a consequence, every other application does not send traffic to applications in states other then ‘UP’. The following example shows how to enable health checks for the client:

application.yml

eureka:
  client:
    healthcheck:
      enabled: true

You can include extra metadata in the instance registration using the eureka.instance.metadataMap. This metadata is accessible to remote clients but typically does not influence client behavior unless the client is explicitly programmed to interpret and act on it.

3.6 Changing the Eureka Instance ID

A vanilla Netflix Eureka instance is registered with an ID that is equal to its host name (that is, there is only one service per host). Spring Cloud Eureka provides a sensible default, which is defined as follows:

${spring.cloud.client.hostname}:${spring.application.name}:${spring.application.instance_id:${server.port}}}

An example is myhost:myappname:8080.

By using Spring Cloud, you can override this value by providing a unique identifier in eureka.instance.instanceId, as shown in the following example:

application.yml

eureka:
  instance:
    instanceId: ${spring.application.name}:${vcap.application.instance_id:${spring.application.instance_id:${random.value}}}

3.7 Why Is It so Slow to Register a Service?

As an instance, the application sends a periodic heartbeat to the registry via the client’s serviceUrl, with a default interval of 30 seconds. A service becomes discoverable by clients only after the instance, server, and client synchronize their metadata in their local caches, which may take up to three heartbeats. You can adjust the interval using eureka.instance.leaseRenewalIntervalInSeconds. Setting it to less than 30 seconds accelerates client connection to services, but in production, it’s generally advisable to use the default value, as the server’s internal computations rely on the assumed lease renewal period.

3.8 Zones

If you have deployed Eureka clients to multiple zones, you may prefer that those clients use services within the same zone before trying services in another zone. To set that up, you need to configure your Eureka clients correctly. First, you need to make sure you have Eureka servers deployed to each zone and that they are peers of each other.

Next, you need to tell Eureka which zone your service is in. You can do so by using the metadataMap property. For example, if service 1 is deployed to both zone 1 and zone 2, you need to set the following Eureka properties in service 1:

Service 1 in Zone 1

eureka.instance.metadataMap.zone = zone1
eureka.client.preferSameZoneEureka = true

Service 1 in Zone 2

eureka.instance.metadataMap.zone = zone2
eureka.client.preferSameZoneEureka = true

3.9 Refreshing Eureka Clients

By default, the EurekaClient bean is refreshable, meaning the Eureka client properties can be changed and refreshed. When a refresh occurs clients will be unregistered from the Eureka server and there might be a brief moment of time where all instance of a given service are not available. One way to eliminate this from happening is to disable the ability to refresh Eureka clients. To do this set eureka.client.refresh.enable=false.