引言
我們都知道微服務(wù)項(xiàng)目需要一個(gè)注冊中心來實(shí)現(xiàn)對服務(wù)的注冊與發(fā)現(xiàn),便于監(jiān)控服務(wù)的健康狀態(tài)郊楣,統(tǒng)一管理每個(gè)服務(wù)憔恳,例如eurka,zookeeper等都可以作為服務(wù)注冊中心來使用净蚤,18年7月的時(shí)候阿里推出了一個(gè)名為Nacos的注冊中心钥组,隨即便受到廣大互聯(lián)網(wǎng)公司的強(qiáng)烈追捧,很多使用eureka的項(xiàng)目都陸續(xù)被替換成Nacos今瀑,Nacos基本完美貼合了微服務(wù)的各大生態(tài)程梦,不僅可以做注冊中心,也可以做配置中心橘荠,同時(shí)管理界面符合國人審美屿附,而且同時(shí)支持AP(高可用)和CP(強(qiáng)一致)模式,社區(qū)活躍哥童,經(jīng)歷過雙十一等大風(fēng)大浪的洗禮挺份,如今已被Spring收錄為官方組件。下面就讓我們一起來領(lǐng)略一下微服務(wù)靈魂擺渡者:Nacos贮懈。
Nacos集群搭建
Nacos可以選擇單點(diǎn)或者集群部署匀泊,在生產(chǎn)環(huán)境中為了避免單點(diǎn)故障需要采用集群部署的方式优训。
準(zhǔn)備工作
本文我們選擇使用集群部署,結(jié)構(gòu)圖如下各聘,使用Nginx做負(fù)載均衡揣非,Mysql做數(shù)據(jù)存儲:
三個(gè) nacos 節(jié)點(diǎn)地址如下,正常應(yīng)該使用三個(gè)不同的服務(wù)器躲因,本文為了方便演示則使用本地電腦分配不同端口來進(jìn)行模擬:
nacos1:
ip:192.168.31.122
port: 8845
nacos2:
ip:192.168.31.122
port: 8846
nacos3:
ip:192.168.31.122
port: 8847
初始化數(shù)據(jù)庫
Nacos默認(rèn)數(shù)據(jù)存儲在內(nèi)嵌數(shù)據(jù)庫Derby中早敬,不屬于生產(chǎn)可用的數(shù)據(jù)庫。官方推薦的最佳實(shí)踐是使用帶有主從的高可用數(shù)據(jù)庫集群大脉,這里我們以單點(diǎn)的數(shù)據(jù)庫為例來講解搞监,首先新建一個(gè)數(shù)據(jù)庫,命名為nacos箱靴,然后執(zhí)行下面的SQL:
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 CURRENT_TIMESTAMP COMMENT '創(chuàng)建時(shí)間',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改時(shí)間',
`src_user` text COMMENT 'source user',
`src_ip` varchar(50) 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';
/******************************************/
/* 數(shù)據(jù)庫全名 = 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 '內(nèi)容',
`gmt_modified` datetime NOT NULL COMMENT '修改時(shí)間',
`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='增加租戶字段';
/******************************************/
/* 數(shù)據(jù)庫全名 = 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 CURRENT_TIMESTAMP COMMENT '創(chuàng)建時(shí)間',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改時(shí)間',
`src_user` text COMMENT 'source user',
`src_ip` varchar(50) 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';
/******************************************/
/* 數(shù)據(jù)庫全名 = 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 CURRENT_TIMESTAMP COMMENT '創(chuàng)建時(shí)間',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改時(shí)間',
`src_user` text COMMENT 'source user',
`src_ip` varchar(50) 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';
/******************************************/
/* 數(shù)據(jù)庫全名 = 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';
/******************************************/
/* 數(shù)據(jù)庫全名 = 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,空字符表示整個(gè)集群',
`quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配額荷愕,0表示使用默認(rèn)值',
`usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',
`max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '單個(gè)配置大小上限衡怀,單位為字節(jié),0表示使用默認(rèn)值',
`max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大個(gè)數(shù)安疗,某残,0表示使用默認(rèn)值',
`max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '單個(gè)聚合數(shù)據(jù)的子配置大小上限学搜,單位為字節(jié),0表示使用默認(rèn)值',
`max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大變更歷史數(shù)量',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時(shí)間',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改時(shí)間',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_group_id` (`group_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='集群、各Group容量信息表';
/******************************************/
/* 數(shù)據(jù)庫全名 = 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 CURRENT_TIMESTAMP,
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`src_user` text,
`src_ip` varchar(50) 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='多租戶改造';
/******************************************/
/* 數(shù)據(jù)庫全名 = 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表示使用默認(rèn)值',
`usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',
`max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '單個(gè)配置大小上限,單位為字節(jié)姐直,0表示使用默認(rèn)值',
`max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大個(gè)數(shù)',
`max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '單個(gè)聚合數(shù)據(jù)的子配置大小上限岳锁,單位為字節(jié),0表示使用默認(rèn)值',
`max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大變更歷史數(shù)量',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時(shí)間',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改時(shí)間',
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 '創(chuàng)建時(shí)間',
`gmt_modified` bigint(20) NOT NULL COMMENT '修改時(shí)間',
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,
UNIQUE INDEX `idx_user_role` (`username` ASC, `role` ASC) USING BTREE
);
CREATE TABLE `permissions` (
`role` varchar(50) NOT NULL,
`resource` varchar(255) NOT NULL,
`action` varchar(8) NOT NULL,
UNIQUE INDEX `uk_role_permission` (`role`,`resource`,`action`) USING BTREE
);
INSERT INTO users (username, password, enabled) VALUES ('nacos', '$2a$10$EuWPZHzz32dJN7jexM34MOeYirDdFAZm2kuWj7VEOJhhZkDrxfvUu', TRUE);
INSERT INTO roles (username, role) VALUES ('nacos', 'ROLE_ADMIN');
下載nacos
nacos在GitHub上有下載地址:https://github.com/alibaba/nacos/releases吊输。
本例采用2.0.3版本(如果有跟著做的小伙伴最好使用同一個(gè)版本饶号,版本不同可能會有問題):
nacos配置
本文我們以windows系統(tǒng)為例,linux操作方式是一模一樣的季蚂,將下載的壓縮包解壓到任意非中文目錄下:
目錄說明:
- bin:啟動(dòng)腳本
- conf:配置文件
進(jìn)入 nacos 的 conf 目錄茫船,修改配置文件 cluster.conf.example,重命名為 cluster.conf扭屁,刪除原有內(nèi)容算谈,添加三個(gè)節(jié)點(diǎn)的 ip 和端口配置(注意ip填寫電腦的真實(shí) ip 地址,因?yàn)閚acos啟動(dòng)的時(shí)候會獲取本機(jī) ip 判斷是否已經(jīng)成為集群節(jié)點(diǎn)料滥,如果不是然眼,會再次進(jìn)行注冊,而獲取的本機(jī) ip 是真實(shí)的 ip 地址葵腹,從而導(dǎo)致產(chǎn)生錯(cuò)誤):
192.168.31.122:8845
192.168.31.122:8855
192.168.31.122:8865
注意:端口不要寫連續(xù)的端口罪治,會出現(xiàn)端口占用問題丽声,一個(gè) nacos 服務(wù)默認(rèn)需要以下 4 個(gè)端口:
server.port(默認(rèn)8848)
raft port: ${server.port} - 1000
grpc port: ${server.port} + 1000
# 如果端口連續(xù),會出現(xiàn)此服務(wù)端口占用觉义,導(dǎo)致服務(wù)啟動(dòng)失敗
grpc port for server: ${server.port} + 1001
然后修改 application.properties 文件雁社,最前面找到 “If use MySQL as datasource” ,下面添加數(shù)據(jù)庫配置:
spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
#此處寫自己數(shù)據(jù)的用戶名
db.user.0=root
#此處寫自己數(shù)據(jù)的密碼
db.password.0=root
然后找到 nacos.inetutils.ip-address 配置項(xiàng)(此處如果不配置nacos可能會獲取不到正確的ip晒骇,影響選舉集群 leader 導(dǎo)致不可用):
# 填寫自己電腦的ip
nacos.inetutils.ip-address=192.168.31.122
啟動(dòng)nacos集群
因?yàn)槲覀円渴鹑齻€(gè)節(jié)點(diǎn)霉撵,所以將解壓后 nacos 文件夾復(fù)制三份,分別命名為:nacos1洪囤、nacos2徒坡、nacos3:
然后分別修改三個(gè)文件夾中的 application.properties
nacos1:
server.port=8845
nacos2:
server.port=8855
nacos3:
server.port=8865
最后分別啟動(dòng)三個(gè)nacos節(jié)點(diǎn),依次執(zhí)行bin文件夾下的 startup.cmd 即可瘤缩,(nacos依賴于jdk啟動(dòng)喇完,需要配置jdk的環(huán)境變量才可正常啟動(dòng))三個(gè)窗口均出現(xiàn)下圖中的提示則代表集群啟動(dòng)成功!
nginx反向代理
我們已經(jīng)成功啟動(dòng)了 nacos 集群剥啤,在這里我們選擇使用 nginx 來對 nacos 進(jìn)行反向代理锦溪,實(shí)現(xiàn)負(fù)載均衡,首先去nginx官網(wǎng) http://nginx.org/en/download.html 下載 nginx 安裝包府怯,解壓至任意非中文目錄下:
修改conf/nginx.conf文件刻诊,在 http 節(jié)點(diǎn)下添加以下配置:
# 反向代理三個(gè)nacos節(jié)點(diǎn)
upstream nacos-cluster {
server 127.0.0.1:8845;
server 127.0.0.1:8855;
server 127.0.0.1:8865;
}
# 監(jiān)聽8848端口
server {
listen 8848;
server_name localhost;
location /nacos {
proxy_pass http://nacos-cluster;
}
}
啟動(dòng) nginx,window下雙擊nginx.exe即可牺丙,相信大家對 nginx 再熟悉不過了则涯,不多贅述,一閃而過冲簿,啟動(dòng)成功粟判。
然后在瀏覽器訪問 http://127.0.0.1:8848/nacos:
用戶名和密碼都是 nacos,對應(yīng)之前創(chuàng)建的 users 表中插入的數(shù)據(jù)峦剔,插入到數(shù)據(jù)庫中的密碼是加密的浮入,登錄,查看一下集群管理菜單下的節(jié)點(diǎn)列表:
展開節(jié)點(diǎn)元數(shù)據(jù)羊异,發(fā)現(xiàn) leader 已經(jīng)選舉成功了:
到這里事秀,nacos 集群就算部署成功了,nacos 和 eurka野舶,nacos集群中的所有節(jié)點(diǎn)會選舉出一個(gè) leader 來執(zhí)行更新易迹,同步等操作,保證數(shù)據(jù)的一致性平道,而 eurka 所有的節(jié)點(diǎn)都是平等的睹欲,一致性相對較弱。
nacos 的集群選舉算法采用的是 raft 算法,每個(gè)節(jié)點(diǎn)都有一個(gè)隨機(jī)的時(shí)間計(jì)數(shù)器窘疮,倒計(jì)時(shí)結(jié)束后會推選自己作為 leader袋哼,如果半數(shù)以上的節(jié)點(diǎn)投票通過,則上位成功闸衫,然后持續(xù)發(fā)送心跳給其他節(jié)點(diǎn)維持自己的 leader 身份涛贯,如果心跳停止,其他節(jié)點(diǎn)會重新選舉 leader蔚出,推選出新 leader 之后 老 leader 恢復(fù)會自動(dòng)降級為follower弟翘。
只有大于半數(shù)的投票才能成為 leader 主要是為了防止 腦裂 現(xiàn)象,在這里就不深入探討了骄酗,感興趣的朋友可以自行查閱稀余。
如果部署完之后節(jié)點(diǎn)元數(shù)據(jù)里沒有 leader 信息,會導(dǎo)致 nacos 集群的很多功能不可用趋翻,可以去 log 文件夾底下的 nacos.log 查看具體報(bào)錯(cuò)解決(如果是按照本文步驟操作睛琳,一般不會出現(xiàn)報(bào)錯(cuò))。
向Nacos注冊服務(wù)
下面我們來測試一下向 nacos 注冊服務(wù)實(shí)例踏烙。
創(chuàng)建srpingCloud微服務(wù)項(xiàng)目
利用idea創(chuàng)建一個(gè) SpringCloud 項(xiàng)目师骗,先創(chuàng)建 pom 父工程:
pom.xml 引入相關(guān)依賴:
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cloud.demo</groupId>
<artifactId>cloud-demo</artifactId>
<version>1.0</version>
<packaging>pom</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.RELEASE</spring-cloud.version>
<mysql.version>5.1.47</mysql.version>
<mybatis.version>2.1.1</mybatis.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- springCloud -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--alibaba的管理依賴-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.5.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
創(chuàng)建一個(gè)子模塊 demoService:
創(chuàng)建成功,如下:
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>cloud.demo</groupId>
<artifactId>cloud-demo</artifactId>
<version>1.0</version>
</parent>
<name>demo-service</name>
<artifactId>demo-service</artifactId>
<description>demo-service</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- nacos客戶端依賴包 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
配置 application.yml:
spring:
cloud:
nacos:
server-addr: localhost:8848
application:
name: demoService
server:
port: 8080
啟動(dòng):
控制臺提示服務(wù)已經(jīng)注冊完成宙帝,看一下 nacos 的服務(wù)管理列表丧凤,服務(wù)已經(jīng)被成功注冊進(jìn)來了:
體驗(yàn)Nacos的服務(wù)分級存儲
一個(gè)服務(wù)可以存在有多個(gè)實(shí)例募闲,例如我們的demoService步脓,可以啟動(dòng)三次,生成三個(gè)實(shí)例:
- 127.0.0.1:8080
- 127.0.0.1:8081
- 127.0.0.1:8082
假如這些實(shí)例分布于全國各地的不同機(jī)房浩螺,例如:
- 127.0.0.1:8080靴患,在天津機(jī)房
- 127.0.0.1:8081,在天津機(jī)房
- 127.0.0.1:8082要出,在北京機(jī)房
使用Nacos可以將同一機(jī)房內(nèi)的實(shí)例劃分為一個(gè)集群鸳君,也就是說,一個(gè)服務(wù)可以包含多個(gè)集群患蹂,如天津集群或颊,北京集群,每個(gè)集群下可以有多個(gè)實(shí)例传于,形成分級模型囱挑,如圖:
下面讓我們給 demoService 配置集群,然后重啟:
spring:
cloud:
nacos:
server-addr: localhost:8848
discovery:
# 集群名稱
cluster-name: TJ
application:
name: demoService
server:
port: 8080
復(fù)制 application.yml沼溜,分別改名為 application-tj.yml 和 application-bj.yml
application-tj.yml:
spring:
cloud:
nacos:
server-addr: localhost:8848
discovery:
# 集群名稱
cluster-name: TJ
application:
name: demoService
server:
port: 8081
application-bj.yml:
spring:
cloud:
nacos:
server-addr: localhost:8848
discovery:
# 集群名稱
cluster-name: BJ
application:
name: demoService
server:
port: 8082
然后復(fù)制兩個(gè)實(shí)例啟動(dòng):
啟動(dòng)完成后平挑,查看 nacos 服務(wù)列表管理界面,集群數(shù)變?yōu)?2,實(shí)例數(shù)變?yōu)?3:
點(diǎn)擊詳情查看:
到此通熄,我們便實(shí)現(xiàn)了服務(wù)的分級存儲唆涝。
正常情況,微服務(wù)互相訪問時(shí)唇辨,應(yīng)該盡可能訪問同集群實(shí)例廊酣,因?yàn)楸镜卦L問速度更快,當(dāng)本集群內(nèi)不可用時(shí)助泽,才訪問其它集群啰扛。
我們需要搭建另一個(gè)服務(wù)來訪問 demoService 體驗(yàn)同集群優(yōu)先訪問的效果,首先在 demoService 新增一個(gè)接口供外界訪問(具體代碼就不貼了)嗡贺,添加之后重啟三個(gè) demoService 服務(wù):
然后搭建 requestService 服務(wù)訪問 demoService 服務(wù)的 now 接口隐解,這里我們使用了 feign 來進(jìn)行訪問:
配置 application.yml,集群名稱配置 TJ:
spring:
cloud:
nacos:
server-addr: localhost:8848
discovery:
# 集群名稱
cluster-name: TJ
application:
name: requestService
server:
port: 8083
demoService:
ribbon:
NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule # 負(fù)載均衡規(guī)則
feign:
httpclient:
enabled: true # 支持HttpClient的開關(guān)
max-connections: 200 # 最大連接數(shù)
max-connections-per-route: 50 # 單個(gè)路徑的最大連接數(shù)
springCloud 默認(rèn)的負(fù)載均衡策略并不能實(shí)現(xiàn)根據(jù)同集群優(yōu)先來實(shí)現(xiàn)負(fù)載均衡诫睬,因此Nacos中提供了一個(gè)NacosRule 的實(shí)現(xiàn)煞茫,可以優(yōu)先從同集群中挑選實(shí)例。
修改 requestService 的application.yml文件摄凡,添加負(fù)載均衡規(guī)則(上面的 yaml 中已經(jīng)有了):
demoService:
ribbon:
NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule # 負(fù)載均衡規(guī)則
啟動(dòng)续徽,訪問 http://localhost:8083/request/now,觀察之前啟動(dòng)的三個(gè) demoService 的控制臺輸出亲澡,發(fā)現(xiàn)只有 TJ 節(jié)點(diǎn) 8080 和 8081 處理了請求:
然后關(guān)閉 8080 和 8081 服務(wù)钦扭,TJ 集群內(nèi)沒有可用服務(wù),則不得不去訪問 BJ 的服務(wù)床绪,日志如下:
如此一來客情,便實(shí)現(xiàn)了優(yōu)先訪問同一集群內(nèi)的效果,分級存儲模型的優(yōu)點(diǎn)也因此得到體現(xiàn)癞己。
Nacos權(quán)重配置
啟動(dòng)之前關(guān)閉的兩個(gè) demoService服務(wù)膀斋,接下來看一下權(quán)重配置。
實(shí)際部署中會出現(xiàn)這樣的場景:
服務(wù)器設(shè)備性能有差異痹雅,部分實(shí)例所在機(jī)器性能較好仰担,另一些較差,我們希望性能好的機(jī)器承擔(dān)更多的用戶請求绩社。
但默認(rèn)情況下NacosRule是同集群內(nèi)隨機(jī)挑選摔蓝,不會考慮機(jī)器的性能問題。因此愉耙,nacos 提供了權(quán)重配置來控制訪問頻率贮尉,權(quán)重越大則訪問頻率越高。
通過 nacos 后臺管理界面我們可以很方便的修改每個(gè)服務(wù)的權(quán)重劲阎,在服務(wù)列表點(diǎn)擊詳情绘盟,然后選擇實(shí)例即可編輯實(shí)例的權(quán)重:
注意:如果權(quán)重修改為0,則該實(shí)例永遠(yuǎn)不會被訪問。
在實(shí)際運(yùn)用中龄毡,如果服務(wù)有更新吠卷,可以先部署新服務(wù),權(quán)重設(shè)置小一些沦零,觀察情況祭隔,如果一切正常,可以把權(quán)重設(shè)置高一些路操,這樣大部分流量便會打到新服務(wù)節(jié)點(diǎn)疾渴,隨后逐漸下線老服務(wù)即可,實(shí)現(xiàn)服務(wù)的灰度發(fā)布(用戶無感知)屯仗。
Nacos環(huán)境隔離
Nacos提供了namespace來實(shí)現(xiàn)環(huán)境隔離功能搞坝。
- nacos中可以有多個(gè)namespace
- namespace下可以有g(shù)roup、service等
-
不同namespace之間相互隔離魁袜,例如不同namespace的服務(wù)互相不可見:
環(huán)境隔離
默認(rèn)情況下桩撮,所有service、data峰弹、group都在同一個(gè)namespace店量,名為public:
public
下面我們自己添加一個(gè) namespece:
添加namespace
添加完畢
接下來我們給 requestService 配置 namespace,修改 application.yml:
spring:
cloud:
nacos:
server-addr: localhost:8848
discovery:
# 集群名稱
cluster-name: TJ
# 控制臺命名空間的id
namespace: a58f82bf-ab3d-4051-8134-25ba052ec373
application:
name: requestService
server:
port: 8083
demoService:
ribbon:
NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule # 負(fù)載均衡規(guī)則
feign:
httpclient:
enabled: true # 支持HttpClient的開關(guān)
max-connections: 200 # 最大連接數(shù)
max-connections-per-route: 50 # 單個(gè)路徑的最大連接數(shù)
重啟鞠呈,可以看到管理界面已經(jīng)出現(xiàn)了我們配置的 namespace:
再次訪問 http://localhost:8083/request/now融师,日志報(bào)錯(cuò):
至此,我們成功實(shí)現(xiàn)了 nacos 的環(huán)境隔離效果蚁吝。
Nacos配置管理
Nacos除了可以做注冊中心旱爆,還可以做配置中心來使用。
當(dāng)微服務(wù)部署的實(shí)例越來越多灭将,達(dá)到數(shù)十疼鸟、數(shù)百時(shí)后控,逐個(gè)修改微服務(wù)配置就會讓人抓狂庙曙,而且很容易出錯(cuò)。我們需要一種統(tǒng)一配置管理方案浩淘,可以集中管理所有實(shí)例的配置捌朴。
Nacos一方面可以將配置集中管理,另一方可以在配置變更時(shí)张抄,及時(shí)通知微服務(wù)砂蔽,實(shí)現(xiàn)配置的熱更新。
在nacos中添加配置文件
下面我們再 nacos 管理后臺新增配置文件署惯。
點(diǎn)擊配置列表左驾,點(diǎn)擊新增:
然后在彈出的表單中,填寫配置信息,填寫完畢诡右,點(diǎn)擊發(fā)布:
發(fā)布成功:
注意:項(xiàng)目的核心配置安岂,需要熱更新的配置才有放到nacos管理的必要》牵基本不會變更的一些配置還是保存在微服務(wù)本地比較好域那。
從微服務(wù)拉取配置
微服務(wù)要拉取nacos中管理的配置,并且與本地的application.yml配置合并猜煮,才能完成項(xiàng)目啟動(dòng)次员。
但如果尚未讀取application.yml,又如何得知nacos地址呢王带?
因此spring引入了一種新的配置文件:bootstrap.yaml文件淑蔚,會在application.yml之前被讀取,流程如下:
首先愕撰,在 demoService 服務(wù)中束倍,引入 nacos-config 的客戶端依賴:
<!--nacos配置管理依賴-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
然后,在 demoService 中添加一個(gè) bootstrap.yml 文件盟戏,內(nèi)容如下:
spring:
application:
name: demoService # 服務(wù)名稱
profiles:
active: dev #開發(fā)環(huán)境绪妹,這里是dev
cloud:
nacos:
server-addr: localhost:8848 # Nacos地址
config:
file-extension: yaml # 文件后綴名
這里 demoService 服務(wù)會根據(jù) spring.cloud.nacos.server-addr
獲取nacos地址,再根據(jù)
${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
作為文件id柿究,來讀取配置邮旷。
本例中,就是去讀取demoService-dev.yaml
蝇摸。
配置熱更新
我們最終的目的婶肩,是修改nacos中的配置后,微服務(wù)中無需重啟即可讓配置生效貌夕,也就是配置熱更新律歼。
有兩種方式可以實(shí)現(xiàn):
方式一:
在@Value
注入的變量所在類上添加注解@RefreshScope
:
@Slf4j
@RestController
@RequestMapping("/demo")
@RefreshScope
public class DemoController {
@Value("${pattern.dateformat}")
private String dateformat;
@GetMapping("/now")
public String now(){
log.info("收到,over");
return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateformat));
}
}
方式二:
使用@ConfigurationProperties
注解代替@Value
注解啡专。
在demoService
服務(wù)中险毁,添加一個(gè)類,讀取patterrn.dateformat
屬性:
@Component
@Data
@ConfigurationProperties(prefix = "pattern")
public class PatternProperties {
private String dateformat;
}
使用這個(gè)類代替@Value
:
@Slf4j
@RestController
@RequestMapping("/demo")
public class DemoController {
@Autowired
private PatternProperties patternProperties;
@GetMapping("/now")
public String now(){
log.info("收到们童,over");
return LocalDateTime.now().format(DateTimeFormatter.ofPattern(patternProperties.getDateformat()));
}
}
同學(xué)們自行測試即可畔况。
配置共享
微服務(wù)啟動(dòng)時(shí),會去 nacos 讀取多個(gè)配置文件慧库,例如:
-
[spring.application.name]-[spring.profiles.active].yaml
跷跪,例如:demoService-dev.yaml -
[spring.application.name].yaml
,例如:userservice.yaml
而[spring.application.name].yaml
不包含環(huán)境齐板,因此可以被多個(gè)環(huán)境共享吵瞻,同上一節(jié)講到的內(nèi)容葛菇,大家可以在配置管理界面新增配置 userservice.yaml
,進(jìn)行配置共享的測試。
配置共享的優(yōu)先級
當(dāng)nacos橡羞、服務(wù)本地同時(shí)出現(xiàn)相同屬性時(shí)熟呛,優(yōu)先級有高低之分,如下圖:
Nacos實(shí)例類型
Nacos的服務(wù)實(shí)例分為兩種類型:
- 臨時(shí)實(shí)例:如果實(shí)例宕機(jī)超過一定時(shí)間尉姨,會從服務(wù)列表剔除庵朝,默認(rèn)的類型。
- 非臨時(shí)實(shí)例:如果實(shí)例宕機(jī)又厉,不會從服務(wù)列表剔除九府,也可以叫永久實(shí)例。
配置一個(gè)服務(wù)實(shí)例為永久實(shí)例:
spring:
cloud:
nacos:
discovery:
ephemeral: true# 設(shè)置為永久實(shí)例
Nacos與Eureka的區(qū)別
-
Nacos與eureka的共同點(diǎn):
- 都支持服務(wù)注冊和服務(wù)拉取
- 都支持服務(wù)提供者心跳方式做健康檢測
-
Nacos與Eureka的區(qū)別:
- Nacos支持服務(wù)端主動(dòng)檢測實(shí)例狀態(tài):臨時(shí)實(shí)例采用心跳模式覆致,非臨時(shí)實(shí)例采用主動(dòng)檢測模式
- 臨時(shí)實(shí)例心跳不正常會被剔除侄旬,非臨時(shí)實(shí)例則不會被剔除
- Nacos支持服務(wù)列表變更的消息推送模式,服務(wù)列表更新更及時(shí)
- Nacos集群默認(rèn)采用AP方式煌妈,當(dāng)集群中存在非臨時(shí)實(shí)例時(shí)儡羔,采用CP模式;Eureka采用AP方式
綜上璧诵,nacos更香汰蜘!
結(jié)語
關(guān)于 nacos 的介紹到這里就結(jié)束了,現(xiàn)在 nacos 在微服務(wù)項(xiàng)目中有著十分廣泛的應(yīng)用之宿,我們需要去理解和掌握族操,nacos 選舉 leader 采用的 raft 算法同學(xué)們可以自行查閱資料了解一下,這也屬于高頻面試點(diǎn)比被,本文主要是講了 nacos 的應(yīng)用色难,關(guān)于它的思想和原理還是需要大家在使用的過程中逐漸體會!
紙上學(xué)來終覺淺等缀,絕知此事要躬行枷莉,在此與諸君共勉!
關(guān)注公眾號 螺旋編程極客
發(fā)送 微服務(wù)
可以獲取本文的源碼
以及微服務(wù)大禮包哦
!