飞天班第30节:整合Nacos

2020/05/03

1、Nacos

基本概念

官网:https://nacos.io/zh-cn/docs/quick-start.html

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

Nacos(Naming&Configuration&Service) 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。

常见的注册中心

服务注册与发现框架 CAP模型 控制台管理 社区活跃度
Eureka AP(可用,分区容错) 支持 低,2.x版本闭源
Zookeeper专业级的独立产品,Dubbo CP(数据一致性,分区容错) 不支持
Consul (Go语言),使用参考我这篇博客 CP 支持
Nacos AP和CP模式切换的 支持

Nacos的主要功能

1、服务发现和服务健康监测()

2、动态配置服务

3、动态DNS服务

4、服务及元数据管理

与SpringCloud Netflix全家桶对比:Eureka(注册) + Config(配置) + Bus(数据总线) = Nacos

一图看懂:

架构图:

下载安装

Nacos依赖于Java环境,所以必须安装Java环境。然后从官网下载Nacos的解压包,安装稳定版的,下载地址:https://github.com/alibaba/nacos/releases

目前最新版本是1.2.1

解压后文件的/bin目录下,windows系统点击startup.cmd就可以启动nacos。linux或mac执行以下命令启动nacos。

# 停止
./shutdown.sh
tar -zxvf nacos-server-1.1.4.tar.gz
cd nacos/bin
# 单机模式启动,不带standalone就是集群模式
./startup.sh -m standalone
# 启动好后可以直接访问了
http://localhost:8848/nacos
# 端口默认:8848,用户名密码:nacos/nacos

nacos的启动端口为8848,在启动时要保证端口不被占用。 启动成功,在浏览器上访问:http://localhost:8848/nacos 会跳转到登陆界面,

默认的登陆用户名密码都是nacos : nacos。

集群模式参考官方文档配置https://nacos.io/zh-cn/docs/cluster-mode-quick-start.html

使用Nacos注册服务

在springcloud的官网上,有Spring Cloud Alibaba 的使用文档

edu-edu和edu-vod 俩个服务都注册到nacos

1、pom.xml导入依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <version>0.9.0.RELEASE</version>
</dependency>

2、配置文件appliation.properties增加nacos server地址配置

# 具体的Nacos实例地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848

3、启动类开启注解@EnableDiscoveryClient

// @EnableEurekaClient 只有Eureka可以用
// 通过 Spring Cloud 原生注解 @EnableDiscoveryClient 开启服务注册发现功能
@SpringBootApplication
@ComponentScan(basePackages = {"com.coding.edu","com.coding.common"})
@EnableDiscoveryClient
public class EduApplication {
    public static void main(String[] args) {
        SpringApplication.run(EduApplication.class,args);
    }
}

4、启动测试,成功注册到nacos

使用Nacos做配置中心

回看自己写的这篇博客

Springcloud之前是config+bus+github来及进行配置中心设置的,现在直接使用Nacos一个服务就能搞定前面三个的工作了,

1、项目中导入依赖

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

2、配置bootstrap.yml文件

server:
  port: 30001
spring:
  application:
    name: nacos-provider
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
      config:
        server-addr: 127.0.0.1:8848
        file-extension: yml

一定要配置bootstrap.yml文件,系统级别的优先级比application.yml高

配置application.yml

management:
  endpoints:
    web:
      exposure:
        incloud: '*'
spring:
  profiles:
    active: dev # 获取dev的配置

3、Controller 添加注解@RefreshScope,是为了让程序中通过@Value从Nacos配置中心获取的值可以动态刷新

@RestController
//配置支持动态更新
@RefreshScope
public class ProviderController {

    @Value("${config.info}")
    private String config;

    @Value("${server.port}")
    private String server_port;

    @GetMapping("sayhello")
    public String getInfo(){
        return "say hello: "+server_port+" config: "+config;
    }
}

Nacos的配置文件格式

${prefix}-${spring.profile.active}.${file-extension}
  • prefix:默认就是spring.application.name的值,也可以通过配置项:spring.cloud.nacos.config.prefix来配置
  • spring.profile.active:为当前环境对应的profile,如果这个为空整个的格式就会变为:${prefix}.${file-extension}
  • file-extension:为配置内容的数据格式,可以通过配置项spring.cloud.nacos.config.file-extension来配置,目前支持properties和yaml,不配置的话,默认是properties,官方文档上有说,文件后缀名一定要保持一致

在Nacos新建一个配置

Nacos分组的概念

命名空间 -> 分组 ->服务,可以按照命名空间和组的关系进行相应服务的隔离

默认访问DEFAULT_GROUP,在bootstrap.yml修改访问的组名

server:
  port: 30001
spring:
  application:
    name: nacos-provider
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
      config:
        server-addr: 127.0.0.1:8848
        file-extension: yml
        group: DEV_GROUP
分组可以实现相同的DataId在不同的组来进行数据的隔离

Nacos命名空间的概念

默认有一个public的空间

新建一个命名空间gavinspace

在gavinspace新建配置文件

在springboot项目的bootstrap.yml修改访问的命名空间

server:
  port: 30001
spring:
  application:
    name: nacos-provider
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
      config:
        server-addr: 127.0.0.1:8848
        file-extension: yml
        namespace: c6de805f-0548-441a-8e6f-f2d87afc3d37

Nacos集群化

首先要考虑的问题,

  • 将nacos配置的数据中心化,放到mysql,也可以是mycat。
  • 不是所有的节点都对外提供服务的,它需要一个节点来管理Nacos集群,做负载均衡

下面用一台服务器启动3个Nacos实例,当然3台服务器3个Nacos实例也是如此的操作。

1、首先修改conf目录下的cluster.conf.example更改为cluster.conf,并在文件里增加以下内容

[root@helloworld conf]# cp cluster.conf.example cluster.conf
[root@helloworld conf]# vim cluster.conf
# 如果不指定端口,那就是默认的8848
# 注意,这里的ip不能写127.0.0.1,如果是127的话,服务都注册不上
172.16.0.3:8848
172.16.0.3:8858
172.16.0.3:8868

2、配置Mysql数据库

集群模式必须使用MySQL数据库,生产使用建议至少主备模式,或者采用高可用数据库

  • 初始化数据库

    在nacos的conf目录下有个脚本文件nacos-mysql.sql,创建数据库nacos_config,再执行脚本文件创建表

  • 添加数据库连接

    在conf目录下的配置文件application.properties中将以下配置填入

    spring.datasource.platform=mysql
      
    db.num=1
    db.url.0=jdbc:mysql://127.0.0.1:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
    db.user=root
    db.password=gavin
      
    # db.num 为数据库实例数量
    # db.url.0 指定第一个数据库连接
    # 如果有多个数据库实例通过 db.url.0、db.url.1… 指定不同的数据库连接
    

3、修改bin目录下的startup.sh 如下内容,增加ip的输入

[root@helloworld bin]# vim startup.sh
while getopts ":m:f:s:p:" opt
do
    case $opt in
        m)
            MODE=$OPTARG;;
        f)
            FUNCTION_MODE=$OPTARG;;
        s)
            SERVER=$OPTARG;;
        p)
            PORT=$OPTARG;;  # 传入端口的参数
        ?)
        echo "Unknown parameter"
        exit 1;;
    esac
done

在startup.sh 最下面增加脚本,使用命令传入的端口启动Nacos:-Dserver.port=${PORT}

[root@helloworld bin]# vim startup.sh
echo "$JAVA ${JAVA_OPT}" > ${BASE_DIR}/logs/start.out 2>&1 &
nohup $JAVA -Dserver.port=${PORT} ${JAVA_OPT} nacos.nacos >> ${BASE_DIR}/logs/start.out 2>&1 &
echo "nacos is starting,you can check the ${BASE_DIR}/logs/start.out"

4、启动三台Nacos服务,端口要和cluster.conf文件里配置一致

./bin/startup.sh -p 8848
./bin/startup.sh -p 8858
./bin/startup.sh -p 8868

这时随便访问一个nacos实例都是可以的

使用Nginx做负载均衡来访问

修改nginx的配置文件,增加nacos负载均衡的反向代理,默认策略时轮询访问

upstream nacos {
    server 127.0.0.1:8848;
    server 127.0.0.1:8858;
    server 127.0.0.1:8868;
}

server {
    listen       80;
    server_name  localhost;

    #charset koi8-r;

    #access_log  logs/host.access.log  main;

    location / {
        root   html;
        index  index.html index.htm;
        proxy_pass http://nacos;
    }
 }

# 关闭nginx
nginx -s stop
# 检查配置文件
nginx -t
# 启动nginx
nginx

访问http://139.199.13.139/nacos/#/login

Nacos的集群总结

  • 需要将各个Nacos的配置保存节点数据从各自的Derby数据库移动到中心化的MySQL上
  • 在Nacos服务的的conf里cluster.conf文件中配置集群的各个ip和端口
  • 启动三个以上的Nacos节点,每个节点都要和cluster文件中配置的ip和端口一致
  • 统一使用一个负载均衡节点比如Nginx或HAProxy来进行负载均衡链接Nacos
  • 应用服务注册到Nacos,应该访问Nginx的IP来做负载均衡的HA,比如我这里的http://139.199.13.139/nacos

作业:配置一个Nacos集群并将配置数据存储到MySQL中

作业完成:

2、Feign调用删除阿里云视频

任务:edu 服务 feign调用vod服务删除阿里云上的视频

回顾Feign:

  • 声明式、模板化、Http客户端! 作用: 微服务之间调用HTTP api!
  • Ribbon(负载均衡,客户端),Hystrix (服务降级!) 无缝集成这两个!

1、edu-edu的pom.xml添加依赖

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

2、edu-edu的主启动类添加 Feign的支持注解@EnableFeignClients

@SpringBootApplication
@ComponentScan(basePackages = {"com.jude.edu","com.jude.common"})
@EnableDiscoveryClient 
@EnableFeignClients
public class EduApplication {
	public static void main(String[] args) {
		SpringApplication.run(EduApplication.class,args);
	}
}

3、edu-edu的feign接口VodClient

@FeignClient(name = "edu-vod")
public interface VodClient {
	// 直接调用服务中的请求
	@DeleteMapping("/admin/vod/video/{videoId}")
	R removeVideo(@PathVariable("videoId") String videoId);
}

4、edu-edu的业务层接口VideoService

void removeVideoById(String id);

接口实现类VideoServiceImpl

@Autowired
VodClient vodClient;

@Override
public void removeVideoById(String id) {
    Video video = this.getById(id);
    // 删除oss上的视频
    String sourceId = video.getVideoSourceId();
    if (!StringUtils.isEmpty(sourceId)){
        // 调用vod微服务的方法,删除云端视频
        R r = vodClient.removeVideo(sourceId);
        if (r.getCode()!= 20000) { // 返回结果不是ok
            throw new JudeException(r.getCode(),r.getMessage());
        }
    }

    this.removeById(id);
}

5、edu-eud web层接口的定义

@ApiOperation(value = "根据id删除课时节点")
@DeleteMapping("{id}")
public R deleteById(@ApiParam(name = "id",value = "课时id",required = true) @PathVariable String id){
    videoService.removeVideoById(id);
    return R.ok();
}

测试服务调用

edu-admin-login也注册到nacos,启动nginx、nacos、edu-admin-login、edu-edu、edu-vod 和 前端后台vue工程edu-admin

xjwdeMacBook:jude-web-admin xjw$ npm run dev
 DONE  Compiled successfully in 7714ms                                                           15:58:15

 I  Your application is running here: http://localhost:9528

3、Hystrix服务降级

Spring Cloud 调用接口的过程

Zuul -> Feign -> Hsystix -> Ribbon -> HttpClient,如下图:

1、edu-edu 开启熔断支持

feign.hystrixs.enabled=true

2、edu-edu编写降级方法

@Component
public class VodClientHystrixFallback implements VodClient {
    @Override
    public R removeVideo(String videoId) {
        return R.error().message("服务降级,VodClientHystrixFallback...执行中");
    }
}

3、edu-edu的feign接口VodClient添加失败回调

@FeignClient(name = "edu-vod",fallback = VodClientHystrixFallback.class)
public interface VodClient {
	// 直接调用服务中的请求
	@DeleteMapping("/admin/vod/video/{videoId}")
	R removeVideo(@PathVariable("videoId") String videoId);
}

测试

把edu-vod服务关掉,删除视频

区分服务降级和服务熔断

  • 服务降级:客户端调用服务无法访问,调用Hystrix的fallback方法,实现服务降级
  • 服务熔断:服务端方法异常,调用 @HystrixCommand 的fallbackMethod,快速返回。

Post Directory