[SpringCloud] 02 Build springcloud microservice project, service management component nacos, load balancing ribbon, remote call Openfeign

Build springcloud microservice project

Technology stack:

  1. springcloud-alibaba
  2. mybatis-plus persistence framework
  3. mysql database 5.7 or above
  4. Springboot is used to build each microservice.

1. Microservice parent project

Insert image description here
Delete all others and keep only one pom file

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.12.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.aaa</groupId>
    <artifactId>qy156-shop-parent</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>
    <name>qy156-shop-parent</name>
    <description>Demo project for Spring Boot</description>
    <!--定义版本号-->
    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF- 8</project.reporting.outputEncoding>
        <spring-cloud.version>Hoxton.SR8</spring-cloud.version>
        <spring-cloud-alibaba.version>2.2.3.RELEASE</spring-cloud-alibaba.version>
    </properties>
    <!--jar得管理 它只负责jar得管理不负责下载-->
    <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>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

2. Create submodule-shop-common

Put the common code of other modules into this module. - - -Entity tool class

Insert image description here

  <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.0</version>
        </dependency>
    </dependencies>

Define related entity classes

@Data
@TableName(value = "shop_order")
public class Order {
    
    
    //订单id
    @TableId
    private Long oid;
    //用户id
    private Integer uid;
    //用户名
    private String username;
    //商品id---购买时99---->活动结束后199
    private Long pid;
    //商品得名称
    private String pname;
    //商品得价格
    private Double pprice;
    //购买得数量
    private Integer number;
}

@Data
@TableName("shop_product")
public class Product {
    
    
    @TableId
    private Long pid;
    private String pname;
    private Double pprice;
    private Integer stock;
}

3. Create submodule –shop-product

Interface for product table operations
Insert image description here

	<dependencies>
          <!--引入公共模块-->
        <dependency>
            <groupId>com.aaa</groupId>
            <artifactId>shop-common</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

        <!--引入springboot-starter-web依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--引入mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
    </dependencies>

Configuration file

# 定义端口号 [8001~8009 未来方便搭建集群]
server:
  port: 8001

#数据源得信息
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springcloud?serverTimezone=Asia/Shanghai
    username: root
    password: root

# mybatis打印日志
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

interface

/**
 * @program: qy156-shop-parent
 * @description:
 * @author: 闫克起
 * @create: 2022-11-17 16:22
 **/
public interface ProductDao extends BaseMapper<Product> {
    
    
}

service code

@Service
public class ProductService implements IProductService {
    
    
    
    @Autowired
    private ProductDao productDao;
    @Override
    public Product findById(Long pid) {
    
    
        return productDao.selectById(pid);
    }
}

controller

@RestController
@RequestMapping("product")
public class ProductController {
    
    

    @Autowired
    private IProductService productService;

    @GetMapping("/getById/{pid}")
    public Product getById(@PathVariable Long pid){
    
    
         return productService.findById(pid);
    }
}

Main startup class

@SpringBootApplication
@MapperScan(basePackages = "com.aaa.product.dao")
public class ProductApp {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(ProductApp.class,args);
    }
}

Insert image description here

4. Create submodule –shop-order

All operation interfaces about the order form
Insert image description here

	<dependencies>
        <!--引入公共模块-->
        <dependency>
            <groupId>com.aaa</groupId>
            <artifactId>shop-common</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

        <!--引入springboot-starter-web依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--引入mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
    </dependencies>

Configuration

#端口号---[9001~9009]集群模式
server:
  port: 9001

#数据源得信息
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springcloud?serverTimezone=Asia/Shanghai
    username: root
    password: root
# sql显示在控制台
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

interface

package com.aaa.order.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;

/**
 * @program: qy156-shop-parent
 * @description:
 * @author: 闫克起
 * @create: 2022-11-18 14:34
 **/
public interface OrderDao extends BaseMapper<OrderDao> {
    
    

}

service code

@Service
public class OrderService implements IOrderService {
    
    

    @Autowired
    private OrderDao orderDao;
    @Override
    public int save(Order order) {
    
    
        return orderDao.insert(order);
    }
}

Inject restTemplate into the configuration class

@SpringBootApplication
public class AppOrder {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(AppOrder.class, args);
    }

    @Bean
    public RestTemplate restTemplate(){
    
    
        return new RestTemplate();
    }
}

controller code

package com.aaa.order.controller;

import com.aaa.entity.Order;
import com.aaa.entity.Product;
import com.aaa.order.service.IOrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

/**
 * @program: qy156-shop-parent
 * @description:
 * @author: 闫克起2
 * @create: 2022-11-17 16:33
 **/
@RestController
@RequestMapping("/order")
public class OrderController {
    
    


    //必须创建并交于spring容器管理。这样才能被注入到相应的类属性上
    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private IOrderService orderService;

    @GetMapping("/saveOrder")
    public String saveOrder(Long pid,Integer num){
    
    

        Order order=new Order();
        //用户得信息可以从登录后获取--Session  redis  jwt
        order.setUid(1);
        order.setUsername("张成");
        //为订单对象设置商品得信息
        order.setPid(pid);
       //需要远程调用商品微服务中的指定接口[注意:凡是关于商品的操作都有商品微服务来执行。]
        //远程调用的方式:第一种基于TCP协议的RPC远程调用   第二种基于http协议Restful风格的调用。
        //分布式架构:TCP协议的
        //微服务架构:http协议的。---在spring框架中封装了一个工具RestTemplate。 如果不是使用的spring框架。你需要自己封装HttpClient工具
        Product product = restTemplate.getForObject("http://localhost:8001/product/getById/"+pid, Product.class);
        order.setPname(product.getPname());
        order.setPprice(product.getPprice());
        order.setNumber(num);


        orderService.save(order);

        return "下单成功";
    }
}

Thinking: Are there any flaws in the remote calling code we wrote above?


[1] We hard-code the product microservice address in our own code - if the product microservice address changes. Need to modify the code of our own current microservices


[2] If the product microservice builds a cluster mode. How does the order microservice call the corresponding product microservice to achieve load balancing characteristics.

Server management component.

eureka: used as a service management component. ---->netflix company’s products—stop update and maintenance


zookeeper: service management component. ---->dubbo distributed framework cooperation


nacos: service governance component. ---->Alibaba products.

Use nacos here

Service governance component

Insert image description here

1. How to use nacos

https://github.com/alibaba/nacos/releases

Nacos1.3 and later supports cluster mode. Not supported before 1.3.

Install nacos server.
JDK must be installed and environment variables configured. And you cannot put nacos into the Chinese directory

Insert image description here
startup.cmd in the bin directory starts nacos
Insert image description here
to access the nacos server
Insert image description here
Insert image description here

2. The microservice client connects to the nacos registration center

(1)Introduce dependencies

<!--引入nacos的依赖-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

(2) Modify the configuration file
Insert image description here

test:
Insert image description here

3. How does the consumer call the provider through nacos?

Introduce nacos dependencies and configure nacos addresses
Modify the control layer code

package com.aaa.order.controller;

import com.aaa.entity.Order;
import com.aaa.entity.Product;
import com.aaa.order.service.IOrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;

/**
 * @program: qy156-shop-parent
 * @description:
 * @author: 闫克起2
 * @create: 2022-11-17 16:33
 **/
@RestController
@RequestMapping("/order")
public class OrderController {
    
    


    //必须创建并交于spring容器管理。这样才能被注入到相应的类属性上
    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private IOrderService orderService;

   	//在nacos中封装了一个类DiscoveryClient,该类可以获取注册中心中指定的清单列表。
    @Autowired
    private DiscoveryClient discoveryClient;

    @GetMapping("/saveOrder")
    public String saveOrder(Long pid,Integer num){
    
    
        Order order=new Order();
        //用户得信息可以从登录后获取--Session  redis  jwt
        order.setUid(1);
        order.setUsername("张成");
        //为订单对象设置商品得信息
        order.setPid(pid);
        
        //获取指定的实例
        List<ServiceInstance> instances = discoveryClient.getInstances("shop-product");
        ServiceInstance serviceInstance = instances.get(0);
//        String path = serviceInstance.getHost().toString();
//        System.out.println(path+"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
//        Integer port = serviceInstance.getPort();
//        System.out.println(port+"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");

        String uri = serviceInstance.getUri().toString();
//        System.out.println(uri+"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
        Product product = restTemplate.getForObject(uri+"/product/getById/"+pid, Product.class);
        order.setPname(product.getPname());
        order.setPprice(product.getPprice());
        order.setNumber(num);

        orderService.save(order);

        return "下单成功";
    }
}

If the provider's address changes later, it will not affect the consumer's code.

Thinking: Is there any problem with the above mode of pulling the service list from nacos?
There is no problem of load balancing. If the later commodity microservice is deployed as a cluster. The caller should distribute the request evenly to each server.

load balancing

In layman's terms, load balancing is to allocate loads (work tasks, access requests) to multiple operating units (servers, components) for execution.

Simulate the construction of multiple product microservices.
Insert image description here


Insert image description here


Insert image description here

1. Control load balancing yourself

The load balancing feature of artificially completing the order microservice calls the commodity microservice.

package com.aaa.order.controller;

import com.aaa.entity.Order;
import com.aaa.entity.Product;
import com.aaa.order.service.IOrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;
import java.util.Random;

/**
 * @program: qy156-shop-parent
 * @description:
 * @author: 闫克起2
 * @create: 2022-11-17 16:33
 **/
@RestController
@RequestMapping("/order")
public class OrderController {
    
    


    //必须创建并交于spring容器管理。这样才能被注入到相应的类属性上
    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private IOrderService orderService;

    @Autowired
    private DiscoveryClient discoveryClient;

    @GetMapping("/saveOrder")
    public String saveOrder(Long pid,Integer num){
    
    
        Order order=new Order();
        //用户得信息可以从登录后获取--Session  redis  jwt
        order.setUid(1);
        order.setUsername("张成");
        //为订单对象设置商品得信息
        order.setPid(pid);
        //在nacos中封装了一个类DiscoveryClient,该类可以获取注册中心中指定的清单列表。
        //获取指定的实例
        List<ServiceInstance> instances = discoveryClient.getInstances("shop-product");

        //随机产生一个下标--0~size
        int index = new Random().nextInt(instances.size());
        ServiceInstance serviceInstance = instances.get(index);

        String uri = serviceInstance.getUri().toString();

        Product product = restTemplate.getForObject(uri+"/product/getById/"+pid, Product.class);
        order.setPname(product.getPname());
        order.setPprice(product.getPprice());
        order.setNumber(num);

        orderService.save(order);

        return "下单成功";
    }
}

These two lines control which microservice is used

//随机产生一个下标--0~size
int index = new Random().nextInt(instances.size());
ServiceInstance serviceInstance = instances.get(index);

If you want to change the load balancing strategy, for example, if you want to change it to a polling strategy, you need to come here to modify the source code, hard coding problem [opening and closing principle]

A ribbon component is provided - this component can complete load balancing.

2. ribbon completes load balancing

Ribbon is a load balancer released by Netflix that helps control HTTP and TCP client behavior. In Spring Cloud, nacos is generally used in conjunction with Ribbon. Ribbon provides the function of client load balancing. Ribbon uses the service information read from nacos to load the service reasonably (strategically) when calling the services provided by the service node. .

In Spring Cloud, you can use the registration center and Ribbon together.Ribbon automatically downloads from the registration centerObtain the list information of service providers and request services based on the built-in load balancing algorithm.

Ribbon automatically obtains the service provider list information from the registration center and requests services based on the built-in load balancing algorithm.

2.1 How to use ribbon

There is no need to introduce any dependencies.
Insert image description here
You only need to add a LoadBalance annotation to the bean obtained by RestTemplate.
Insert image description here

@LoadBalanced tells RestTemplate to use ribbon to complete load balancing. Automatically pull services from the registration center. Use the built-in load balancing strategy to complete service calls.

Modify the controller code
Insert image description here
and the test found that the polling strategy is used by default. Whether the ribbon can be changed to other strategies. The ribbon provides many strategies.

Route name Strategy description Implementation instructions
BestAvailableRule Select a server with the smallest concurrent requests Examine the servers one by one. If the server is tripped, ignore it and select the server with the smallest ActiveRequestsCount.
RandomRule Randomly select a server Randomly on index. Select the server corresponding to the index
RoundRobinRule Polling modePolling selection Poll the index and select the server corresponding to the index
AvailabilityFilteringRule Filter out those back-end servers marked as circuittripped because they keep failing to connect, and filter out those back-end servers with high concurrency (active connections exceed the configured threshold) Use an AvailabilityPredicate to include the logic of filtering servers. In fact, it is to check the running status of each server recorded in status.
WeightedResponseTimeRule A weight is assigned based on the corresponding time. The longer the response time, the smaller the weight and the lower the possibility of being selected. A background thread periodically reads the evaluation response time from status and calculates a weight for each server. The calculation of Weight is also relatively simple. Response time minus each server's own average response time is the weight of the server. When the operation is just started and no status is formed, the roubine strategy is used to select the server.
RetryRule On-machine retry mechanism for selected load balancing policies. If server selection fails within a configured time period, try to use subRule to select an available server.
ZoneAvoidanceRule Select the server based on the composite judgment of the performance of the region where the server is located and the availability of the server. Use ZoneAvoidancePredicate and AvailabilityPredicate to determine whether to select a server. The former determines whether the running performance of a zone is available, except for unavailable zones (all servers). AvailabilityPredicate is used to filter out servers with too many connections.

How to use the corresponding strategy:
The first way: define a bean in the configuration class.
This way iscurrent service vs. all servicesBoth use the RandomRule strategy

    @Bean
    public RandomRule randomRule(){
    
    
        return new RandomRule();
    }

The second way: configure in yml.
This way isCurrent services to shop-productService, using RandomRule strategy

shop-product:  # 这里使用服务的名称
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #使用的的负载均衡策略

If the above strategies are not enough, you can also customize the strategy class. Implement the IRule interface to complete the custom strategy.
Insert image description here
If the above strategies are not enough, you can also customize the strategy class. Implement the IRule interface to complete the custom strategy.

2.2 Customized load balancing strategy

Regardless of any load balancing, they are all subclasses of the IRule interface.
Insert image description here
Our custom rule class must also inherit the AbstractLoadBalancerRule class.

Requirements:
A customized algorithm is required: it is still a polling strategy, but after each server is called 5 times, it is the turn of the next service. That is, each service used to be called once, but now each service is called 5 times.

Custom rule classes—simulate existing classes.

package com.aaa.order.rule;

import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancer;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;

import java.util.List;

/**
 * @program: qy156-shop-parent
 * @description:
 * @author: 闫克起2
 * @create: 2022-11-19 14:42
 **/
public class MyRule extends AbstractLoadBalancerRule {
    
    
    @Override
    public void initWithNiwsConfig(IClientConfig iClientConfig) {
    
    
         //初始化方法 读取配置文件内容
    }

    //统计访问的次数
    private int total;
    //作为集群服务器下标
    private int index;
    @Override
    public Server choose(Object key) {
    
    
        //获取负载均衡选择器
        ILoadBalancer lb = getLoadBalancer();
        if (lb == null) {
    
    
            return null;
        }
        Server server = null;

        while (server == null) {
    
    
            if (Thread.interrupted()) {
    
    
                return null;
            }
            //获取所有可用的服务器
            List<Server> upList = lb.getReachableServers();
            //获取所有的服务器。
            List<Server> allList = lb.getAllServers();

            int serverCount = allList.size();
            if (serverCount == 0) {
    
    
                return null;
            }

            //判断该服务访问的次数是否>5次
            if(total<5){
    
    
                 server=upList.get(index);
                 total++;
            }else{
    
    
                 total=0;
                 index++;
                 index=index%upList.size();
            }

            if (server == null) {
    
    
                Thread.yield();
                continue;
            }

            if (server.isAlive()) {
    
    
                return (server);
            }

            // Shouldn't actually happen.. but must be transient or a bug.
            server = null;
            Thread.yield();
        }

        return server;
    }
}

(2) Create a configuration class, which is used to create the above bean object

@Configuration
public class RuleConfig {
    
    

    @Bean
    public MyRule myRule(){
    
    
        return new MyRule();
    }
}

(3)ribbon uses the custom rules above
Insert image description here

2.3 Hungry Chinese style loading

Ribbon defaults to lazy-style loading, which means that resources are not loaded at startup, but are loaded at first startup. You can modify the yml file to lazy-style loading.

ribbon:
  eager-load:
    enabled: true # 开启饥饿加载
    clients: # 指定饥饿加载的服务名称
      - shop-order

Remote calling component-Openfeign

The calls between our services above use the RestTemplate tool class to complete the corresponding calls. But the RestTemplate model does not conform to our programming habits.

dao----service----controller: Inject the dao object into the service class, then call the method in dao, pass in the relevant parameters, and accept the relevant return type.

1 Overview

OpenFeign is a declarative pseudo-Http client provided by Spring Cloud, which enablesCalling a remote service is as easy as calling a local service, just create an interface and add an annotation.

Nacos is very compatible with OpenFeign. Feign load balancing integrates Ribbon by default, so using Fegin under Nacos achieves the load balancing effect by default.

2. How to use openfeign components

(1)Introduce related dependencies

<!--引入openfeign的依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

(2) Create feign interface

value:调用远程微服务的名称
@FeignClient(value = "shop-product")
public interface ProductFeign {
    
    
    @GetMapping("/product/getById/{pid}")
    public Product getById(@PathVariable Long pid);
}

(3) Enable the feign annotation driver
Insert image description here
(4) Use the feign interface

package com.aaa.order.controller;

import com.aaa.entity.Order;
import com.aaa.entity.Product;
import com.aaa.order.feign.ProductFeign;
import com.aaa.order.service.IOrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;
import java.util.Random;

/**
 * @program: qy156-shop-parent
 * @description:
 * @author: 闫克起2
 * @create: 2022-11-17 16:33
 **/
@RestController
@RequestMapping("/order")
public class OrderController {
    
    

    @Autowired
    private IOrderService orderService;

    //spring容器会为该接口生成带来实现类。
    @Autowired
    private ProductFeign productFeign;

    @GetMapping("/saveOrder")
    public String saveOrder(Long pid,Integer num){
    
    
        Order order=new Order();
        //用户得信息可以从登录后获取--Session  redis  jwt
        order.setUid(1);
        order.setUsername("张恒");
        //为订单对象设置商品得信息
        order.setPid(pid);
        //就像调用本地方法一样
        Product product = productFeign.getById(pid);

        order.setPname(product.getPname());
        order.setPprice(product.getPprice());
        order.setNumber(num);

        orderService.save(order);
        return "成功";
    }
}

If a single Nacos machine fails, all microservices will be registered and the corresponding service information will be pulled. This renders the entire project unusable.

Therefore, we need to build a cluster mode for nacos.
Link: xxx

Guess you like

Origin blog.csdn.net/qq_60969145/article/details/127970097