什么是nacos

Nacos是阿里巴巴开源的服务发现、配置管理和服务管理平台。它主要提供两大核心功能:

服务注册与发现:微服务启动时注册到Nacos,服务间通过服务名而非IP地址相互发现和调用。

配置中心:集中管理应用配置,支持动态更新,无需重启服务即可生效。

Nacos替代了Eureka和Config,简化了微服务架构,支持健康检查、动态DNS和流量管理,是云原生应用的关键组件。

我们先学习一下如何通过配置来实现服务注册与发现。

在centos上安装nacos

通过git clone获取最新版nacos-docker

git clone https://github.com/nacos-group/nacos-docker.git

完成后进入到nacos-docker/example目录下,使用以下命令进行nacos服务管理

启动服务
docker compose -f standalone-derby.yaml up -d
查看服务状态
docker compose -f standalone-derby.yaml ps
停止并移除服务
docker compose -f standalone-derby.yaml down
查看实时日志
docker compose -f standalone-derby.yaml logs -f
重启服务
docker compose -f standalone-derby.yaml restart
暂停/恢复服务
docker compose -f standalone-derby.yaml pause/unpause

如果未安装docker compose可以通过下面这个命令安装

sudo yum install -y docker-compose-plugin

nacos启动后可以通过docker ps查看容器启动情况,可以看到除了nacos-server还有grafana和prometheus这两个监控服务。这里先关注nacos-server的状态是UP即可。

还需留意nacos比较耗费系统资源,建议将虚拟机内存调整到4G以上。

CONTAINER ID   IMAGE                       COMMAND                  CREATED        STATUS       PORTS                                                                                                                             NAMES
ddd3ddc2a9dc   prom/prometheus:latest      "/bin/prometheus --c…"   11 hours ago   Up 2 hours   0.0.0.0:9090->9090/tcp, :::9090->9090/tcp                                                                                         prometheus
fdf54d32ef1f   grafana/grafana:latest      "/run.sh"                11 hours ago   Up 2 hours   0.0.0.0:3000->3000/tcp, :::3000->3000/tcp                                                                                         grafana
53d370c5430b   nacos/nacos-server:v3.1.1   "sh bin/docker-start…"   11 hours ago   Up 2 hours   0.0.0.0:8080->8080/tcp, :::8080->8080/tcp, 0.0.0.0:8848->8848/tcp, :::8848->8848/tcp, 0.0.0.0:9848->9848/tcp, :::9848->9848/tcp   nacos-standalone

服务启动后,可以在浏览器上登录nacos控制台,默认端口是8080

什么是openfeign

OpenFeign是Java的声明式HTTP客户端,常用于微服务架构。开发者只需编写接口并用注解(如@RequestMapping)声明远程服务的API契约,OpenFeign便会自动生成实现类,简化了服务间的HTTP调用。它整合了Ribbon实现负载均衡,并能与Eureka等服务发现组件协作,让微服务调用像调用本地方法一样简单,提升了代码的可读性与可维护性。

有了openfeign,我们只需要新增一个接口类(interface),按要求写一下格式,就可以很方便的实现调用了。如下图:

//UserClient.java

package com.decotest.orderservice;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(name ="user-service")
public interface UserClient {
    @GetMapping("/user/{id}")
    String getUserById(@PathVariable("id") String id);
}

服务注册及调用实例

新建两个服务,一个是user-service,一个是order-service。order-service调用user-service模拟用户验证。

user-service相关代码如下:

//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>3.3.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.decotest</groupId>
    <artifactId>user-service</artifactId>
    <version>0.0.1</version>
    <name>user-service</name>
    <description>user-service</description>
    <url/>
    <licenses>
        <license/>
    </licenses>
    <developers>
        <developer/>
    </developers>
    <scm>
        <connection/>
        <developerConnection/>
        <tag/>
        <url/>
    </scm>
    <properties>
        <java.version>17</java.version>
        <spring-cloud.version>2023.0.3</spring-cloud.version>
        <spring-cloud-alibaba.version>2023.0.3.2</spring-cloud-alibaba.version>
    </properties>


    <dependencyManagement>
        <dependencies>
            <!-- Spring Cloud 依赖管理 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- Spring Cloud Alibaba 依赖管理 -->
            <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>

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

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

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>
    </dependencies>

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

</project>
#application.properties

spring.application.name=user-service
server.port=8080

# Nacos server--此处需要修改为部署nacos的服务器地址
spring.cloud.nacos.discovery.server-addr=192.168.31.172:8848
spring.cloud.nacos.discovery.namespace=public
spring.cloud.nacos.discovery.group=DEFAULT_GROUP

# nacos client
spring.cloud.nacos.discovery.ip=127.0.0.1
spring.cloud.nacos.discovery.port=${server.port}
spring.cloud.nacos.discovery.service=${spring.application.name}
//UserServiceApplication.java

package com.decotest.userservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

//此处要增加nacos的注解EnableDiscoveryClient
@SpringBootApplication
@EnableDiscoveryClient
public class UserServiceApplication {

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

}
//userservice.java

package com.decotest.userservice;

import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class userservice {
    @RequestMapping("/user/{id}")
    public String getUserById(@PathVariable String id) {
        try {
            int iId = Integer.parseInt(id);
            if (iId < 10000) {
                return "user id(" + id + ") is alive";
            } else {
                return "user id(" + id + ") is not alive";
            }
        } catch (Exception e) {
            return "user id(" + id + ") is invalid";
        }
    }
}

order-service相关代码

//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>3.3.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.decotest</groupId>
    <artifactId>order-service</artifactId>
    <version>0.0.1</version>
    <name>order-service</name>
    <description>order-service</description>
    <url/>
    <licenses>
        <license/>
    </licenses>
    <developers>
        <developer/>
    </developers>
    <scm>
        <connection/>
        <developerConnection/>
        <tag/>
        <url/>
    </scm>
    <properties>
        <java.version>17</java.version>
        <spring-cloud.version>2023.0.3</spring-cloud.version>
        <spring-cloud-alibaba.version>2023.0.3.2</spring-cloud-alibaba.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <!-- Spring Cloud 依赖管理 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- Spring Cloud Alibaba 依赖管理 -->
            <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>

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

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

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
    </dependencies>

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

</project>
#application.properties

spring.application.name=order-service
server.port=8081

# Nacos server--此处需要修改为部署nacos的服务器地址
spring.cloud.nacos.discovery.server-addr=192.168.31.172:8848
spring.cloud.nacos.discovery.namespace=public
spring.cloud.nacos.discovery.group=DEFAULT_GROUP

# nacos client
spring.cloud.nacos.discovery.ip=127.0.0.1
spring.cloud.nacos.discovery.port=${server.port}
spring.cloud.nacos.discovery.service=${spring.application.name}

logging.level.com.decotest.feign.UserClient=DEBUG
//OrderServiceApplication.java

package com.decotest.orderservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

//此处要增加nacos的注解@EnableDiscoveryClient,以及OpenFeign的注解@EnableFeignClients
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class OrderServiceApplication {

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

}
//UserClient.java
//声明OpenFeign调用接口

package com.decotest.orderservice;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(name ="user-service")
public interface UserClient {
    @GetMapping("/user/{id}")
    String getUserById(@PathVariable("id") String id);
}
//orderservice.java

package com.decotest.orderservice;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.UUID;

@RestController
@RequestMapping("/order")
public class orderservice {
    @Autowired
    private UserClient uc;

    @RequestMapping("/place/{id}")
    public String placeOrder(@PathVariable String id){
        String userinfo;
        try {
            userinfo = uc.getUserById(id);    //通过openfeign接口进行服务调用
        } catch (Exception e) {
            return "call user-service error!";
        }

        if (userinfo.contains("is alive")) {
            return "order id " + UUID.randomUUID().toString() + " is placed by user " + id + "!";
        } else {
            return userinfo;
        }
    }
}

服务启动后,通过nacos控制台可以看到服务注册上来了

访问oder-service,可观察到服务调用

将user-service服务停掉后,再访问order-service,可观察调用失败的异常返回

大功告成!

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐