服务发现、配置中心,Nacos帮我们都搞定了
作者:鱼仔
博客首页: https://codeease.top
公众号: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。
官网如下:https://spring.io/projects/spring-cloud-alibaba/
# (三)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
2
3
4
5
启动后访问: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>
2
3
4
在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
2
3
4
5
6
7
8
9
10
接着在启动类中增加一个开启注解
@EnableDiscoveryClient //开启服务注册发现
在这里实现一个最简单的接口:
@RestController
public class IndexController {
@GetMapping("/{name}")
public String index(@PathVariable("name") String name){
return "provider "+name;
}
}
2
3
4
5
6
7
启动服务后就可以在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>
2
3
4
5
6
7
8
通过RestTemplate调用 首先在启动类中将RestTemplate注入到Bean容器中:
@LoadBalanced //负载均衡
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
2
3
4
5
然后在代码中直接通过服务名称调用即可
@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);
}
}
2
3
4
5
6
7
8
9
10
11
12
通过feign调用
在启动类时开启注解**@EnableFeignClients**
使用方式也很简单,三个步骤
建立对应于服务提供者的接口:
@FeignClient(name = "nacos-discovery-provider",fallback = TestServiceFallback.class,configuration = FeignConfiguration.class)
public interface TestService {
@GetMapping("/{name}")
String index(@PathVariable("name") String string);
}
2
3
4
5
TestServiceFallback对应于报错回调
public class TestServiceFallback implements TestService{
@Override
public String index(String string) {
return null;
}
}
2
3
4
5
6
FeignConfiguration将回调类注入到Bean容器中
public class FeignConfiguration {
@Bean
public TestServiceFallback testServiceFallback(){
return new TestServiceFallback();
}
}
2
3
4
5
6
最后在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);
}
}
2
3
4
5
6
7
8
9
10
# 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);
}
}
2
3
4
5
6
7
8
9
10
11
注意点:如果Nacos服务宕机了,以前已经调用过的接口依旧可以被调用,因为Nacos客户端会缓存调用信息。
# (五)Nacos作为配置中心
Nacos提供用于存储配置和其他元数据的key/value存储,为分布式系统中的外部化配置提供服务器端和客户端支持。Nacos-config的核心依赖是:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
2
3
4
首先在配置中心新建一行配置
具体内容如下:
如果在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
2
3
4
5
6
7
8
9
10
11
12
接着就可以在代码中使用配置文件了,具体如何使用配置文件方式和使用本地配置文件一样,这里介绍一种:
@RestController
public class TestController {
@Value("${user.name}")
private String name;
@Value("${user.addr}")
private String addr;
@GetMapping("/config")
public String config(){
return name+"----------"+addr;
}
}
2
3
4
5
6
7
8
9
10
11
# 配置中心的多环境版本
在之前使用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
2
3
4
# (六)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');
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
执行完成后会创建一系列的表,接下来在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
2
3
4
5
6
7
配置完成后所有的数据都会放在外部的Mysql中了。
# (七)总结
至此,你已经可以将Nacos放到具体的项目中使用了。等真正在项目中用过一段时间后,再去探究它的源码,将会更加简单。你会累是因为你在走上坡路,我是鱼仔,我们下期再见!