服务发现、配置中心,Nacos帮我们都搞定了

677

听说微信搜索《Java鱼仔》会变更强哦!

本文收录于JavaStarter ,里面有我完整的Java系列文章,学习或面试都可以看看哦

(一)前言

如今微服务架构已经被炒的如火如荼,互联网公司况且不说,连我接触的一个国企现在都开始往微服务分布式架构发展。因此,我会通过最近几篇博客介绍目前比较流行的一些微服务组件,其实微服务并没有那么难。如果在跑项目过程中,想要知道整个项目的所有依赖pom文件或者任何疑问,直接联系我即可

(二)SpringCloudAlibaba

以前一直听人说SpringCloud,现在又冒出来一个Spring Cloud Alibaba,其实Spring Cloud Alibaba是Spring Cloud下的一个子项目。Spring Cloud不是一个新的框架,而是一系列框架的集合,Spring Cloud Alibaba同样如此。按照官方的说法,Spring Cloud Alibaba为分布式应用程序开发提供了一站式解决方案,它包含开发分布式应用程序所需的所有组件,使您可以轻松地使用Spring Cloud开发应用程序,总结一句话,Spring Cloud Alibaba可以让分布式开发更加简单,并且他提供的开源组件也经历了双十一的洗礼,绝对是如今分布式系统开发的首要选择。

SpringCloudAlibaba中的开源组件有:Nacos Discovery、Nacos Config、Sentinel、RocketMQ、Dubbo Spring Cloud。

官网如下:spring.io/projects/sp…

(三)Nacos

Nacos是alibaba开源的一个动态服务发现、配置管理和服务管理平台,Nacos约等于eureka+springcloudconfig。

所谓服务发现,其实就是指服务的提供者将服务注册到一个统一的平台,服务的消费者从这个统一的平台中获取服务进行调用

服务注册调用

Nacos就提供了这样一个服务注册中心的平台,而且基于SpringBoot开发,十分简单。

所谓配置中心,就是将项目中的一系列配置(那些原本写在application.properties配置),放到一个统一的平台,就不需要给每个微服务都重新配置,也更加方便管理。

服务配置中心

以上两点就是Nacos的功能,了解Nacos能做什么之后,接下来就是代码实践了。在此之前先安装Nacos,我用的是linux版本。

给出Nacos的下载地址:我下载的是最新的1.4.1版本

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

下载这个文件

上传到linux系统上后,先部署:

tar -zxvf nacos-server-1.4.1.tar.gz -C /usr/local/

进到/usr/local/,启动服务,单机环境下需要加上参数-m standalone

./startup.sh -m standalone

可以通过启动的sh文件看到原因:不加standalone参数情况下启动的是集群服务

if [[ "${MODE}" == "standalone" ]]; then
    echo "nacos is starting with standalone"
else
    echo "nacos is starting with cluster"
fi

启动后访问:http://ip:8848/nacos/ 即可进入nacos管理页面,默认登陆名和密码都是nacos

(四)Nacos实现服务注册发现中心

4.1 服务注册

Nacos通过简单的注解,就可以快速注册服务,首先Nacos依赖:

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

在application.properties中配置nacos的地址、用户名以及密码:

server.port=8081
spring.application.name=nacos-discovery-provider

# 单机环境下
spring.cloud.nacos.discovery.server-addr=192.168.78.128:8848
#集群环境下,地址逗号分开
#spring.cloud.nacos.discovery.server-addr=192.168.78.128:8848,192.168.78.129:8848

spring.cloud.nacos.username=nacos
spring.cloud.nacos.password=nacos

接着在启动类中增加一个开启注解

@EnableDiscoveryClient //开启服务注册发现

在这里实现一个最简单的接口:

@RestController
public class IndexController {
    @GetMapping("/{name}")
    public String index(@PathVariable("name") String name){
        return "provider "+name;
    }
}

启动服务后就可以在Nacos的管理页面中看到注入的服务

服务注册

4.2 调用服务

前面已经把一个服务注册到Nacos,接下来需要用另外一个服务去调用它,调用方式有很多,这里主要介绍两种:由于调用中会用到feign和ribbon,先引入依赖:

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

通过RestTemplate调用 首先在启动类中将RestTemplate注入到Bean容器中:

@LoadBalanced //负载均衡
@Bean
public RestTemplate restTemplate(){
    return new RestTemplate();
}

然后在代码中直接通过服务名称调用即可

@Slf4j
@RestController
public class TestController {
    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/rest/{name}")
    public String etIndex2(@PathVariable("name")String name){
        String url="http://nacos-discovery-provider/"+name;
        return restTemplate.getForObject(url,String.class);
    }
}

通过feign调用

在启动类时开启注解**@EnableFeignClients**

使用方式也很简单,三个步骤

建立对应于服务提供者的接口:

@FeignClient(name = "nacos-discovery-provider",fallback = TestServiceFallback.class,configuration = FeignConfiguration.class)
public interface TestService {
    @GetMapping("/{name}")
    String index(@PathVariable("name") String string);
}

TestServiceFallback对应于报错回调

public class TestServiceFallback implements TestService{
    @Override
    public String index(String string) {
        return null;
    }
}

FeignConfiguration将回调类注入到Bean容器中

public class FeignConfiguration {
    @Bean
    public TestServiceFallback testServiceFallback(){
        return new TestServiceFallback();
    }
}

最后在Controller中调用Feign接口:

@Slf4j
@RestController
public class TestController {
    @Autowired
    private TestService testService;
    @GetMapping("/feign/{str}")
    public String etIndex3(@PathVariable("str")String string){
        return testService.index(string);
    }
}

4.3 在代码中获取Nacos服务的数据

有时候在业务逻辑中需要获取到Nacos中服务的列表以及详细信息,可以通过DiscoveryClient来实现

@Slf4j
@RestController
public class TestController {
    @Autowired
    private DiscoveryClient discoveryClient;
    @GetMapping("/services/{services}")
    public Object getService(@PathVariable("services")String services){
        log.info(String.valueOf(discoveryClient.getServices()));
        return discoveryClient.getInstances(services);
    }
}

注意点:如果Nacos服务宕机了,以前已经调用过的接口依旧可以被调用,因为Nacos客户端会缓存调用信息。

(五)Nacos作为配置中心

Nacos提供用于存储配置和其他元数据的key/value存储,为分布式系统中的外部化配置提供服务器端和客户端支持。Nacos-config的核心依赖是:

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

首先在配置中心新建一行配置

配置中心 具体内容如下:

在这里插入图片描述

如果在SpringBoot项目中要使用配置中心的话,需要新建一个bootstrap.properties配置文件,在配置文件中配置相关信息:

server.port=8084

spring.application.name=nacos-discovery-config

spring.cloud.nacos.username=nacos
spring.cloud.nacos.password=nacos

spring.cloud.nacos.discovery.server-addr=192.168.78.128:8848
spring.cloud.nacos.config.server-addr=192.168.78.128:8848

#如果需要使用yaml格式的,需要在配置文件中进行文件类型扩展
#spring.cloud.nacos.config.file-extension=yaml

接着就可以在代码中使用配置文件了,具体如何使用配置文件方式和使用本地配置文件一样,这里介绍一种:

@RestController
public class TestController {
    @Value("${user.name}")
    private String name;
    @Value("${user.addr}")
    private String addr;
    @GetMapping("/config")
    public String config(){
        return name+"----------"+addr;
    }
}

配置中心的多环境版本

在之前使用springboot时,我们会新建多个配置文件,如application-dev.properties、application-test.properties,然后使用spring.profiles.active=dev去激活对应的配置文件。

在Nacos中,同样也可以这样操作,新建一个dev的配置文件:注意命名需要加后缀,不然获取不到

配置一个开发环境的配置文件

bootstrap.properties中去激活:

spring.profiles.active=dev

这样访问的就是${spring.application.name}-${spring.profiles.active}.${file-extension}文件了

Nacos服务配置数据模型

Nacos的配置中心在权限隔离上有三个概念,命名空间、组(Group)、Data ID,这三个概念都是用来隔离区分的,可以在代码中指定对应的命名空间、组和Data ID,来获取到唯一的配置文件。

数据模型

在代码中可以配置命名空间、组信息,从而选择适合该应用的配置文件。

#配置组
spring.cloud.nacos.config.group=My_GROUP
#配置命名空间
spring.cloud.nacos.config.namespace=9464c719-e93b-414f-a904-2f21ec540178

(六)Nacos数据持久化

Nacos中的数据默认是保存在内嵌数据库中的,0.7版本后增加了mysql数据库的支持。新建一个数据库,我这里命名为nacos_config,然后执行官方的sql语句:

/*
 * Copyright 1999-2018 Alibaba Group Holding Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_info   */
/******************************************/
CREATE TABLE `config_info` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `data_id` varchar(255) NOT NULL COMMENT 'data_id',
  `group_id` varchar(255) DEFAULT NULL,
  `content` longtext NOT NULL COMMENT 'content',
  `md5` varchar(32) DEFAULT NULL COMMENT 'md5',
  `gmt_create` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '修改时间',
  `src_user` text COMMENT 'source user',
  `src_ip` varchar(20) DEFAULT NULL COMMENT 'source ip',
  `app_name` varchar(128) DEFAULT NULL,
  `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
  `c_desc` varchar(256) DEFAULT NULL,
  `c_use` varchar(64) DEFAULT NULL,
  `effect` varchar(64) DEFAULT NULL,
  `type` varchar(64) DEFAULT NULL,
  `c_schema` text,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_configinfo_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info';

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_info_aggr   */
/******************************************/
CREATE TABLE `config_info_aggr` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `data_id` varchar(255) NOT NULL COMMENT 'data_id',
  `group_id` varchar(255) NOT NULL COMMENT 'group_id',
  `datum_id` varchar(255) NOT NULL COMMENT 'datum_id',
  `content` longtext NOT NULL COMMENT '内容',
  `gmt_modified` datetime NOT NULL COMMENT '修改时间',
  `app_name` varchar(128) DEFAULT NULL,
  `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_configinfoaggr_datagrouptenantdatum` (`data_id`,`group_id`,`tenant_id`,`datum_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='增加租户字段';


/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_info_beta   */
/******************************************/
CREATE TABLE `config_info_beta` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `data_id` varchar(255) NOT NULL COMMENT 'data_id',
  `group_id` varchar(128) NOT NULL COMMENT 'group_id',
  `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
  `content` longtext NOT NULL COMMENT 'content',
  `beta_ips` varchar(1024) DEFAULT NULL COMMENT 'betaIps',
  `md5` varchar(32) DEFAULT NULL COMMENT 'md5',
  `gmt_create` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '修改时间',
  `src_user` text COMMENT 'source user',
  `src_ip` varchar(20) DEFAULT NULL COMMENT 'source ip',
  `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_configinfobeta_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_beta';

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_info_tag   */
/******************************************/
CREATE TABLE `config_info_tag` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `data_id` varchar(255) NOT NULL COMMENT 'data_id',
  `group_id` varchar(128) NOT NULL COMMENT 'group_id',
  `tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
  `tag_id` varchar(128) NOT NULL COMMENT 'tag_id',
  `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
  `content` longtext NOT NULL COMMENT 'content',
  `md5` varchar(32) DEFAULT NULL COMMENT 'md5',
  `gmt_create` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '修改时间',
  `src_user` text COMMENT 'source user',
  `src_ip` varchar(20) DEFAULT NULL COMMENT 'source ip',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_configinfotag_datagrouptenanttag` (`data_id`,`group_id`,`tenant_id`,`tag_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_tag';

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_tags_relation   */
/******************************************/
CREATE TABLE `config_tags_relation` (
  `id` bigint(20) NOT NULL COMMENT 'id',
  `tag_name` varchar(128) NOT NULL COMMENT 'tag_name',
  `tag_type` varchar(64) DEFAULT NULL COMMENT 'tag_type',
  `data_id` varchar(255) NOT NULL COMMENT 'data_id',
  `group_id` varchar(128) NOT NULL COMMENT 'group_id',
  `tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
  `nid` bigint(20) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`nid`),
  UNIQUE KEY `uk_configtagrelation_configidtag` (`id`,`tag_name`,`tag_type`),
  KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_tag_relation';

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = group_capacity   */
/******************************************/
CREATE TABLE `group_capacity` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `group_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Group ID,空字符表示整个集群',
  `quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值',
  `usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',
  `max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值',
  `max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数,,0表示使用默认值',
  `max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值',
  `max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',
  `gmt_create` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '修改时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_group_id` (`group_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='集群、各Group容量信息表';

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = his_config_info   */
/******************************************/
CREATE TABLE `his_config_info` (
  `id` bigint(64) unsigned NOT NULL,
  `nid` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `data_id` varchar(255) NOT NULL,
  `group_id` varchar(128) NOT NULL,
  `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
  `content` longtext NOT NULL,
  `md5` varchar(32) DEFAULT NULL,
  `gmt_create` datetime NOT NULL DEFAULT '2010-05-05 00:00:00',
  `gmt_modified` datetime NOT NULL DEFAULT '2010-05-05 00:00:00',
  `src_user` text,
  `src_ip` varchar(20) DEFAULT NULL,
  `op_type` char(10) DEFAULT NULL,
  `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
  PRIMARY KEY (`nid`),
  KEY `idx_gmt_create` (`gmt_create`),
  KEY `idx_gmt_modified` (`gmt_modified`),
  KEY `idx_did` (`data_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='多租户改造';


/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = tenant_capacity   */
/******************************************/
CREATE TABLE `tenant_capacity` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `tenant_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Tenant ID',
  `quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值',
  `usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',
  `max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值',
  `max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数',
  `max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值',
  `max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',
  `gmt_create` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '修改时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='租户容量信息表';


CREATE TABLE `tenant_info` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `kp` varchar(128) NOT NULL COMMENT 'kp',
  `tenant_id` varchar(128) default '' COMMENT 'tenant_id',
  `tenant_name` varchar(128) default '' COMMENT 'tenant_name',
  `tenant_desc` varchar(256) DEFAULT NULL COMMENT 'tenant_desc',
  `create_source` varchar(32) DEFAULT NULL COMMENT 'create_source',
  `gmt_create` bigint(20) NOT NULL COMMENT '创建时间',
  `gmt_modified` bigint(20) NOT NULL COMMENT '修改时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_tenant_info_kptenantid` (`kp`,`tenant_id`),
  KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='tenant_info';

CREATE TABLE users (
	username varchar(50) NOT NULL PRIMARY KEY,
	password varchar(500) NOT NULL,
	enabled boolean NOT NULL
);

CREATE TABLE roles (
	username varchar(50) NOT NULL,
	role varchar(50) NOT NULL,
	constraint uk_username_role UNIQUE (username,role)
);

CREATE TABLE permissions (
    role varchar(50) NOT NULL,
    resource varchar(512) NOT NULL,
    action varchar(8) NOT NULL,
    constraint uk_role_permission UNIQUE (role,resource,action)
);

INSERT INTO users (username, password, enabled) VALUES ('nacos', '$2a$10$EuWPZHzz32dJN7jexM34MOeYirDdFAZm2kuWj7VEOJhhZkDrxfvUu', TRUE);

INSERT INTO roles (username, role) VALUES ('nacos', 'ROLE_ADMIN');

执行完成后会创建一系列的表,接下来在nacos的配置文件(conf/application.properties)中配置数据库连接:

spring.datasource.platform=mysql
### Count of DB:
db.num=1
### Connect URL of DB:
db.url.0=jdbc:mysql://192.168.199.170:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=123456

配置完成后所有的数据都会放在外部的Mysql中了。

(七)总结

至此,你已经可以将Nacos放到具体的项目中使用了。等真正在项目中用过一段时间后,再去探究它的源码,将会更加简单。你会累是因为你在走上坡路,我是鱼仔,我们下期再见!