- Mastering Spring Cloud
- Piotr Minkowski
- 775字
- 2021-08-27 18:57:06
Building the example application
For the Eureka Server, all of the required changes may be defined in configuration properties. In the application.yml file, I defined three different profiles for each instance of the discovery service. Now, if you try to run Eureka Server embedded in the Spring Boot application, you need to activate the specific profile by providing the VM argument -Dspring.profiles.active=peer[n], where [n] is the instance sequence number:
spring:
profiles: peer1
eureka:
instance:
hostname: peer1
metadataMap:
zone: zone1
client:
serviceUrl:
defaultZone: http://localhost:8762/eureka/,http://localhost:8763/eureka/
server:
port: ${PORT:8761}
---
spring:
profiles: peer2
eureka:
instance:
hostname: peer2
metadataMap:
zone: zone2
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/,http://localhost:8763/eureka/
server:
port: ${PORT:8762}
---
spring:
profiles: peer3
eureka:
instance:
hostname: peer3
metadataMap:
zone: zone3
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/
server:
port: ${PORT:8763}
After running all three instances of Eureka using different profile names, we created a local discovery cluster. If you take a look at the Eureka dashboard for any instance just after startup, it always looks the same, we have three instances of DISCOVERY-SERVICE visible:
The next step is to run the client application. The configuration settings in the projects are very similar to those for the application with the Eureka Server. The order of addresses provided in the defaultZone field determines the sequence of connection attempts to different discovery services. If the connection to the first server cannot be established, it tries to connect with the second one from the list, and so on. The same as earlier, we should set the VM argument -Dspring.profiles.active=zone[n] to select the right profile. I also suggest you set the -Xmx192m parameter, keeping in mind that we test all of the services locally. If you do not provide any memory limits for the Spring Cloud application it consumes around 350 MB of heap after starting, and about 600 MB of total memory. Unless you have got a lot of RAM it may make it difficult to run multiple instances of microservices on your local machine:
spring:
profiles: zone1
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/,http://localhost:8763/eureka/
server:
port: ${PORT:8081}
---
spring:
profiles: zone2
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8762/eureka/,http://localhost:8761/eureka/,http://localhost:8763/eureka/
server:
port: ${PORT:8082}
---
spring:
profiles: zone3
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8763/eureka/,http://localhost:8761/eureka/,http://localhost:8762/eureka/
server:
port: ${PORT:8083}
Let's take a look at the Eureka dashboard again. We have three instances of client-service registered everywhere, although the application has been originally connected to only one instance of the discovery service. The result is the same no matter which discovery service instance's dashboard we go into to look at. It was the exact purpose of this exercise. Now, we create some additional implementation only to demonstrate that everything works in accordance with the assumptions:
The client application does nothing more than expose a REST endpoint that prints the selected profile name. The profile name points to the primary discovery service instance for the particular application instance. Here's a simple @RestController implementation that prints the name of the current zone:
@RestController
public class ClientController {
@Value("${spring.profiles}")
private String zone;
@GetMapping("/ping")
public String ping() {
return "I'm in zone " + zone;
}
}
Finally, we can proceed to the implementation of API gateway. It's out of the scope of this chapter to go into detail about features provided by Zuul, Netflix's API gateway, and router. We will discuss it in the next chapters. Zuul will now be helpful in testing our sample solution, because it is able to retrieve the list of services registered in the discovery server and perform load balancing between all of the running instances of the client application. As you can see in the following configuration fragment, we use a discovery server listening on port 8763. All incoming requests with the /api/client/** path would be routed to client-service:
zuul:
prefix: /api
routes:
client:
path: /client/**
serviceId: client-service
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8763/eureka/
registerWithEureka: false
Let's move on to the testing. Our application with the Zuul proxy should be launched using the java -jar command and unlike previous services, there is no need to set any additional parameters, including a profile name. It is connected by default with discovery service number #3. To invoke the client API via the Zuul proxy, you have to type the following address into your web browser, http://localhost:8765/api/client/ping. The result is visible in the following screenshot:
If you retry the request a few times in a row, it should be load balanced between all of the existing client-service instances in the proportions 1:1:1, although our gateway is connected only to discovery #3. This example fully demonstrates how to build service discovery with multiple Eureka instances.
The preceding example application is available on GitHub (https://github.com/piomin/sample-spring-cloud-netflix.git) in the cluster branch (https://github.com/piomin/sample-spring-cloud-netflix/tree/cluster_no_zones).