Learning notes - springCloud

Posted by kevin99 on Thu, 03 Feb 2022 03:14:54 +0100

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:

  1. Eureka no longer removes services that should expire because they haven't received a heartbeat for a long time from the registration list
  2. 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)
  3. 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

Topics: Spring Cloud