2. Spring Cloud: Nacos Registration Center + OpenFeign + Loadbalancer

Table of contents

overview

source code project structure

Project global pom.xml

payment module (i.e. a payment service)

 order module (i.e. an order service)

Startup and Validation

 Start the payment service

 Start the order service

View Nacos

call verification

Attachment 1: Nacos service registration discovery client temporary storage directory

Attachment 2: Nacos isolation three-layer concept

Attachment 3: Java code interacts with Nacos registration center

Attachment 4: Call open API through curl 

List instances under a service from Nacos:

Obtain an instance information from Nacos:

Publish/modify the Nacos instance (note that the metadata format in the URL is not JSON):


overview

  • Service provider: payment
  • Service consumer: order service (need to call payment service)
  • All of the above are in one project, but they belong to different modules
  • The nacos server has been installed and started.

source code project structure

  ---- Project

      ∟ payment      [module]

      ∟ order           [module]

      ∟ pom.xml [global pom file]

Project global pom.xml

Configure the dependent information required by each module through the global pom.xml

<?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.6.6</version>
        <relativePath/>
    </parent>

    <modules>
        <module>payment</module>
        <module>order</module>
    </modules>

    <groupId>com.example</groupId>
    <artifactId>myproject-global-pom</artifactId>
    <version>0.0.1-DEFAULT</version>
    <packaging>pom</packaging>
    <description>This is my project global pom config</description>
    <properties>
        <java.version>1.8</java.version>
        <springcloud.version>3.1.5</springcloud.version>
        <springcloudalibaba.version>2021.0.4.0</springcloudalibaba.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>${springcloudalibaba.version}</version>
            <exclusions>
                <exclusion>
                    <groupId>com.alibaba.nacos</groupId>
                    <artifactId>nacos-client</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>com.alibaba.nacos</groupId>
            <artifactId>nacos-client</artifactId>
            <version>1.4.5</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
            <version>${springcloud.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
            <version>${springcloud.version}</version>
        </dependency>
        
    </dependencies>

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

payment module (i.e. a payment service)

The pom.xml file of the payment module is as follows:

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>myproject-global-pom</artifactId>
        <groupId>com.example</groupId>
        <version>0.0.1-DEFAULT</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>payment</artifactId>
    <version>0.2.2-SNAPSHOT</version>
</project>

The application.properties configuration file of the payment module

#本服务的默认监听端口
server.port=8080

spring.application.name=payment

#Nacos注册中心服务端的地址和端口(形式ip:port,ip:port,...) 在启动时,会向多个地址都发起注册
spring.cloud.nacos.discovery.server-addr=39.100.80.168:8848

#如定义了此属性,则nacos取此名作为服务名,否则取spring.application.name作为默认服务名
spring.cloud.nacos.discovery.service=paymentService

 For more configuration items of the nacos client in springcloud, you can visit the official website of nacos (more configuration information about Nacos Starter): https://github.com/alibaba/spring-cloud-alibaba/wiki/Nacos-discovery

Under package=com.example.payment, add a @EnableDiscoveryClient annotation to the SpringBoot main class PaymentApplication.class: enable the service registration discovery mechanism

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

Create a new controller to simulate the fund payment logic. Add a new class under package=com.example.payment.contronller as follows:

@RestController
public class PaymentController {
    @Value("${server.port}")
    private int myport;

    @GetMapping("/dopay/{orderid}")
    public ResponseEntity<String> paylogic(@PathVariable("orderid") Long orderid) {
        return ResponseEntity.ok("支付服务successful! orderid=" + orderid + ", 支付成功。 支付服务的端口为port=" + myport );
    }
}

 order module (i.e. an order service)

The pom.xml file of the order module is as follows:

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>myproject-global-pom</artifactId>
        <groupId>com.example</groupId>
        <version>0.0.1-DEFAULT</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>order</artifactId>
    <version>1.0-SNAPSHOT</version>
</project>

The application.properties configuration file of the order module

#本服务的默认监听端口
server.port=4444

spring.application.name=customerOrder

#Nacos服务端的地址和端口(形式ip:port,ip:port,...)
spring.cloud.nacos.discovery.server-addr=39.100.80.168:8848

#如定义了此属性,则nacos取此名作为服务名,否则取spring.application.name作为默认服务名
spring.cloud.nacos.discovery.service=orderService

#向Nacos注册时,本服务对外暴露的IP地址 (若不配置,则从本机上的网卡自动选择作为对外暴露的IP)
#spring.cloud.nacos.discovery.ip=x.x.x.x

For more configuration items of the nacos client in springcloud, you can visit the official website of nacos (more configuration information about Nacos Starter): https://github.com/alibaba/spring-cloud-alibaba/wiki/Nacos-discovery

Under package=com.example.order, two annotations are added to the SpringBoot main class OrderApplication.class to enable the service registration discovery mechanism and the OpenFeign client respectively.

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

 Define the openFeign client interface (package=com.example.order.feignclients). You only need to define the interface, no need to implement it manually.

@FeignClient(value = "paymentService")    // Feign客户端制定目标服务的名字(根据此名字从注册中心订阅具体的服务实例信息)
public interface IPaymentServiceClient {

    @GetMapping("/dopay/{payid}")  // 目标服务(服务提供方)的内具体的调用URL路径
    public ResponseEntity<String> dodopay(@PathVariable("payid") Long payid);
}

Create a new controller to simulate order processing. Add a new class under package=com.example.order.contronller as follows:

@RestController
public class OrderController {

    @Autowired
    private IPaymentServiceClient paymentServiceClient;

    @GetMapping("/consumer/{orderid}")
    public ResponseEntity<String> consumerFeign( @PathVariable("orderid") Long orderid) {
        return ResponseEntity.ok ("调用订单模拟服务完成。 订单orderid:" + orderid + ",   调用返回的Body:" + paymentServiceClient.dodopay(orderid).getBody() );
    }
}

Startup and Validation

In maven, package the payment and order modules respectively, and then start them.

 Start the payment service

   Start two instances of payment, the service ports are 8888 and 9999 respectively.

 java -jar payment-0.2.2-SNAPSHOT.jar --server.port=8888

 java -jar payment-0.2.2-SNAPSHOT.jar --server.port=9999

 Start the order service

java -jar order-1.0-SNAPSHOT.jar

View Nacos

  This is from Nacos, we can see that paymentService and orderService have two services. where paymentService has two instances

call verification

curl http://localhost:4444/consumer/66

The result of the call is as follows. You can see that the two instances of paymentService are trained in rotation to provide services alternately. This is to use the spring could loadbalance component for openFeign, which uses the RR round-robin algorithm by default.

 

 In addition: If you configure the --logging.level.root=DEBUG attribute to enable the debug log when springboot starts, you can find the specific attributes of the http protocol when openfeign is called, for example, it can be observed that keep-alive is enabled.

Attachment 1: Nacos service registration discovery client temporary storage directory

  • The Nacos client will temporarily save the service and instance list information discovered from the Nacos server to the client locally (if the service and instance change, it will be automatically updated to the client locally).
  • The directory where the Nacos client is temporarily stored locally is: $HOME/nacos/naming/ ($HOME is the HOME path where the client application starts the user)
     

Attachment 2: Nacos isolation three-layer concept

As shown below:

  • namespace: It can be used for complete isolation of resources, config configuration resources under different namespaces are not shared, and services are not interoperable (cannot be found). Multi-tenant isolation can be achieved through namespace
  • group: can be used for resource grouping. Under the same namespace, the config configuration resources of different groups are not shared, and the services are not interoperable (cannot be found). Different environments can be isolated through groups
  • cluster_name: differentiates the cluster where the service instance resides. Under the same namespace and the same group, the services of different clusters are interoperable (mutually accessible). The different clusters or data centers where the service runs can be identified by different clusters. This concept exists in service registration discovery, but does not exist in config configuration.

Note 1: The groups of the registration center and the configuration center are different, and each has its own management.

Note 2: For the settings of the above layers, different groups can be configured in the Nacos registration center and configuration center for the same service instance. That is to say, the same service declares group=A when obtaining configuration from Nacos, and declares group=B when registering the service with Nacos, which is allowed.
 

Attachment 3: Java code interacts with Nacos registration center
 

      a. Instead of using the Springboot Bean method, directly access the Nacos server through the following methods

NamingService namingService = NacosFactory.createNamingService(serverAddrList);

namingService.getAllInstances("serviceName");
namingService.getAllInstances("serviceName", "groupName");
namingService.getAllInstances(......);
namingService.shutDown();


...... ConfigService 类似,省略 ......

       b. If in the Springboot Bean, the namingService object is obtained through automatic injection:

    @Autowired
    NacosServiceManager nacosServiceManager;

    @Autowired
    NacosConfigManager nacosConfigManager;

 
 
...... 省略 ......
     NamingService namingService = nacosServiceManager.getNamingService();
     ConfigService configService = nacosConfigManager.getConfigService();
...... 然后使用该对象操作(省略)......
 

Attachment 4: Call open API through curl 

List instances under a service from Nacos:

curl -X GET http://39.100.80.168:8848/nacos/v1/ns/instance/list?serviceName=paymentService

return result:

{"name":"DEFAULT_GROUP@@paymentServicecurl","groupName":"DEFAULT_GROUP","clusters":"","cacheMillis":10000,"hosts":[],"lastRefTime":1686204572768,"checksum":"","allIPs":false,"reachProtectionThreshold":false,"valid":true}{"name":"DEFAULT_GROUP@@paymentService","groupName":"DEFAULT_GROUP","clusters":"","cacheMillis":10000,"hosts":[{"ip":"192.168.163.1","port":8080,"weight":0.8,"healthy":true,"enabled":true,"ephemeral":true,"clusterName":"BJ","serviceName":"DEFAULT_GROUP@@paymentService","metadata":{"my.key2":"value2","gjs.canhandle.vCustomerDistribution":"value1"},"instanceHeartBeatInterval":5000,"instanceHeartBeatTimeOut":15000,"ipDeleteTimeout":30000}],"lastRefTime":1686204572823,"checksum":"","allIPs":false,"reachProtectionThreshold":false,"valid":true}

Obtain an instance information from Nacos:

curl -X GET "http://39.100.80.168:8848/nacos/v1/ns/instance/?serviceName=paymentService&ip=192.168.163.1&port=8080&clusterName=BJ"

return result:

{"service":"DEFAULT_GROUP@@paymentService","ip":"192.168.163.1","port":8080,"clusterName":"BJ","weight":0.8,"healthy":true,"instanceId":null,"metadata":{"my.key2":"value2","gjs.canhandle.vCustomerDistribution":"value1"}}

 

Publish/modify the Nacos instance (note that the metadata format in the URL is not JSON):

curl -X PUT "http://39.100.80.168:8848/nacos/v1/ns/instance/?serviceName=paymentService&ip=192.168.163.1&port=8080&clusterName=BJ&metadata=my.key2=newvalue44,bb.xx=44,yyy=455555"

return result:

ok

Call again to get an instance information from Nacos:

{"service":"DEFAULT_GROUP@@paymentService","ip":"192.168.163.1","port":8080,"clusterName":"BJ","weight":1.0,"healthy":true,"instanceId":null,"metadata":{"yyy":"455555","my.key2":"newvalue44","gjs.canhandle.vCustomerDistribution":"value1","bb.xx":"44"}}

 

For more API operations, see Nacos official website Open API guide

Guess you like

Origin blog.csdn.net/zyplanke/article/details/120849248