Recommended reading:

Notes on the Learning route of Spring Cloud Alibaba microservice Architecture

Introduction to Service Governance

Let’s start with a question

We hardcoded the service provider’s network address (IP, port) into the code, which has many problems:

  • As soon as the service provider address changes, you need to manually modify the code

  • Once there are multiple service providers, load balancing cannot be implemented

  • Once services become more numerous, it is difficult to maintain the call relationships manually

So how should solve, this time needs to implement service governance dynamically through the registry.

What is service governance

Service governance is the core and basic module of microservice architecture. It is used to realize automatic registration and discovery of each microservice.

  • Service registry: In the service governance framework, a registry is built to which each service unit registers details of the services it provides. And form a list of services in the registry. The service registry needs to monitor whether the services in the list are available by heartbeat. If not, it needs to eliminate the unavailable services in the service list.

  • Service discovery: The service invocation consults the service registry for services and obtains a list of instances of all services to realize the implementation of specific services

Example access.

As you can see from the above call diagram, in addition to microservices, another component is the service registry, which is a very important component of the microservices architecture and plays a major role as a coordinator in the microservices architecture. Registries generally contain the following functions:

1. Service Discovery:

  • Service registry: Holds information about service providers and service callers

  • Service subscription: Service callers subscribe to information about service providers, and the registry pushes information about providers to subscribers

2. Service Configuration:

  • Configuration subscriptions: Service providers and service callers subscribe to microservice-related configurations

  • Configuration delivery: Actively pushes configuration to service providers and service callers

3. Service health check

  • Detect the health of the service provider and perform service culling if exceptions are found

A common registry

  • Zookeeper

Zookeeper is a distributed service framework and a subproject of Apache Hadoop. It is used to solve data management problems frequently encountered in distributed applications, such as unified naming service, status synchronization service, cluster management, and configuration item management of distributed applications.

  • Eureka

Eureka is an important component of Springcloud’s Netflix, mainly for service registration and discovery. But now it’s closed

  • Consul

Consul is an open source tool based on the GO language that provides service registration, service discovery, and configuration management for distributed, service-oriented systems. Consul offers useful features including: service registration/discovery, health check, Key/Value storage, multi-data center, and distributed consistency assurance. Consul is only a binary executable file, so it is easy to install and deploy Consul. You only need to download Consul from the official website and execute the corresponding startup script.

  • Nacos

Nacos is a dynamic service discovery, configuration management, and service management platform that makes it easier to build cloud-native applications. It is one of the SpringCloud Alibaba components responsible for service registry discovery and service configuration, which can be considered nacos= Eureka +config.

Nacos profile

Nacos is dedicated to helping you discover, configure, and manage microservices. Nacos provides an easy-to-use feature set that helps you quickly implement dynamic service discovery, service configuration, service metadata, and traffic management.

As you can see from the above, NACOS functions as a registry to manage the microservices that are registered.

Nacos combat introduction

Next, we added nacOS to our existing environment and registered our two microservices.

Set up the NACOS environment

Step 1: Install nacOS

The installation package download address: https://github.com/alibaba/nacos/releases download zip format, and then for decompression operationCopy the code

Step 2: Start NACOS

CD nacos/bin # Start startup. Cd-m standaloneCopy the code

Step 3: Access nacOS

Open the browser to http://localhost:8848/nacos, you can access the service, the default password is nacos/nacos

Register commodity microservices with NACOS

Next, start modifying the code for the shop-Product module to register it with the NACOS service

1 Add nacOS dependencies to pom.xml

<! -- NacOS client --> 

<dependency> 

<groupId>com.alibaba.cloud</groupId> 

<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> 

</dependency> 
Copy the code

2 Add the @enableDiscoveryClient annotation to the main class

@SpringBootApplication 

@EnableDiscoveryClient 

public class ProductApplication 
Copy the code

3 Add the address of the nacos service to application.yml

Spring: Cloud: nacos: Discovery: server-addr: 127.0.0.1:8848Copy the code

4. Start the service and observe whether there are registered commodity microservices in nacOS control panel

Register the order microservice with NACOS

Next, start modifying the code for the SHOP_ORDER module to register it with the NACOS service

1 Add nacOS dependencies to pom.xml

<! -- NacOS client --> 

<dependency> 

<groupId>com.alibaba.cloud</groupId> 

<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> 

</dependency>
Copy the code

2 Add to the main class@EnableDiscoveryClientannotations

@SpringBootApplication 

@EnableDiscoveryClient 

public class OrderApplication
Copy the code

3 Add the address of the nacos service to application.yml

Spring: Cloud: nacos: Discovery: server-addr: 127.0.0.1:8848Copy the code

Modify OrderController to implement microservice invocation

@RestController 

@Slf4j 

public class OrderController { 

@Autowired 

private RestTemplate restTemplate; 

@Autowired 

private OrderService orderService; 

@Autowired 

private DiscoveryClient discoveryClient; 

// Ready to buy 1 item

@GetMapping("/order/prod/{pid}") 

public Order order(@PathVariable("pid") Integer pid) { 

log.info(">> Customer orders, at this time to call the product micro service to query the product information"); 

// Get the service address from nacos

ServiceInstance serviceInstance = 

discoveryClient.getInstances("service-product").get(0); 

String url = serviceInstance.getHost() + ":" + 

serviceInstance.getPort(); 

log.info(">> The microservice address obtained from NACOS is :" + url); 

// Invoke the commodity microservice from restTemplate

Product product = restTemplate.getForObject( 

"http://" + url + "/product/" + pid, Product.class); 

log.info(">> Product information, query result :" + JSON.toJSONString(product)); 

Order order = new Order(); 

order.setUid(1); 

order.setUsername("Test user"); 

order.setPid(product.getPid());
Copy the code

DiscoveryClient is dedicated to service registration and discovery. It allows you to obtain all services registered in the registry

5 Start the service, observe whether there are registered order microservices in nacOS’s control panel, and verify whether the call is successful by accessing the consumer service

Implement load balancing of service invocations

What is load balancing

In layman’s terms, load balancing is to spread the load (work tasks, access requests) across multiple operation units (servers, components) for execution.

Load balancing can be classified into server load balancing and client load balancing based on the location of load balancing.

Server-side load balancing refers to what happens on the service provider side, such as the common NGINx load balancing

Client-side load balancing occurs on the side of the service request, where an instance is selected to handle the request before it is sent.

We typically choose client load balancing in microservice invocation relationships, where one side of the service invocation decides which provider will perform the service.

Customize load balancing

Procedure 1 Start a shop-Product microservice using IDEA and set port number to 8082

2 Use nacos to view the startup status of microservices

3 Modify the shop-order code to implement load balancing

@RestController 

@Slf4j 

public class OrderController { 

@Autowired 

private RestTemplate restTemplate; 

@Autowired 

private OrderService orderService; 

@Autowired 

private DiscoveryClient discoveryClient; 

// Ready to buy 1 item

@GetMapping("/order/prod/{pid}") 

public Order order(@PathVariable("pid") Integer pid) { 

log.info(">> Customer orders, at this time to call the product micro service to query the product information"); 

// Get the service address from nacos

// Custom rules implement random selection of services

List<ServiceInstance> instances = discoveryClient.getInstances("service- product");

int index = new Random().nextInt(instances.size()); 

ServiceInstance serviceInstance = instances.get(index); 

String url = serviceInstance.getHost() + ":" + 

serviceInstance.getPort(); 

log.info(">> The microservice address obtained from NACOS is :" + url); 

// Invoke the commodity microservice from restTemplate

Product product = restTemplate.getForObject("http://" + url + 

"/product/" + pid, Product.class); 

log.info(">> Product information, query result :" + JSON.toJSONString(product)); 

Order order = new Order(); 

order.setUid(1); 

order.setUsername("Test user"); 

order.setPid(product.getPid()); 

order.setPname(product.getPname()); 

order.setPprice(product.getPprice()); 

order.setNumber(1); 

orderService.save(order); 

returnorder; }}Copy the code

Step 3: Start two service providers and one service consumer, and test the effect by visiting the consumer several times

Load balancing based on the Ribbon

The Ribbon is a component of Spring Cloud that makes load balancing easy with a single annotation

Step 1: Add the @loadBalanced annotation to the generation method of the RestTemplate

@Bean 

@LoadBalanced 

public RestTemplate restTemplate(a) { 

return new RestTemplate(); 

} 
Copy the code

Step 2: Modify the method of the service invocation

@RestController 

@Slf4j 

public class OrderController { 

@Autowired 

private RestTemplate restTemplate; 

@Autowired 

private OrderService orderService; 

// Ready to buy 1 item

@GetMapping("/order/prod/{pid}") 

public Order order(@PathVariable("pid") Integer pid) { 

log.info(">> Customer orders, at this time to call the product micro service to query the product information"); 

// Get the service address from nacOS using the microservice name directly

String url = "service-product"; 

// Invoke the commodity microservice from restTemplate

Product product = restTemplate.getForObject( 

"http://" + url + "/product/" + pid, Product.class); 

log.info(">> Product information, query result :" + JSON.toJSONString(product)); 

Order order = new Order(); 

order.setUid(1); 

order.setUsername("Test user"); 

order.setPid(product.getPid()); 

order.setPname(product.getPname()); 

order.setPprice(product.getPprice()); 

order.setNumber(1); 

orderService.save(order); 

returnorder; }}Copy the code

Load balancing policies supported by the Ribbon

Ribbon built in a variety of load balancing strategy, internal load balance of the top interface for com.net flix. The loadbalancer. IRule, specific load strategy as shown in the figure below:

Policy name Strategy description Implementation notes
BestAvailableRule Select a server with minimum concurrent requests Inspect servers one by one, skip tripped, and select the Server with the smallest activity equestscount
AvailabilityFilteringRule Filter out back-end servers marked with circuit tripped because they kept connecting, and filter out those with high concurrency (Activeconnections exceeded the configured threshold) Use an AvailabilityPredicate to include the logic for filtering servers, which checks the status of each server recorded in status
WeightedResponseTimeRule Assign a weight according to the corresponding time, the longer the corresponding time, the smaller the weight, the lower the probability of being selected. A background thread periodically reads the response time from status, calculating a weight for each server. It’s also a little bit easier to calculate the Weight of the responseTime minus the average responsetime of each server is the Weight of the server. When no StatAs is formed, the Roubine policy is used to select the server.
RetryRule Retry mechanism for the selected load balancing policy. If the server selection fails during a configuration period, the system tries to use subRule to select an available server
RoundRobinRule Polling Mode Select server in polling mode Poll index and select the server corresponding to index
RandomRule Select a server at random Randomly select the server corresponding to index
ZoneAvoidanceRule Select a server to judge the performance and availability of the server Use zone avoidancePredicate and AvailabilityPredicate to determine whether a server is selected, the former predicate determines whether a zone’s performance is available, and excludes the unavailable zone (all servers), AvailabilityPredicate is used to filter out servers that have too many connections.

You can adjust the Ribbon’s load balancing policy by modifying the configuration as shown below

Service - the product: # to invoke the name of the provider of ribbon: NFLoadBalancerRuleClassName: com.net flix. Loadbalancer. RandomRuleCopy the code

Implement service invocation based on Feign

What is Feign

Feign is a declarative pseudo Http client provided by Spring Cloud that makes calling remote services as simple as calling local services, creating an interface and adding an annotation.

Nacos is very compatible with Feign, which integrates the Ribbon by default, so using Fegin in Nacos is load balancing by default.

The use of Feign

1 Added Fegin dependency

<! - fegin component - > 

<dependency> 

<groupId>org.springframework.cloud</groupId> 

<artifactId>spring-cloud-starter-openfeign</artifactId> 

</dependency>
Copy the code

Add Fegin’s annotations to the main class

@SpringBootApplication 

@EnableDiscoveryClient 

@EnableFeignClients/ / open Fegin

public class OrderApplication {}
Copy the code

Create a service and implement the microservice invocation using Fegin

@FeignClient("service-product")// Declare the name of the invoked provider

public interface ProductService { 

// Specify which method of the provider to call

// @feignClient + @getMapping is a complete request path http://service-

product/product/{pid} 

@GetMapping(value = "/product/{pid}") 

Product findByPid(@PathVariable("pid") Integer pid); 

}
Copy the code

4 Modify the Controller code and enable verification

@RestController 

@Slf4j 

public class OrderController { 

@Autowired 

private OrderService orderService; 

@Autowired 

private ProductService productService;
// Ready to buy 1 item

@GetMapping("/order/prod/{pid}") 

public Order order(@PathVariable("pid") Integer pid) { 

log.info(">> Customer orders, at this time to call the product micro service to query the product information"); 

// Invoke commodity microservices through fegin

Product product = productService.findByPid(pid); 

log.info(">> Product information, query result :" + JSON.toJSONString(product)); 

Order order = new Order(); 

order.setUid(1); 

order.setUsername("Test user"); 

order.setPid(product.getPid()); 

order.setPname(product.getPname()); 

order.setPprice(product.getPprice()); 

order.setNumber(1); 

orderService.save(order); 

returnorder; }}Copy the code

5 Restart the Order micro service and view the effect