vlambda博客
学习文章列表

不会服务治理怎么做微服务, 试试nacos


什么是Nacos

用于发现、配置和管理微服务的工具平台


ta可以做什么


构建以“服务”为中心的现代应用架构

实现动态服务发现、服务配置、服务元数据及流量管理

地位: 替代注册中心(eureka、consul等传统方案)和 配置中心(spring cloud config)


1. 下载

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

2. 安装

2.1. 单机部署

解压缩即可

2.2. 集群部署

3个或3个以上Nacos节点才能构成集群

复制3个nacos安装文件夹, 分别命名 nacos 1,2,3

在所有nacos目录的conf目录下,有文件cluster.conf.example,将其命名为cluster.conf,并将每行配置成ip:port格式

127.0.0.1:8848
127.0.0.1:8849
127.0.0.1:8850

3. 启动和关闭Nacos server

3.1. 启动

需要先配置JAVA_HOME, 最低版本jdk8

进入cmd 输入 startup.cmd -m standalone

闪过一堆文字, 看到

INFO Nacos started successfully in stand alone mode...

启动完成

3.2. 集群模式启动

每个节点都启动命令

`startup.cmd -m cluster`

3.3. 关闭

shutdown.cmd

4. 登录控制台

http://localhost:8848/nacos

账密: nacos / nacos

5. 基本名词

nacos的结构如下

namespace > group > service / dataid

Namespace:代表不同环境,如开发、测试、生产环境。
Group:代表某项目,如XX医疗项目、XX电商项目
DataId:每个项目下往往有若干个工程,每个配置集(DataId)是一个工程的主配置文件

5.1. 命名空间 Namespace

namespace, 以下简称ns, 代表环境

默认空间为public, 未指定时使用默认

解决对环境和多租户问题

单租户多环境

可以创建: 开发 dev, 测试 test, 生产 prod 等多个ns, 以实现隔离

多租户

可以由管理员nacos, 在权限管理中, 给不同的用户, 分配不同的ns资源, 以实现隔离

5.2. 配置分组 Group

用于对配置集进行分组, 通常一个Group代表一个项目

默认分组为DEFAULT_GROUP, 未指定时使用默认

通常按项目或应用建立分组

5.3. 配置集 Data ID

一组配置文件, 可以理解为一个.properties文件, 或一个yaml文件

每个Data ID代表一套配置项的文件集合, 即一个Java Project的配置文件

配置项是其中的内容, 以key=value格式存放

例如springboot中的application.properties的内容, 数据源配置, 日志配置等等, 都可以做成配置集

ext-config[index] 的优先级,index越小,优先级越高,从0开始

6. 配置中心

6.1. 配置属性

注意: 创建后dataid和group无法修改, 要改只能删掉重建

在nacos管理器的配置列表里建立配置文件信息, 得到dataid

server.port=8888
server.servlet.context-path=/myconfig

nacos.config.server-addr=localhost:8848
nacos.config.namespace=1fdbe251-032b-416a-8323-fe9cf68cdc51

在启动类里, 加上读取配置来源

@SpringBootApplication
@NacosPropertySource(dataId = "myprop", groupId="myproject", autoRefreshed = true)
public class MynacosConfigApplication {
    public static void main(String[] args) {
        SpringApplication.run(MynacosConfigApplication.class, args);
    }
}

这样, 此项目会采用指定ns下的, group=myproject的myprop配置文件

然后在类里可以使用配置属性, 属性值会跟随配置变更而自动变化

@NacosValue(value = "${user:david}", autoRefreshed = true)
private String user;

另一种刷新参数的方法, @RefreshScope

@RefreshScope
public class IdEntity {
    @Value("${id}")
    private int id;
}

附: SpringBoot项目的复杂配置文件参考

nacos.config.bootstrap.enable=true
nacos.config.server-addr=192.168.16.104:8848    # 主配置服务器地址
nacos.config.data-id=people    # 主配置 data-id
nacos.config.group=DEFAULT_GROUP    # 主配置 group-id
nacos.config.type=properties    # 主配置 配置文件类型
nacos.config.max-retry=10    # 主配置 最大重试次数
nacos.config.auto-refresh=true    # 主配置 开启自动刷新
nacos.config.config-retry-time=2333    # 主配置 重试时间
nacos.config.config-long-poll-timeout=46000    # 主配置 配置监听长轮询超时时间
nacos.config.enable-remote-sync-config=true    # 主配置 开启注册监听器预加载配置服务(除非特殊业务需求,否则不推荐打开该参数)

nacos.config.ext-config[0].data-id=test
nacos.config.ext-config[0].group=DEFAULT_GROUP
nacos.config.ext-config[0].max-retry=10
nacos.config.ext-config[0].type=yaml
nacos.config.ext-config[0].auto-refresh=true
nacos.config.ext-config[0].config-retry-time=2333
nacos.config.ext-config[0].config-long-poll-timeout=46000
nacos.config.ext-config[0].enable-remote-sync-config=true

可以查看健康审计

http://localhost:8888/myconfig/actuator/

6.2. 托管application.properties

采用Spring Cloud模式, 根目录下放 bootstrap.properties 和 application.properties

加载顺序 bootstrap.* > application.* > application-dev(prod).*

思路: bootstrap里, 声明连接nacos配置; application里, 只定义context和port, 其他都可以在nacos里动态配置

pom.xml

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    <version>2.2.5.RELEASE</version>
</dependency>

bootstrap.properties, 以下配置将在程序启动时, 去127.0.0.1:8848的nacos server, 查找namespace下的, group名为myserver里面的, Data ID为mysql80.properties的配置信息

spring.application.name=mysql80

spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.namespace=1fdbe251-032b-416a-8323-fe9cf68cdc51
spring.cloud.nacos.config.group=myserver

application.properties只配置固定项

server.port=8900
server.servlet.context-path=/config-cloud

此时, 系统里用到的配置内容就会被自动加载

@Configuration
public class HikariCpConfig {
    private Logger logger = LoggerFactory.getLogger(HikariConfig.class);
 
    @Value("${spring.datasource.url}")
    private String dbUrl;
 
    @Value("${spring.datasource.type}")
    private String type;
 
    @Value("${spring.datasource.username}")
    private String username;
 
    @Value("${spring.datasource.password}")
    private String password;
 
    @Value("${spring.datasource.driver-class-name}")
    private String driverClassName;
}

7. 注册中心

注册中心解决服务注册和服务发现两个问题

注册时可指定namespace, 不指定则默认public

同一个注册中心的微服务之间, 如果ns不同或group不同, 则无法通讯

7.1. 服务注册

在application.properties里配置注册中心, 以及注册信息

server.port=8888
server.servlet.context-path=/myserver

spring.application.name=myserver
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.cloud.nacos.discovery.namespace=1fdbe251-032b-416a-8323-fe9cf68cdc51
spring.cloud.nacos.discovery.group=myappgroup

以上将会注册一个服务myserver, 放在指定的ns和group下

在启动类增加注解

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

然后可以在项目里, 定义各种api

@RestController
public class UserController {
    @RequestMapping(value = "/login", method = RequestMethod.GET)  
    public String login(String name) {
        return "正在登陆: "+name;
    }
}

7.2. 服务发现

我们需要从注册中心找到服务, 进行调用, 首先要把自己也做注册

server.port=9999
server.servlet.context-path=/myclient

spring.application.name=myclient
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.cloud.nacos.discovery.namespace=1fdbe251-032b-416a-8323-fe9cf68cdc51
spring.cloud.nacos.discovery.group=myappgroup

在启动类增加注解

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

然后客户端程序就可以调用已注册的服务功能, 主要有下面三种方式, 大家可以自行选择. 

7.2.1 手工调用服务

配置RestTemplate, 高版本中为RestOperations

@Bean
RestOperations restTemplate(RestTemplateBuilder builder) {
    return builder.build();
}

在其他类里, 可以远程调用服务中心的类, 并自动负载均衡

@RestController
public class ClientController {
    @Autowired
    private RestOperations restTemplate;
    @Autowired
    private LoadBalancerClient loadBalancerClient;
    
    @GetMapping(value = "/remote")
    public String execRemote(String name) {
        ServiceInstance serviceInstance = loadBalancerClient.choose("myserver"); //注册中心的服务名
        String requestUrl = String.format("http://%s:%s/myserver/login?name=%s", serviceInstance.getHost(), serviceInstance.getPort(), name);
        String re=restTemplate.getForObject(requestUrl, String.class);
        return re;
    }
}

步骤1. 通过loadBalancerClient在注册中心, 查找名叫myserver的服务

步骤2. 构造访问路径, 服务提供者的ip:port由balanceClient获取, 如果多个实例, 则每次不一样

步骤3. Ribbon调用, 并获得返回值

7.2.2 自动通过负载均衡调用

配置RestTemplate是注明LoadBalanced

@LoadBalanced
@Bean
public RestTemplate restTemplateLoadBalanced() {
    return new RestTemplate();
}

调用时直接可以使用

@RestController
public class ClientController {
    @Autowired
    private RestTemplate restTemplateLoadBalanced;
    
    @GetMapping(value = "/remote")
    public String execRemote(String name) {
    Map params=new HashMap();
    params.put("name", name);
        //http://myserver/myserver/login 这个url里,
        //第一个myserver是spring.application.name, 即在nacos里注册的服务名称
        //第二个myserver是server.servlet.context-path, 即调用的应用的上下文路径
        String re=restTemplateLoadBalanced.getForObject("http://myserver/myserver/login", String.class, params);
        return re;
    }
}

7.2.3 通过feign访问

pom里要加入feign

    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-openfeign</artifactId>
      <version>2.2.2.RELEASE</version>
    </dependency>

启动类加入注解

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class MynacosClientApplication {
    ...
}

创建feign接口, 注意参数要写RequestParam

@FeignClient("myserver")
public intreface UserFeign {
    @RequestMapping(value = "/login", method = RequestMethod.GET)  
    public String login(@RequestParam("name") String name);
}

调用

@RestController
public class ClientController {
    @Autowired
    private UserFeign userFeign;
    
    @GetMapping(value = "/remote")
    public String execRemote(String name) {
        return userFeign.login(name);
    }
}


以上就是Nacos的配置过程,看完的小伙伴赶紧动手试试吧。



提升技术
每天学习10分钟