Overall website architecture
SpringCloud and springBoot
-
SpringBoot focuses on developing individual micro services quickly and easily.
-
SpringCloud is a microservice coordination and management framework that focuses on the overall situation. It integrates and manages individual microservices developed by SpringBoot, and provides integrated services between microservices: configuration management, service discovery, circuit breaker, routing, micro agent, event bus, global lock, decision-making campaign, distributed session and so on.
-
. SpringBoot can be used independently of SpringClooud to develop projects, but SpringCloud is inseparable from SpringBoot and belongs to dependency
-
Conclusion: SpringBoot focuses on the rapid and convenient development of individual micro services, and SpringCloud focuses on the overall service governance framework
Interview questions
1.1. What is micro service?
1.2 how do microservices communicate independently?
1.3 what are the differences between SpringCloud and Dubbo?
1.4. SpringBoot and SpringCloud, please talk about your understanding of them
1.5. What is service fusing? What is service degradation
1.6 what are the advantages and disadvantages of microservices? Tell me about the pitfalls you encountered in project development
1.7. What are the micro service technology stacks you know? Please list one or two
1.8. eureka and zookeeper can provide the functions of service registration and discovery. Please tell us the difference between the two?
Reference documents
Spring Cloud Netflix Chinese document reference manual Chinese version
Spring Cloud Chinese website - official document Chinese version
Basic environment construction
Parent project dependency
Empty maven project
<modules> <module>springCloudapi</module> <module>springCloud-provider-dept-8001</module> <module>springcloud-consumer-dept-80</module> </modules> <properties> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> </properties> <!--Packaging method--> <packaging>pom</packaging> <dependencyManagement> <dependencies> <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies --> <!--springCLoud--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Greenwich.SR3</version> <type>pom</type> <scope>import</scope> </dependency> <!--sprinyBoot--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.3.7.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <!--database--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.22</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.8</version> </dependency> <!--Springboot starter--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.3</version> </dependency> <!--junit--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.1</version> </dependency> <!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.22</version> </dependency> <!--log4j--> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.2.3</version> </dependency> </dependencies> </dependencyManagement>
API
Entity class provider
No need to define the version number, it will be obtained from the parent project!!!
<dependencies> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies>
@Data @NoArgsConstructor @Accessors(chain = true)//Chained writing @ Builder //Support dept.setname() setDeptno(); public class Dept implements Serializable { private long deptno; private String dname; private String db_source; public Dept(String dname){ this.dname=dname; } }
Provider-8001
springboot project
rely on
Note that another project entity is imported as a dependency: the spring cloud API
<dependencies> <!--You need to get the entity class, so configure it api module--> <dependency> <groupId>org.example</groupId> <artifactId>springCloudapi</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency> <!--test--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-test</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--jetty--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId> </dependency> <!--Hot deployment--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> </dependencies>
springboot configuration
server: port: 8001 mybatis: type-aliases-package: com.yang.pojo config-location: classpath:mybatis/mybatis-config.xml #It's no use mapper-locations: classpath:mybatis/mapper/*.xml #Important, register mapper spring: application: name: springCloud-provider-dept datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/db01?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8 password: 123456 username: root
Dao
@Repository @Mapper public interface DeptDao { boolean addDept(Dept dept); Dept queryDeptById(long deptno); List<Dept> queryAll(); }
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!--namespace = Bind a corresponding Dao/Mapper Interface --> <mapper namespace="com.yang.dao.DeptDao"> <select id="queryAll" resultType="dept" > select * from db01.dept </select> <insert id="addDept" parameterType="dept"> insert into dept (dname,db_source) values (#{dname},DATABASE()) </insert> <select id="queryDeptById" resultType="dept"> select * from dept where deptno=#{deptno} </select> </mapper>
Service
@Service public class DeptServiceImpl implements DeptService{ @Autowired private DeptDao deptDao; @Override public boolean addDept(Dept dept) { return deptDao.addDept(dept); } @Override public Dept queryDeptById(long deptno) { return deptDao.queryDeptById(deptno); } @Override public List<Dept> queryAll() { return deptDao.queryAll(); } }
Controller
@RestController public class DeptController { @Autowired private DeptService deptService; @PostMapping("/dept/add") public boolean addDept(@RequestBody Dept dept){ return deptService.addDept(dept); } @GetMapping("/dept/get/{deptno}") public Dept getDept(@PathVariable("deptno") long deptno){ return deptService.queryDeptById(deptno); } @GetMapping("/dept/list") public List<Dept> list(){ return deptService.queryAll(); } }
Consumer-80
On the consumer side, there is no service layer, only the Controller, which can remotely request the address of the Provider to provide services to customers
)
Dependency: spring cloud API should also be introduced
<dependencies> <dependency> <groupId>org.example</groupId> <artifactId>springCloudapi</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--Hot deployment--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> </dependencies>
Configure port:
server: port: 80
Register a tool in Config: RestTemplate
@Configuration public class MyConfig { @Bean public RestTemplate restTemplate() { return new RestTemplate(); } }
The Controller implements remote call:
restTemplate.getForObject/postForObject and other methods are selected according to the request method to be called. For example, when calling the "/ dept/add" request of the provider, PostMapping is used in the provider to process the request, so postForObject is used to send the request
@RestController public class DeptConsumerController { //The consumer does not have a service layer @Autowired //You need to manually register beans in config private RestTemplate restTemplate;//Provide a variety of convenient methods to access remote http services and a simple Restful service template private static final String REST_URL_PREFIX="http://localhost:8001"; @GetMapping("/consumer/dept/get/{id}") public Dept get(@PathVariable("id")long id){ return restTemplate.getForObject(REST_URL_PREFIX+"/dept/get/"+id,Dept.class); } @RequestMapping ("/consumer/dept/add") public boolean addDept(Dept dept){ return restTemplate.postForObject(REST_URL_PREFIX+"/dept/add",dept,Boolean.class); } @GetMapping("/consumer/dept/list") public List<Dept> list(){ return restTemplate.getForObject(REST_URL_PREFIX+"/dept/list",List.class); } }
Eureka
Self protection mechanism
When a micro service is unavailable at a certain time, eureka will not clean it immediately, but will still save the information of the micro service!
- By default, if EurekaServer does not receive the heartbeat of a micro service instance within a certain period of time, EurekaServer will log off the instance (90 seconds by default). However, when the network partition fails, there is no normal traffic between the microservice and Eureka, and the above behavior may become very dangerous - because the microservice itself is actually healthy, and the service should not be cancelled at this time. Eureka solves this problem through self-protection mechanism - when Eureka server node loses too many clients in a short time (network partition failure may occur), the node will enter self-protection mode. Once in this mode, EurekaServer will protect the information in the service registry and will not delete the data in the service registry (that is, it will not log off any microservices). When the network fault recovers, the EurekaServer node will automatically exit the self-protection mode
- In self-protection mode, EurekaServer will protect the information in the service registry and will not log off any service instances. When the number of heartbeats it receives recovers above the threshold, the EurekaServer node will automatically exit the self-protection mode. Its design philosophy is to retain the wrong service registration information rather than blindly cancel any possible healthy service instances. In a word: it's better to live than to die
- To sum up, self-protection mode is a security protection measure to deal with network abnormalities. Its architectural philosophy is that it would rather retain all micro services at the same time (both healthy and unhealthy micro services will be retained), rather than blindly cancel any healthy micro services. Using self-protection mode can make Eureka cluster more robust and stable
- In spring cloud, you can use Eureka server. Enable se1f preservation = false disable self-protection mode
[it is not recommended to close the self-protection mechanism]
Registration Center
Since it cannot be started normally, the springboot version of the parent project is described as follows:
<!--Import eureka Error reporting reduced version: 2.1.6.RELEASE, 2.3.7.RELEASE--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.1.6.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency>
Dependency:
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka-server</artifactId> <version>1.4.6.RELEASE</version> </dependency> <!--Hot deployment--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency>
springBoot configuration:
server: port: 7001 eureka: instance: hostname: localhost # Instance name of Eureka server client: register-with-eureka: false #Do you register yourself with the eureka registry fetch-registry: false # false indicates your own registry service-url: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
The main startup class starts Eureka: @ EnableEurekaServer
@SpringBootApplication @EnableEurekaServer //The startup class of EurekaServer server can accept others to register public class EurekaServer_7001 { public static void main(String[] args) { SpringApplication.run(EurekaServer_7001.class,args); } }
Test:
Run the main startup class to access: http://localhost:7001/
Provider
Add to the previously built environment:
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> <version>1.4.6.RELEASE</version> </dependency>
eureka: instance: hostname: localhost # Instance name of Eureka server instance-id: springCloud-provider-dept-hystrix-8001 #Modify the default description information on eureka prefer-ip-address: true # Display the real ip address instead of localhost client: #register-with-eureka: true #Do you register yourself with the eureka registry #fetch-registry: true # false indicates your own registry service-url: defaultZone: http://${eureka.instance.hostname}:7001/eureka/
Start Eureka registration on the main startup class: @ EnableEurekaClient
//Manually register the startup class @SpringBootApplication @EnableEurekaClient //Automatically register in Eureka after service startup public class DeptProvider_8001 { public static void main(String[] args) { SpringApplication.run(DeptProvider_8001.class,args); } }
Information configuration:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
info: app.name: yang-springcloud company.name: haimeiyou
Service discovery
Take the provider as an example:
Import dependency:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
Open discovery service: @ EnableDiscoveryClient
@EnableDiscoveryClient//Service discovery @SpringBootApplication//Manually register the startup class @EnableEurekaClient //Automatically register in Eureka after service startup public class DeptProvider_8001 { public static void main(String[] args) { SpringApplication.run(DeptProvider_8001.class,args); } }
Using: DiscoveryClient
@RestController public class DeptController { //It can obtain some configuration information and specific micro services @Autowired private DiscoveryClient client; @RequestMapping("/dept/discovery") public Object discovery(){ List<String> services = client.getServices(); System.out.println("discovery==>services"+services); List<ServiceInstance> instances = client.getInstances("SPRINGCLOUD-PROVIDER-DEPT"); for (ServiceInstance instance : instances) { System.out.println(instance.getHost()+"\t" +instance.getPort()+"\t" +instance.getUri()+"\t" +instance.getServiceId() ); } return this.client; } }
colony
)
Three registration centers are configured: eureka7001, eureka7002 and eureka7003
Service URL binds addresses other than itself
- eureka7001
server: port: 7001 eureka: instance: hostname: Eureka7001 # Instance name of Eureka server client: register-with-eureka: false #Do you register yourself with the eureka registry fetch-registry: false # false indicates your own registry service-url: defaultZone: http://Eureka7002:7002/eureka/,http://Eureka7003:7003/eureka/
- eureka7002
server: port: 7002 eureka: instance: hostname: Eureka7001 # Instance name of Eureka server client: register-with-eureka: false #Do you register yourself with the eureka registry fetch-registry: false # false indicates your own registry service-url: defaultZone: http://Eureka7001:7001/eureka/,http://Eureka7003:7003/eureka/
- eureka7003
server: port: 7003 eureka: instance: hostname: Eureka7001 # Instance name of Eureka server client: register-with-eureka: false #Do you register yourself with the eureka registry fetch-registry: false # false indicates your own registry service-url: defaultZone: http://Eureka7001:7001/eureka/,http://Eureka7002:7002/eureka/
provider registration: register all three
eureka: instance: hostname: localhost # Instance name of Eureka server instance-id: springCloud-provider-dept8001 #Modify the default description information on eureka client: service-url: defaultZone: http://Eureka7001:7001/eureka/,http://Eureka7002:7002/eureka/,http://Eureka7003:7003/eureka/
Display:
Eureka vs zookeeper
CAP principle
CAP principle, also known as CAP theorem, refers to that in a distributed system, uniformity(Consistency),usability(Availability),Partition tolerance (Partition tolerance). The CAP principle refers to these three principles essential factor At most, it can only achieve two points at the same time, and it is impossible to give consideration to the three.
-
C onsistency: in distributed system Whether all data in the backup have the same value at the same time. (equivalent to all nodes accessing the same latest data copy)
-
Availability (A): ensure that every request has A response regardless of success or failure.
-
Partition tolerance (P): the loss or failure of any information in the system will not affect the continuous operation of the system. [1]
The essence of CAP principle is either AP, CP or AC, but there is no CAP. If there is no copy of data in a distributed system, the system must meet the strong consistency condition, because there is only one data, and there will be no data inconsistency. At this time, C and P elements are available. However, if the system has network partition or downtime, some data will not be accessible, and the availability condition can not be met, That is, in this case, the CP system is obtained, but the CAP cannot be satisfied at the same time
zookeeper CP
When querying the service list from the registry, we can tolerate that the registry returns the registration information a few minutes ago, but we can't accept that the service is directly down and unavailable. In other words, the service registration function requires higher availability than consistency. But zk there will be such a situation: when the master node loses contact with other nodes due to network failure, the remaining nodes will conduct leader election again. The problem is that the election leader takes too long, 30~120s, and the whole zk cluster is unavailable during the election, which leads to the paralysis of the registration service during the election. In the cloud deployment environment, the loss of the master node of the water cluster due to network problems is a high probability event. Although the service can be restored eventually, the long-term unavailability of registration caused by the long election time cannot be tolerated.
Eureka AP?
Eureka understands this, so it gives priority to ensuring availability in design. Eureka's nodes are equal. The failure of several nodes will not affect the work of normal nodes, and the remaining nodes can still provide registration and query services. When registering with an Eureka client, if the connection fails, it will automatically switch to other nodes. As long as one Eureka is still there, the availability of the registration service can be maintained,
However, the information found may not be up-to-date. In addition, Eureka has a self-protection mechanism. If more than 85% of the nodes do not have a normal heartbeat within 15 minutes, Eureka thinks that there is a network failure between the client and the registry. At this time, the following situations will occur:
- Eureka no longer removes services that should expire because they haven't received a heartbeat for a long time from the registration list
- Eureka can still accept the registration and query requests of new services, but it will not be synchronized to other nodes (that is, ensure that the current node is still available)
- When the network is stable, the new registration information of the current instance will be synchronized to other nodes
Therefore, Eureka can deal with the loss of contact of some nodes due to network failure without paralyzing the whole registration service like zookeeper
ribbon
What is it?
-
Spring Cloud Ribbon is a set of client-side load balancing tools based on Netflix Ribbon.
-
In short, Ribbon is an open source project released by Netflix. Its main function is to provide software load balancing algorithms for clients and connect Netflix's middle tier services together. The Ribbon client component provides a series of complete configuration items, such as connection timeout, Retry, and so on. Simply put, list all the machines behind the loadbalancer (LB: load balancer for short) in the configuration file. The Ribbon will automatically help you connect these machines based on certain rules (such as simple polling, random connection, etc.). We can also easily use Ribbon to implement custom load balancing algorithm!
-
Load balancing simply means that users' requests are evenly distributed to multiple services, so as to achieve the HA (high availability) of the system.
-
Load balancing classification
-
Centralized:
That is, independent LB facilities are used between consumers and providers of services, such as Nginx: reverse proxy server!, The facility is responsible for forwarding the access request to the service provider through some policy!
-
Enter program
Integrate LB logic into the consumer. The consumer knows which addresses are available from the service registry, and then selects a suitable server from these addresses.
Ribbon belongs to in-process LB, which is just a class library integrated into the consumer process. The consumer obtains the address of the service provider through it!
-
Configure consumer
(limited by the computer configuration, there is no practical operation from the cluster, and the following is only theory)
Dependency:
Choose one of the following ribbons, which can be used and which one. Spring cloud starter Netflix ribbon is suitable for the new version
(* * the new version of erueka includes ribbon, so there is no need to rely on it. Otherwise, it will not start
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-ribbon --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> <version>2.2.6.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-ribbon --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-ribbon</artifactId> <version>1.4.6.RELEASE</version> </dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> <version>1.4.6.RELEASE</version> </dependency>
Configure and start eureka
server: port: 80 eureka: client: register-with-eureka: false # Do not register yourself with eureka service-url: defaultZone: http://localhost:7001/eureka/,...,... # Write the three addresses of the cluster here
@SpringBootApplication @EnableEurekaClient public class DeptConsumer_80 { public static void main(String[] args) { SpringApplication.run(DeptConsumer_80.class,args); } }
Enable load balancing @ LoadBalanced
@Configuration public class MyConfig { @Bean @LoadBalanced //Configure load balancing to implement RestTemplate public RestTemplate restTemplate() { return new RestTemplate(); } }
Use in controller:
(service name does not support underscore???)
//The Ribbon address should be a variable, accessed by the service name //private static final String REST_URL_PREFIX="http://localhost:8001"; private static final String REST_URL_PREFIX="http://SPRINGCLOUDE-PROVIDER-DEPT"; //Followed by the name of the spring app configured in the provider's spring configuration file
Configure multiple provider s
Create three database tables and three provider items with port numbers of 800180028003 respectively to ensure the consistency of database contents (except database fields). The three items spring app name (service name) are exactly the same and are linked into the cluster. After startup, you can see that a service has three service instances in eureka:
test
Using consumer to connect to the database for query, under the action of load balancing, it will enter three different service instances in turn and query from three different databases
Load balancing strategy
Interface: IRule:
-
Roundrobin rule polling default
-
AvailabilityFilteringRule
The services with tripping and access failure will be filtered out first, and the remaining services will be polled
-
RandomRule random
Configure additional policies:
@Configuration public class MyRule { @Bean public IRule iRule(){ return new RandomRule(); } }
Configuration on main startup class:
@Ribbonclient name = service name configuration = configure policy class
@SpringBootApplication @EnableEurekaClient @RibbonClient(name = "SPRINGCLOUDE-PROVIDER-DEPT",configuration = MyRule.class) public class DeptConsumer_80 { public static void main(String[] args) { SpringApplication.run(DeptConsumer_80.class,args); } }
Custom policy
- Also in the myrule package, it is not at the same level as the main startup class
- Inherit AbstractLoadBalancerRule class
- Poll after 5 times for each service as follows
package com.myrule; public class MyRoundRule extends AbstractLoadBalancerRule { private int currentIndex=0; private int count=0; public MyRoundRule() { } @SuppressWarnings({"RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE"}) public Server choose(ILoadBalancer lb, Object key) { if (lb == null) { return null; } else { Server server = null; while(server == null) { if (Thread.interrupted()) { return null; } List<Server> upList = lb.getReachableServers();//Access to 'living' services List<Server> allList = lb.getAllServers();//Get all services int serverCount = upList.size(); if (serverCount == 0) { return null; } //======================================= if (count<5){ server=upList.get(currentIndex); count++; }else { count=0; currentIndex++; if (currentIndex>serverCount-1){ currentIndex=0; } server=upList.get(currentIndex); } //====================================== int index = this.chooseRandomInt(serverCount);//Get the random number of an interval if (server == null) { Thread.yield(); } else { if (server.isAlive()) { return server; } server = null; Thread.yield(); } } return server; } } protected int chooseRandomInt(int serverCount) { return ThreadLocalRandom.current().nextInt(serverCount); } public Server choose(Object key) { return this.choose(this.getLoadBalancer(), key); } public void initWithNiwsConfig(IClientConfig clientConfig) { } }
Feign
Feign does not do load balancing. Feign only integrates ribbons. Load balancing is still done by the built-in ribbons of feign. Feign is an alternative to RestTemplate. Its performance is relatively low, but it can make the code readable.
Dependency:
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-ribbon --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> <version>1.4.6.RELEASE</version> </dependency> <!--The new version uses the following--> <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-openfeign --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> <version>2.2.6.RELEASE</version> </dependency>
Configure service:
@Component @FeignClient(value = "SPRINGCLOUDE-PROVIDER-DEPT") //service name public interface DeptClientService { @GetMapping("/dept/get/{id}") Dept queryById(@PathVariable("id")long id); Dept queryAll(); boolean addDept(Dept dept); }
Use in feign consumer:
@Autowired private DeptClientService service; @RequestMapping("/consumer/dept/add") public boolean add(Dept dept){ return this.service.addDept(dept); } @RequestMapping("/consumer/dept/get/{id}") public Dept get(@PathVariable("id")long id){ return this.service.queryById(id); } @RequestMapping("/consumer/dept/list") public List<Dept> list(){ return this.service.queryAll(); }
Abandon the following service access methods and turn to interface oriented programming:
@Autowired private RestTemplate restTemplate; private static final String REST_URL_PREFIX="http://SPRINGCLOUDE-PROVIDER-DEPT";
Start feign under the main startup class of consumer
@SpringBootApplication @EnableEurekaClient //@RibbonClient(name = "SPRINGCLOUDE-PROVIDER-DEPT",configuration = MyRule.class) @EnableFeignClients(basePackages = {"com.yang"}) public class DeptConsumer_80 { public static void main(String[] args) { SpringApplication.run(DeptConsumer_80.class,args); } }
Service fuse
introduce
What is Hystrix
Hystrix is an open source library for dealing with delay and fault tolerance of distributed systems. In distributed systems, many dependencies inevitably fail to call, such as timeout, exception, etc. hystrix can ensure that when a dependency fails, it will not lead to overall service failure, avoid cascading failures, and improve the elasticity of distributed systems.
"Circuit breaker" itself is a kind of switching device. When a service unit fails, it returns a service expected and processable alternative response (FallBack) to the caller through the fault monitoring of the circuit breaker (similar to a blown fuse), rather than waiting for a long time or throwing an exception that cannot be handled by the calling method, This can ensure that the thread of the service caller will not be occupied unnecessarily for a long time, so as to avoid the spread and even avalanche of faults in the distributed system
Service fuse
Fusing mechanism is a microservice link protection mechanism corresponding to avalanche effect.
When a microservice of the fan out link is unavailable or the response time is too long, the service will be degraded, which will fuse the call of the microservice of the node and quickly return the wrong response information. When it is detected that the microservice call response of the node is normal, the call link is restored. In the spring cloud framework, the fuse mechanism is implemented through hystrix. Hystrix will monitor the status of calls between microservices. When the failed call reaches a certain threshold, the default is 20 calls in 5 seconds, and the circuit breaker mechanism will be started if the call fails. The annotation of the fuse mechanism is @ HystrixCommand.
Use service fuse
Create a new project and copy provider-8001
Dependency:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> <version>1.4.6.RELEASE</version> </dependency>
Loading alternative methods: @ HystrixCommand(fallbackMethod = "hystrixGetDept") / / use the fuse mechanism
@RestController public class DeptController { @Autowired private DeptService deptService; @GetMapping("/dept/get/{deptno}") @HystrixCommand(fallbackMethod = "hystrixGetDept")//Use of fuse mechanism public Dept getDept(@PathVariable("deptno") long deptno){ Dept dept = deptService.queryDeptById(deptno); if (dept==null){ throw new RuntimeException("id->"+deptno+"No corresponding information @Exception"); } return dept; } //Alternatives to fusing public Dept hystrixGetDept(@PathVariable("deptno") long deptno){ return new Dept() .setDeptno(deptno) .setDname("id->"+deptno+"No corresponding information @Hystrix") .setDb_source("no this database"); } }
Enable support: @ enablercircuitbreaker
@EnableDiscoveryClient//Service discovery @SpringBootApplication//Manually register the startup class @EnableEurekaClient //Automatically register in Eureka after service startup @EnableCircuitBreaker //Add fuse support and circuit breaker public class DeptProviderHystrix_8001 { public static void main(String[] args) { SpringApplication.run(DeptProviderHystrix_8001.class,args); } }
Test: query the objects that do not exist, and the information returned through the circuit breaker mechanism:
Use service degradation
Use with feign
Call service degradation in api service interface: fallbackFactory= xxx.class
@Component @FeignClient(value = "SPRINGCLOUDE-PROVIDER-DEPT",fallbackFactory = DeptClientServiceFallbackFactory.class) //service name public interface DeptClientService { @GetMapping("/dept/get/{id}") Dept queryById(@PathVariable("id")long id); @GetMapping("/dept/list") List<Dept> queryAll(); @GetMapping("/dept/add") boolean addDept(Dept dept); }
Provide degraded services:
@Component public class DeptClientServiceFallbackFactory implements FallbackFactory { @Override public DeptClientService create(Throwable throwable) { return new DeptClientService() { @Override public Dept queryById(long id) { return new Dept() .setDeptno(id) .setDname("id->"+id+"There is no corresponding information. This service has been shut down. Please try again later") .setDb_source("no database"); } @Override public List<Dept> queryAll() { return null; } @Override public boolean addDept(Dept dept) { return false; } }; } }
Enable service degradation in the client configuration using feign:
feign: hystrix: enabled: true
Personal understanding:
Service degradation is the setting of the client consumer. After use, the standby degraded service can be used even if the service provider crashes (or temporarily closes for rational resource distribution).
Service fusing is the setting of the service provider. When the service timeout and exception occur, it will be caught and handled accordingly
Dashboard traffic monitoring
Monitoring tools
Create a new client, springcloud consumer hystrix dashboard, port 9001
server: port: 9001
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> <version>1.4.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId> <version>1.4.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-ribbon</artifactId> <version>1.4.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> <version>1.4.6.RELEASE</version> </dependency> <dependency> <groupId>org.example</groupId> <artifactId>springCloudapi</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--Hot deployment--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency>
Enable flow monitoring on the main startup class: @ EnableHystrixDashboard
@SpringBootApplication @EnableHystrixDashboard public class ConsumerDashboard_9001 { public static void main(String[] args) { SpringApplication.run(ConsumerDashboard_9001.class,args); } }
Testing: accessing Hystrix Dashboard
Monitoring object
The monitoring object is the provider,
Add a servlet to the main startup class in the provider that imported the hystrix and actor dependencies:
@EnableDiscoveryClient//Service discovery @SpringBootApplication//Manually register the startup class @EnableEurekaClient //Automatically register in Eureka after service startup @EnableCircuitBreaker //Add fuse support and circuit breaker public class DeptProviderHystrix_8001 { public static void main(String[] args) { SpringApplication.run(DeptProviderHystrix_8001.class,args); } @Bean public ServletRegistrationBean hystrixMetricsStreamServlet(){ ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet()); registrationBean.addUrlMappings("/actuator/hystrix.stream"); return registrationBean; } }
Test: access: localhost:8001/actuator/hystrix.stream
monitor
Enter on the monitoring page https://localhost:8001/actuator/hystrix.stream delay=2000ms Title= name
Enter the following page:
-
Solid circle:
There are two meanings. It represents the health degree of the instance through the change of color. Its health degree decreases from green < yellow < orange < red. In addition to the change of color, the size of the solid circle will also change according to the request flow of the instance. The larger the flow, the larger the solid circle. Therefore, through the display of the solid circle, we can quickly find fault instances and high pressure instances in a large number of instances.
-
Line:
It is used to record the relative change of flow within 2 minutes, and the rising and falling trend of flow can be observed through it
-
Overall drawing:
Zuul routing gateway
summary:
zuul includes two main functions: Request Routing and filtering:
The routing function is responsible for forwarding external requests to specific micro service instances, which is the basis for realizing the unified entrance of external access, while the filter function is responsible for intervening in the processing process of requests, which is the basis for realizing request verification, service aggregation and other functions. Zuul and Eureka integrate, register zuul as an application under Eureka service governance, and obtain messages of other micro services from Eureka, that is, access to micro services in the future is obtained through zuul jump.
structure
New project: springcloud-zuul-9527
Dependency: zuul
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zuul</artifactId> <version>1.4.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> <version>1.4.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId> <version>1.4.6.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-ribbon --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-ribbon</artifactId> <version>1.4.6.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> <version>1.4.6.RELEASE</version> </dependency> <dependency> <groupId>org.example</groupId> <artifactId>springCloudapi</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--Hot deployment--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> </dependencies>
server: port: 9527 spring: application: name: springcloud-zuul eureka: client: service-url: defaultZone: http://localhost:7001/eureka / # here write the cluster (3 addresses) instance: instance-id: zuul9527 prefer-ip-address: true info: app.name: yang-springcloud
Open gateway: @ EnableZuulProxy
@SpringBootApplication @EnableZuulProxy public class ZuulApplication_9527 { public static void main(String[] args) { SpringApplication.run(ZuulApplication_9527.class,args); } }
test
Run eureka 7001, provider 8001, zuul 9527
You can see that the registry has two services:
Data can be obtained by directly accessing the provider:
Data can also be obtained through the gateway:
Hide the service name in the path
Add in springcloud-zuul-9527:
zuul: routes: mydept.serviceId: springcloud-provider-dept mydept.path: /mydept/** ignored-services: springcloud-provider-dept # Access is no longer supported on the path of the proxy service name #Ignored services: "*" hide all service names and paths
Test:
Set prefix
zuul: prefix: /yang
Full path: http://localhost:9527/yang/mydept/dept/get/2
Git
Download Git: https://git-scm.com/download/win
upload
git add . git commit -m "Comment statement" git push
Remote access project Server
New project: springcloud-config-server-3344
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-config-server --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> <version>2.1.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> <version>1.4.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
server: port: 3344 spring: application: name: springcloud-config-server #Connect to remote warehouse cloud: config: server: git: uri: https://gitee.com/yang-KUKU/springcloud-config.git
Open service: @ enableconfig server
@SpringBootApplication @EnableConfigServer public class Config_Server_3344 { public static void main(String[] args) { SpringApplication.run(Config_Server_3344.class,args); } }
Test:
Client
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> <version>2.1.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> <version>1.4.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>
to configure:
- bootstrap.yml
#System level configuration application is user level configuration spring: cloud: config: name: config-client # Resource name that needs to be read remotely without suffix uri: http://localhost:3344 profile: dev label: master
- application.yml
spring: application: name: springcloud-config3355
controller:
@RestController public class ConifgClientController { @Value("${spring.application.name}") private String applicationName; @Value("${eureka.client.service-url.defaultZone}") private String eurekaServer; @Value("${server.port}") private String port; @RequestMapping("/config") public String getConifg(){ return "applicationName"+applicationName+ "eurekaServer"+eurekaServer+ "port"+port; } }
Note: the controller is only written to more vividly display the configuration obtained from the remote. This configuration has taken effect and there is no need to write other code
Write the main startup class test: it can be seen that the client has obtained the configuration information from the remote
Summary:
Realize remote unified configuration management, and the source code is clean, concise and safe