I. Introduction to Eureka
1. What is service governance
Spring Cloud encapsulates the Eureka module developed by Netflix to achieve service governance. In the traditional RPC remote call framework, it is complicated to manage the dependency relationship between each service and service, so it is necessary to use service governance to manage the dependency relationship between services, which can realize service invocation, load balancing, fault tolerance, etc., and realize service discovery and registration.
2. What is service registration and discovery
Eureka adopts CS design architecture. Eureka Sever serves as the server for service registration function. It is the service registry. Other microservices in the system use Eureka’s clients to connect to Eureka Server and maintain heartbeat connections. In this way, the maintenance personnel of the system can monitor the normal operation of each micro-service in the system through Eureka Server.
In service registration and discovery, there is a registry. When the server is started, it aliases the information of the current server to the registry, such as the service address and correspondence address. Another party (consumer service provider), in the form of the alias to registry access to the actual service address, and then realize local RPC calls RPC remote invocation framework core design idea: lies in the registry, because use registry management a dependency between each service and the service (service governance concept). In any RPC remote framework, there is a registry that holds information about the service address (interface address).
3. Eureka consists of two components :Eureka Server and Eureka Client
Eureka Server provides service registration services
After each micro-service node is configured and started, it will be registered in EurekaServer. In this way, the service registry in EurekaServer will store the information of all available service nodes, and the information of service nodes can be directly seen on the interface.
EurekaClient is accessed through a registry
It is a Java client designed to simplify Eureka Server interactions and also has a built-in load balancer that uses round-robin load algorithms. After the application is started, the heartbeat is sent to the Eureka Server (default interval is 30 seconds). If EurekaServer does not receive a heartbeat from a node within multiple heartbeat cycles, EurekaServer will remove the node from the service registry (default: 90 seconds).
Ii. Construction of single point Eureka
1. Create the module environment (Cloud-Eureka-Server7001)
Pom file
Differences between the old version and the new version:
<! -- Eureka old and new -->
<! -- Old version (2018) -->
<dependency>
<groupid>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<! -- Now new version (2020.2) --><! -- We use the latest -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
Copy the code
Now use the new version and introduce all dependencies:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cloud2021</artifactId>
<groupId>com.atguigu</groupId>
<version>1.0.0 - the SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.atguigu.springcloud</groupId>
<artifactId>cloud-eureka-server7001</artifactId>
<dependencies>
<! --eureka-server-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<! -- Introduced a generic API package that allows you to pay Entity using Payment -->
<dependency>
<groupId>com.atguigu.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<! --boot web actuator-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<! -- General General configuration -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
</project>
Copy the code
Yaml files
server:
port: 7001
eureka:
instance:
hostname: locathost # Eureka server instance name
client:
#false: do not register yourself with the registry.
register-with-eureka: false
#false indicates that my end is the registry and my responsibility is to maintain the service instance, not to retrieve the service
fetch-registry: false
service-url:
This address is used by the Eureka server.
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
Copy the code
Write programs
Start the class:
@SpringBootApplication
@EnableEurekaServer
public class EurekaMain7001 {
public static void main(String[] args) { SpringApplication.run(EurekaMain7001.class,args); }}Copy the code
Note that this is the Eureka server.
Start and go to Eureka. You can see the Eureka registry page.
2. Inject other modules into Eureka
Introduction of depend on
Module 8001 introduces dependencies.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
Copy the code
annotations
Annotate the Eureka customer as the user.
@SpringBootApplication
@EnableEurekaClient
public class PaymentMain8001 {
public static void main(String[] args) { SpringApplication.run(PaymentMain8001.class,args); }}Copy the code
Yaml configuration
eureka:
client:
# indicates to register with eurekaServer server
register-with-eureka: true
The default value is true. Clusters must be set to true to work with the ribbon to ensure load balancing
fetch-registry: true
service-url:
defaultZone: http://localhost:7001/eureka
Copy the code
Open discovery registered in:
The same is true for module 80.
Introduce dependencies, annotate, and write YAML.
eureka:
client:
# indicates whether to register yourself in Eurekaserver. The default is true.
register-with-eureka: true
Whether to fetch existing registration information from EurekaServer. Default is true. The cluster must be set to True to use load balancing with the ribbon
fetchRegistry: true
service-url:
defaultZone: http://localhost:7001/eureka
Copy the code
The test found that the service center was joined.
3. Construction of Eureka cluster
1. Eureka cluster principle description
In the case of multiple Eureka service clusters, each Eureka needs to register the information of other EureKas to ensure that they can call each other.
2. Set up EurekaServer cluster
Create the cloud-Eureka-Server7002 module, same as 7001. Introduce the POM files into the corresponding dependencies.
Create the Eureka cluster
Eureka-instance-hostname for 7001 and 7002 needs to be modified. Find the C:\Windows\System32\drivers\etc\hosts file.
Add a configuration using an administrator.
127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
Copy the code
Yaml modified configuration, module 7001:
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com # Eureka server instance name
client:
#false: do not register yourself with the registry.
register-with-eureka: false
#false indicates that my end is the registry and my responsibility is to maintain the service instance, not to retrieve the service
fetch-registry: false
service-url:
This address is used by the Eureka server.
defaultZone: http://eureka7002.com:7002/eureka/
Copy the code
7002 module:
server:
port: 7002
eureka:
instance:
hostname: eureka7002.com
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://eureka7001.com:7001/eureka/
Copy the code
7002 Build main startup class:
@SpringBootApplication
@EnableEurekaServer
public class EurekaMain7002 {
public static void main(String[] args) { SpringApplication.run(EurekaMain7002.class,args); }}Copy the code
Start the test.
Testing:
- localhost:7001
- localhost:7002
- eureka7001:7001
- eureka7002:7002
Found no problem.
The payment and order modules join the cluster
Module 8001 YAML needs to be modified:
# Used to be a single point Eureka
#defaultZone: http://localhost:7001/eureka
# Now it's cluster, both eurekas need to register
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
Copy the code
Same for port 80:
#defaultZone: http://localhost:7001/eureka
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
Copy the code
Start the test.
Localhost/consumer/payment/get / 1 = = = > test successfully.
3. Set up payment service provider cluster
What this means is that if Eureka doesn’t create the cluster, if Eureka has a single point of failure, the program will crash. Similarly, service providers may also fail. If a server fails and no one is left to handle it, it will also fail. In this case, create a cluster for the provider to avoid a single point of failure.
Creating a new order module (Cloud-provider-Payment8002)
As with 8001, create and paste POM files, as well as the code of each layer (DAO, Service, controller) can be pasted.
The port number of the YAML file should be changed to 8002.
Modify the configuration
You can modify the configuration of the 8001 and 8002 payment modules to see who handles it. The Controller layer adds serverPort, which can be obtained directly from YAML. When you output it, you can see who did it.
@RestController
@Slf4j
public class PaymentController {
@Resource
private PaymentService paymentService;
@Value("${server.port}")
private String serverPort;
@PostMapping(value = "/payment/create")
public CommonResult<Payment> create(@RequestBody Payment payment){
int result = paymentService.create(payment);
log.info([insert result] :{},result);
if (result > 0) {return new CommonResult(200."Database inserted successfully,serverPort=" + serverPort,result);
}else{
return new CommonResult(444."Failed to insert database".null); }}@GetMapping(value = "/payment/get/{id}")
public CommonResult getPaymentById(@PathVariable("id") Long id){
Payment payment = paymentService.getPaymentById(id);
log.info("[Query result] :{}",payment);
if(payment ! =null) {return new CommonResult(200."Database query succeeded,serverPort=" + serverPort,payment);
}else{
return new CommonResult(444."There's no record... Where id = "; + id,null); }}}Copy the code
To start, see the registry:
Port 7001, registered with 7002, has 1 order-service and 2 Payment-service. Same thing with 7002.
Test: localhost/consumer/payment/get / 1, the findings are also 8001 port processing logic.
This is because the consumption module calls the payment module, but the consumption module line contains the port number to access:
public static final String PAYMENT_URL = "http://localhost:8001";
Copy the code
The code needs to be modified so that both payment modules can work together.
Cloud-payment-service is the name of the PAYMENT SERVICE. In this way, we can find two ports 8001,8002 according to the SERVICE name instead of the port number. Modification:
public static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";
Copy the code
In addition, the load balancing function of the RestTemplate must be enabled.
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate(a){
return newRestTemplate(); }}Copy the code
This restarts the test and finds ports 8001 and 8002 polling.
Other operations
1. Delete the host name
Once again, we found that the name of the host was exposed at the back of the registry. We don’t want to expose this information.
Add one more line at the end of YAML so that the test is displayed with its configured name.
server:
port: 8001
spring:
application:
name: cloud-payment-service
datasource:
type: com.alibaba.druid.pool.DruidDataSource The current data source operation type
driver-class-name: org.gjt.mm.mysql.Driver Mysql driver package
url: jdbc:mysql://localhost:3306/springcloud2021? useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: 123
mybatis:
mapperLocations: classpath:mapper/*.xml
type-aliases-package: com.atguigu.springcloud.entities Package for all Entity alias classes
eureka:
client:
# indicates to register with eurekaServer server
register-with-eureka: true
The default value is true. Clusters must be set to true to work with the ribbon to ensure load balancing
fetch-registry: true
service-url:
#defaultZone: http://localhost:7001/eureka
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
instance:
instance-id: payment8001
Copy the code
If the other two services do not fail, restart the test for both.
2. Access path Displays the IP address
Add prefer-ip-address: true to the configuration.
instance:
instance-id: payment8002
prefer-ip-address: true
Copy the code
Once configured, place your mouse over Payment8002 to see the IP address displayed below.
3. Service Discovery
You want services registered with Eureka to display some information that can be configured in this way.
We need to introduce the DiscoveryClient class to help us. Introduced in the PaymentController layer.
@Resource
private DiscoveryClient discoveryClient;
Copy the code
Note that there are two DiscoveryClients, introduce this:
import org.springframework.cloud.client.discovery.DiscoveryClient;
Copy the code
If you introduce it wrong, the method won’t come in.
@GetMapping(value = "/payment/discovery")
public Object discovery(a){
List<String> services = discoveryClient.getServices();
for (String service:services){
log.info(【 contents 】service:{},service);
}
List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
for (ServiceInstance instance :instances){
log.info(instance.getInstanceId() +
"\t" + instance.getHost() + "\t" + instance.getPort() + "\t" + instance.getUri());
}
return this.discoveryClient;
}
Copy the code
Annotate @enableDiscoveryClient on the main startup class:
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
public class PaymentMain8001 {
public static void main(String[] args) { SpringApplication.run(PaymentMain8001.class,args); }}Copy the code
Test, website:
Background:
4. Eureka’s self-protection mechanism
In the early days, entering the Eureka registry might result in a red:
EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY’RE NOT. RENEWALS ARE LESSER THANTHRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUSTTO BE SAFE
That’s going into protected mode.
Protection mode function
It is used to protect a group of clients and the Eureka Server when network partitions exist. Once in protected mode, Eureka Server will attempt to protect the information in its service registry and will not delete the data in the service registry, that is, will not unregister any microservices.
In other words, Eureka will not immediately clean up a microservice when it becomes unavailable, but will still save the information of the microservice. Belongs to the AP branch in CAP.
What is self-protection mode?
By default, EurekaServer will log out of a microservice instance if it does not receive a heartbeat for a certain amount of time (90 seconds by default). However, when a partition failure occurs (delay, lag, congestion) and the microservice cannot communicate with EurekaServer properly, this behavior can become very dangerous — the microservice itself is actually healthy and should not be logged out. Eureka solves this problem by going into “self-protected mode” — when the EurekaServer node loses too many clients in a short period of time (possibly due to a network partition failure), the node goes into self-protected mode.
Self-protection mechanism
Self-protection mechanism: By default, EurekaClient periodically sends heartbeat packets to the EurekaServer
If Eureka does not receive a heartbeat packet from EurekaClient within a certain period of time (90 seconds by default), the service will be removed from the service registration list. However, a large number of heartbeat instances of EurekaClient will be lost within a short period (90 seconds). At this time, Eurekaserver will turn on the self-protection mechanism and will not remove the service (this phenomenon may occur if the network is disconnected but EurekaClient is down, then if you change to another registry, if there is no heartbeat within a certain period of time, the service will be removed, so there is a serious error. Because the client can still send heartbeat normally, it is just a network delay problem, and the protection mechanism is created to solve this problem).
How do I turn off self-protection mode
- Yaml Settings of module 7001:
eureka.server.enable-self-preservation = false
eureka:
.
server:
# Turn off the self-protection mechanism to ensure that unavailable services are kicked out in time
enable-self-preservation: false
eviction-interval-timer-in-ms: 2000
Copy the code
The following red indicates that self-protection mode has been turned off.
- 8001 module
instance:
instance-id: payment8001
prefer-ip-address: true
Heartbeat detection and renewal time
Make sure the registry can remove the service even after the service is closed
#Eureka Interval in seconds for the client to send heartbeat to the server (default is 30 seconds)
lease-renewal-interval-in-seconds: 1
#Eureka Server waiting time limit after receiving the last heartbeat, in seconds (default is 90 seconds)
lease-expiration-duration-in-seconds: 2
Copy the code
Now it is sent once in 1ms, and will be removed if timeout occurs. Therefore, port 8001 is closed, and the registry detects that 8001 has no heartbeat, so it will be directly removed and will not be retained.