Nacos service discovery
What is service discovery
In the microservice architecture, the whole system is divided into multiple services according to responsibilities and capabilities, and business objectives are achieved through cooperation between services. In this way, it is inevitable to make remote calls between services in our code. The service consumer needs to call the service producer. In order to complete a request, the consumer needs to know the network location (IP address and port number) of the service producer.
Our code can read the network location of the service producer by reading the configuration file, as follows:
What is collaboration between services? For example, ha, Service A is an order service and Service B is a commodity service. When creating an order, you need to call commodities, that is, the order service will call Commodity services, which is the cooperation between services. The one called is called the producer, and the one calling other services is called the consumer, that is, Service A is called the consumer, and Service B is called the producer.
We can easily implement it through Spring boot technology:
Service B (service producer)
Service B is the producer of the service and exposes the / service service address. The implementation code is as follows:
@SpringBootApplication @RestController public class SpringRestProviderBootstrap { public static void main(String[] args) { SpringApplication. run(SpringRestProviderBootstrap.class, args); } @GetMapping(value = "/service") //Exposure services public String service(){ return "provider invoke" ; } }
Profile:
server.port = 56010
Service a (service consumer)
Among service consumers, they must know the port number and ip address of the manufacturer.
Implementation code:
@SpringBootApplication @RestController public class SpringRestConsumerBootstrap { public static void main(String[] args) { SpringApplication. run(SpringRestConsumerBootstrap.class, args); } @Value("${provider . address}") private String providerAddress; @GetMapping(value = "/service") public String service(){ RestTemplate restTemplate = new RestTemplate(); //Call service String providerResult = restTemplate . getFor0bject("http://" + providerAddress + "/service" ,String. class); return "consumer invoke|" + providerResult; } }
Profile:
server.port = 56020 #Address of service manufacturer provider.address = 127.0.0.1:56010
visit http://127.0.0.1:56020/service , output the following:
consumer invoke | provider invoke
It looks perfect, but when you think about it carefully, this solution is different from words and deeds for microservice applications.
First, microservices may be deployed in a cloud environment, and the network location of service instances may be dynamically allocated. In addition, each service generally has multiple instances for load balancing. Due to downtime or upgrade, the network address of the service instance will often change dynamically. Moreover, each service may also add new service nodes to cope with the temporary access pressure. As shown in the figure below:
Based on the above questions, how do services perceive each other? How are services managed? This is the problem of service discovery. As shown below:
In the above figure, the service instance itself does not record the network address of the service producer. All service instances contain service discovery clients.
(1) When each service starts, it will report its network location to the service discovery center. In this way, a service registry will be formed inside the service discovery center. The service registry is the core part of service discovery and a database containing the network addresses of all service instances.
(2) The service discovery client will periodically synchronize the service registry from the service discovery center and cache it in the client.
(3) When a service needs to be requested, the service instance locates the target service network address through the registry. If the target service has multiple network addresses, use the load balancing algorithm to select one from multiple service instances and then issue the request.
To sum up, in the microservice environment, because the network address of service running instances is changing dynamically and the number of service instances is changing dynamically, it is impossible to use a fixed configuration file to record the network address of the service provider, rather than using a dynamic service discovery mechanism to realize mutual perception between microservices. Each service instance will report its own network address, so that the service center forms a complete service registry. Each service instance will obtain the network address of the target service through the service discovery registry, so as to realize the service discovery mechanism.
Comparison between mainstream service discovery and configuration center
At present, there are many service discovery centers on the market: Nacos Eureka. Consul and Zookeeper.
From the above comparison, we can see that as a service discovery center, Nacos has more function support items, and in the long run, Nacos will support the combination of Spring Cloud+Kubernetes in future versions to fill the gap between the two. Under the two systems, the same set of service discovery and configuration management solutions can be adopted, which will greatly simplify the use and auxiliary cost. In addition, Nacos plans to implement Service Mesh, which is also the development trend of micro services in the future.
Nacos service discovery quick start
In this section, we will demonstrate how to use Spring Cloud Alibaba Nacos Discovery to seamlessly integrate spring cloud applications with Nacos. Through some native spring cloud annotations, we can quickly implement the service discovery mechanism of spring cloud microservices, and use Nacos Server as the service discovery center to uniformly manage all microservices.
Spring Cloud service collaboration process
Now, we don't know about some components in Spring cloud. In order to fully understand the QuickStart program, we need to learn the following.
The common integration method of Spring Cloud is to use Feign+Ribbon technology to complete remote calls and load balancing between services, as shown in the following figure:
Concept of load balancing
A service may have multiple instances, so load balancing is used.
In the spring cloud service agreement process, ServiceA invokes ServiceB through load balancing, 'let's learn about load balancing:
Load balancing is the strategy of over - setting user requests (traffic) Allocation is executed on multiple service instances. It is one of the important means for the system to deal with high concurrency, alleviate network pressure and expand the capacity of the server. It is divided into server-side load balancing and client-side load balancing.
Server load balancing
Maintain a list of available service instances in the load balancer. When a client request comes, the load balancing server selects it from the list of available service instances according to a configured rule (load balancing algorithm) to process the client's request. This is the server load balancing.
For example, Nginx performs load balancing through Nginx, the client sends a request to Nginx, and Nginx selects one of multiple servers for access through the load balancing algorithm. That is, the load balancing algorithm is allocated on the server side.
Client service load balancing
Ribbon belongs to client load balancing. The ribbon client will have a service instance address list. Before sending a request, select a service instance through the load balancing algorithm and then access it. This is client load balancing. That is, the load balancing algorithm is allocated on the client.
Ribbon is a client load balancer. Its responsibility is to select appropriate instances from a group of instance lists. How to select them? Depends on the load balancing policy.
IRule, the core component of Ribbon, is a load balancing policy interface. It has the following implementations. We only need to know:
Roundrobin rule * * (default): polling, that is, obtaining the address of the instance in rotation in a certain order.
RandomRile: random, that is to obtain the address of the instance in a random way.
Availability filtering rule: it will first filter out the services in the circuit breaker tripping state due to multiple access faults and the services with concurrent connections exceeding the threshold, and then access the remaining service list according to the polling policy * *;
WeightedResponseTimeRule: calculate the weight of all services according to the average response time. The faster the response time, the greater the service weight, and the higher the probability of being selected;
When starting up, if the statistics are insufficient, the roundrobin rule policy will be used. When the statistics are sufficient, it will switch to
WeightedResponse TimeRule
RetryRule: first obtain the service according to the roundrobin rule policy. If the service acquisition fails, it will retry within the specified time to obtain the available service;
BestAvailableRule: first filter out the services in the circuit breaker tripping state due to multiple access faults, and then select a service with the smallest concurrency;
Introduction to Fegin
Feiga is a declarative and templated HTTP client developed by Netflix. Feign can help us call HTTP API more quickly and gracefully.
Feign means "pretend, disguise, color" in English. It can be understood that the HTTP message request mode is disguised as a simple java interface call mode.
Refer to the example of ServiceA calling ServiceB in Chapter 1. We use Feign to implement this process. The code is as follows:
@SpringBootApplication @RestController public class SpringRestProviderBootstrap { public static void main(String[] args) { SpringApplication. run(SpringRestProviderBootstrap.class, args); } @GetMapping(value = "/service") //Exposure services public String service(){ return "provider invoke"; } }
Feign calling method
1. Declare Feign client
Generate a dynamic proxy object, take the service instance address from the service center and initiate remote call
@FeignClient(value = "serviceB") public interface ServiceBAgent { /** *Query account information according to user name book @param username user name @return account information */ @GetMapping(value = "/service") public String service(); }
2. Service call
@Autowired private ServiceBAgent serviceBAgent. ; //.... slightly serviceBAgent . service(); //.... slightly
Feign will hand over the specific access address of the service B to the ribbon. If the service has multiple instance addresses, the ribbon will select instances using the specified load balancing strategy.
Feign is compatible with spring web annotations (such as @ GetMapping). It will analyze and declare the spring annotations in feign client methods to obtain Http request method, parameter information and return information structure.
When the business calls Feign client method, the proxy class will be called. According to the above analysis results, the proxy class will complete the actual parameter encapsulation, remote http request, return result encapsulation and other operations.
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</ artifactId> </ dependency>
Feign integrates Ribbon by default and can be used directly
You also need to mark @ EnableFeignClients in the spring cloud startup class to indicate that the project starts the Feign client:
@SpringBootApplication @EnableDiscoveryClient @EnableFeignClients public class SpringRestlonsumerBootstrap { public static void main(String[] args) { SpringApplication. run(SpringRestConsumerBootstrap.class, args);
Create parent project
Create a maven project, as shown below:
Pom. Dependencies to be introduced in the XML file:
<dependencyManagement> <dependencies> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2.1.0.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Greenwich.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.1.3.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>2.5.3</version> </plugin> </plugins> </build>
Service producer
The following steps demonstrate how to register a service producer with Nacos.
Create a maven sub project of the service producer, as shown in the following figure:
1.pom.xml configuration
Including Spring Cloud Feign component, Spring Cloud Alibaba Nacos Discovery component and Spring boot web related component dependencies.
<dependencies> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> </dependencies>
2.application.yml configuration. Some basic configurations of Nacos must also be in application The YML (or application.properties) configuration is as follows: yml
server: port: 56010 #Boot port spring: application: name: quickstart-provider cloud: nacos: discovery: server-addr: 127.0.0.1:8848 logging: level: root: info org.springframework: info
Note:spring. cloud. nacos. discovery. Server addr specifies the network address and port number of the Nacos Server.
3. Provider service implementation
@RestController public class ProviderController { private static final Logger LOG= LoggerFactory.getLogger(ProviderController.class); @GetMapping("/service") public String service(){ Log.info("provider invoke"); return "provider invoke"; } }
4. Startup
Service consumers
1. Create a service consumer module
2. POM to service consumers Add dependencies in XML. The added dependencies are the same as those in the service producer, which will not be demonstrated here.
3.application.yml configuration
server: port: 56020 #Start port command line injection spring: application: name: quickstart-consumer cloud: nacos: discovery: server-addr: 127.0.0.1:8848
4. Definition of provider remote agent
@FeignClient(value = "quickstart-provider") public interface ProviderClient { @GetMapping("/service") public String service(); }
@FeignClient annotation can realize service discovery, that is, production services will be called in consumer services, so as to establish the relationship between services.
5. Consumer service implementation
@RestController public class ConsumerController { private static final Logger LOG= LoggerFactory.getLogger(ConsumerController.class); @Autowired private ProviderClient providerClient; @GetMapping("/service") public String service(){ LOG.info("consumer invoke"); String providerResult=providerClient.service(); return "consumer invoke"+"|"+providerResult; } }
6. Write a startup class
After the startup class is successfully started, an additional service will appear in the nacos registry, as shown in the following figure:
Test service discovery
Invoking production services in consumer services is shown below.
The interface for accessing consumer services is as follows: