I Build a simple microservice project
1. Evolution from monomer architecture to microservice architecture
The single architecture we first came into contact with has only one project for the whole system. The packaging is often made into a war package and then deployed to a single tomcat. This is the single architecture, as shown in the figure:
Advantages of single architecture
1. Simple structure and deployment
2. Less hardware resources required
3. Cost savings
shortcoming
1. Version iteration is slow, and often changing a code will affect the overall situation
2. Cannot satisfy certain concurrent access
3. It is difficult to maintain the code. All the codes in one project are at risk of being modified by others
With the expansion of business and the development of the company, the single architecture can not meet our needs slowly. We need to change the architecture. The simplest way we can think of is to add machines and expand the application horizontally. As shown in the figure:
This architecture seems to solve our problem temporarily, but after the number of users increases slowly, we can only solve it by adding machines horizontally. There will still be problems of slow version iteration and difficult code maintenance. It is impossible for users to expand the capacity of the whole module because there are too many users who need to expand the capacity of the whole module. Therefore, it is impossible for users to expand the capacity of the whole module. Therefore, it is necessary to split the whole project according to modules. The split architecture diagram is as follows:
After the module is split, the communication between modules needs to be carried out through interface call, and the load balancing between modules is carried out through shunting software. This architecture solves the problems of resource waste and code management in front, because we split the system, and each module has a separate project. For example, if I modify the commodity module, I don't need to worry about whether it will affect the shopping cart module. However, this architecture expansion is very troublesome. Once you need to add machines horizontally or reduce machines, you need to modify the nginx configuration. Once there are more machines, the amount of nginx configuration is an impossible task. OK, then the SOA Service governance framework came into being. The architecture diagram is as follows:
The SOA framework based on the registry is very convenient to expand, because there is no need to maintain the shunting tool, but when we start the application, we will register the service to the registry through http.
There are generally three roles in SOA framework: 1. Registry 2. Service provider 3. Service consumer
1. Registration Center
A list of services is maintained in the registry
2. Service provider
When the service provider starts, it will register itself in the registration center
3. Service consumer
When the service consumer starts, the list of the services of the registration center is obtained, and then one of them is called from the service list when it is called.
Characteristics of microservice Engineering:
1. Flexible expansion
2. Each application is small in scale
3. Clear service boundary and perform their respective duties
4. With more packaged applications, CI continuous integration tools are often needed
2. Simple microservice engineering construction
1. Establishment of Registration Center (eureka server: Netflix eureka server)
In spring cloud, we choose eureka as the registry. The spring cloud project is based on the springboot project. pom. jar package dependency in XML:
<!--parent--> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.2.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <!--Springcloud Version of--> <properties> <java.version>1.8</java.version> <spring-cloud.version>Hoxton.SR1</spring-cloud.version> </properties> <!--Eureka Server initiator import--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <!--Springcloud Dependent warehouse import--> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
application.properties configuration file (cannot be called bootstrap.properties)
server.port=8763 eureka.instance.hostname=localhost #Register with eureka eureka.client.registerWithEureka=false #Whether to pull the registration information from eureka eureka.client.fetchRegistry=false ##Expose the address of eureka service # http://localhost:8763/eureka/ eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/ #In the self-protection mode, when there are network partitions and eureka loses too many clients in a short time, it will enter the self-protection mode, that is, if a service does not send heartbeat for a long time, eureka will not delete it. The default is true eureka.server.enable-self-preservation=true #The time interval for eureka server to clean up invalid nodes. The default is 60000 milliseconds, that is, 60 seconds eureka.server.eviction-interval-timer-in-ms=60000 #Service manual offline delete request http://localhost:8763/eureka/apps/MICRO-ORDER/localhost:xxx:8084
Startup class
package len.hgy; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @SpringBootApplication @EnableEurekaServer public interface EurekaApplication { public static void main(String[] args) { SpringApplication.run(EurekaApplication.class,args); } }
see
http://localhost:8763/
2. Service provider (eureka client: Netflix eureka client)
Pom's jar package depends on. Everything else is the same as eureka server, except that the service provider needs to register the service with eureka server, so the service provider is eureka's client, so it needs to import the initiator of eureka client.
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
bootstrap.properties
spring.application.name=micro-order server.port=8084 eureka.client.serviceUrl.defaultZone=http://localhost:8763/eureka/ # There is a default configuration #Service renewal, heartbeat interval eureka.instance.lease-renewal-interval-in-seconds=30 #If you do not receive a new heartbeat within 90 seconds from the previous heartbeat time, call the rejection service eureka.instance.lease-expiration-duration-in-seconds=90 #It indicates how long the eureka client takes to pull the service registration information. The default is 30 seconds eureka.client.registry-fetch-interval-seconds=30
Startup class
package len.hgy; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication(scanBasePackages = {"len.hgy"}) // Register with eureka @EnableEurekaClient @MapperScan("len.hgy.dao") public class MicroOrderApplication { public static void main(String[] args) { SpringApplication.run(MicroOrderApplication.class, args); } }
3. Reeuka client: reeuka client
pom is basically the same as the property configuration file. The consumer is responsible for calling the service provider, so the client needs to be called
rely on
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
bootstrap.properties
#Register with eureka eureka.client.registerWithEureka=true #Whether to pull the registration information from eureka eureka.client.fetchRegistry=true eureka.client.serviceUrl.defaultZone=http://localhost:8763/eureka/
Startup class
package len.hgy; import len.hgy.service.feign.StudentService; import len.hgy.service.feign.TeacherServiceFeign; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @SpringBootApplication(scanBasePackages = {"len.hgy"}) //Register with eureka @EnableEurekaClient //Turn on the function of circuit breaker //@EnableCircuitBreaker //Enable feign support. clients specifies which class to enable feign //@EnableFeignClients(clients = {StudentService.class,TeacherServiceFeign.class}) public class MicroWebApplication { @Bean // Load balancing annotation @LoadBalanced RestTemplate restTemplate() { return new RestTemplate(); // Use this bean instance to load balance } public static void main(String[] args) { SpringApplication.run(MicroWebApplication.class,args); } }
When a service is called, it is called according to the service name of the service provider
public static String SERVIER_NAME = "micro-order"; @Override public List<ConsultContent> queryContents() { s.incrementAndGet(); List<ConsultContent> results = restTemplate.getForObject("http://" + SERVIER_NAME + "/user/queryContent", List.class); return results; }
The name of the service provider and the interface name of the service provider can complete the call. When the service provider and service consumer start, they will register the service in the service registry. The eureka server can also view the service registration through the interface:
http://localhost:8763/
Call web interface test
// controller package len.hgy.controller; import len.hgy.bean.ConsultContent; import len.hgy.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController @RequestMapping("/user") public class UserController { @Autowired private UserService userService; @RequestMapping("/queryUser") public List<ConsultContent> queryUser() { return userService.queryContents(); } @RequestMapping("/queryMonitor") public String queryMonitor() { return userService.queryMonitor(); } }
http://localhost:8083/user/queryUser
3. Eureka user authentication
When connecting to eureka, you need to bring the user name and password of the connection
Eureka server transformation
Add security initiator
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> // spring-boot </dependency>
Turn off csrf authentication
package hgy.security; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; @EnableWebSecurity public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { //Turn off csrf http.csrf().disable(); //Enable authentication: login in URL format must be httpBasic http.authorizeRequests().anyRequest().authenticated().and().httpBasic(); } }
application.properties configuration
# Turn on basic verification and set login user name and password security.basic.enabled=true spring.security.user.name=admin spring.security.user.password=admin
Eureka client transformation
When connecting with eureka, you should bring your user name and password
#eureka.client.serviceUrl.defaultZone=http://localhost:9876/eureka/ eureka.client.serviceUrl.defaultZone=http://admin:admin@localhost:9876/eureka/
At this time, the login page needs to enter the user password
http://localhost:9876/
4. Service renewal
After the client starts to register its own service list with eureka, it needs to send a heartbeat to the eureka server every other period of time to prove that it is still alive. When eureka receives the heartbeat request, it will know that the client is still alive and maintain the service list information of the client. Once the client fails to send heartbeat to eureka server on time due to some reasons, eureka may think that your client has hung up, and it may delete the service from the service list.
Configuration of renewal and maintenance
Client configuration
# Client configuration #Service renewal, heartbeat interval eureka.instance.lease-renewal-interval-in-seconds=30 #If no new heartbeat is received within 90 seconds from the previous heartbeat time, the service will be rejected eureka.instance.lease-expiration-duration-in-seconds=90 #It indicates how long the eureka client takes to pull the service registration information. The default is 30 seconds eureka.client.registry-fetch-interval-seconds=30
Server configuration
# Server configuration #In the self-protection mode, when there are network partitions and eureka loses too many clients in a short time, it will enter the self-protection mode, that is, if a service does not send heartbeat for a long time, eureka will not delete it. The default is true eureka.server.enable-self-preservation=true #Eureka Server will count whether the heartbeat failure rate is lower than 85% within 15 minutes during operation. If it is lower than 85%, Eureka Server will protect these instances eureka.server.renewal-percent-threshold=0.85 #The time interval for eureka server to clean up invalid nodes. The default is 60000 milliseconds, that is, 60 seconds eureka.server.eviction-interval-timer-in-ms=60000
5. Eureka health test
Eureka's default health detection is to check whether the service connection is UP or DOWN, and then the client will only call the service in UP status. However, in some cases, although the service connection is good, some interfaces of the service may not be normal, and the interface call may fail due to the need to connect to Redis, mongodb or DB, So theoretically, although the service can be called normally, it is not a healthy service. Therefore, it is necessary for us to do custom health detection for this situation.
application.properties configuration
Turn on health detection
#Health testing eureka.client.healthcheck.enabled=true
Custom health detection code
@Configuration public class MicroWebHealthIndicator implements HealthIndicator { @Override public Health health() { //This status is whether the database connection is OK if(UserController.canVisitDb) { // Business ID, which is more specific to the connection of db,redis, mysql, etc return new Health.Builder(Status.UP).build(); } else { return new Health.Builder(Status.DOWN).build(); } } }
jar
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
6. Service offline
For example, in some cases, the service host goes down unexpectedly, which means that the service cannot give eureka heartbeat information. However, eureka relies on maintaining the service for 90s when it does not receive heartbeat. Within this 90s, a client may call the service, which may lead to call failure. Therefore, we must have a mechanism that can manually remove the down services from the eureka service list immediately to avoid being called by the service caller.
Call the interface of service offline: this interface is the interface of calling eureka server
http://localhost:9876/eureka/apps/micro-order/localhost:micro-order:8765
delete request
be careful:
If the service is not shut down during the test, there will always be a heartbeat, resulting in manual offline failure
In addition, manually stopping the idea service will directly remove the service and will not keep it alive for 90s, because it is a normal shutdown and the client automatically goes offline
You can simulate abnormal downtime by yourself through the following commands
windows
netstat -nao | findstr 8765 taskkill /f /pid 19016 # At this time, there are still services in eureka's service list, and eureka will delete them when the maintenance time passes
linux
ps -aux | grep 8765 kill -9 19016
Pause service interface
PUT http://localhost:9876/eureka/apps/micro-order/localhost:micro-order:8765?value=OUT_OF_SERVICE
Online service
PUT http://localhost:9876/eureka/apps/micro-order/localhost:micro-order:8765?value=UP
7. Eureka high availability
The architecture of Eureka hot backup is as follows:
There are multiple eureka services in the whole microservice. Each eureka service is copied to each other, and the services registered by the client will be copied to other nodes in the eureka cluster. In fact, it simply means that each node of eureka copies each other.
The specific configuration is as follows:
The eureka server with port 9878 registers itself with the eureka server with port 9877
# Multiple are separated by commas server.port=9877 eureka.client.serviceUrl.defaultZone=http://localhost:9878/eureka/
The eureka server with port 9877 registers itself with the eureka server with port 9878
# Multiple are separated by commas server.port=9878 eureka.client.serviceUrl.defaultZone=http://localhost:9877/eureka/
configuration file
application-9877.properties
application-9878.properties
When starting, start according to the specified configuration file
java -jar netflix-eureka-server-1.0-SNAPSHOT.jar --spring.profiles.active=9877 --server.port=9877
java -jar netflix-eureka-server-1.0-SNAPSHOT.jar --spring.profiles.active=9878 --server.port=9878
This is the configuration
eureka.client.serviceUrl.defaultZone=http://admin:admin@localhost:9877/eureka/