SpringCloud Alibaba:理論+實(shí)踐通關(guān)微服務(wù)靈魂擺渡者—Nacos

引言

我們都知道微服務(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ù)存儲:


集群結(jié)構(gòu)圖

三個(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操作方式是一模一樣的季蚂,將下載的壓縮包解壓到任意非中文目錄下:


nacos目錄

目錄說明:

  • 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:


復(fù)制三份

然后分別修改三個(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)成功!

nacos啟動(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 安裝包府怯,解壓至任意非中文目錄下:

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

用戶名和密碼都是 nacos,對應(yīng)之前創(chuàng)建的 users 表中插入的數(shù)據(jù)峦剔,插入到數(shù)據(jù)庫中的密碼是加密的浮入,登錄,查看一下集群管理菜單下的節(jié)點(diǎn)列表:
集群列表

展開節(jié)點(diǎn)元數(shù)據(jù)羊异,發(fā)現(xiàn) leader 已經(jīng)選舉成功了:
leader選舉成功

到這里事秀,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父工程

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):


啟動(dòng)

控制臺提示服務(wù)已經(jīng)注冊完成宙帝,看一下 nacos 的服務(wù)管理列表丧凤,服務(wù)已經(jīng)被成功注冊進(jìn)來了:


服務(wù)注冊成功

體驗(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):


copy

配置

啟動(dòng)完成后平挑,查看 nacos 服務(wù)列表管理界面,集群數(shù)變?yōu)?2,實(shí)例數(shù)變?yōu)?3:


集群和實(shí)例

點(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)行訪問:


項(xiàng)目結(jié)構(gòu)

配置 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 處理了請求:

8080

8081

8082

然后關(guān)閉 8080 和 8081 服務(wù)钦扭,TJ 集群內(nèi)沒有可用服務(wù),則不得不去訪問 BJ 的服務(wù)床绪,日志如下:
跨集群訪問發(fā)生

如此一來客情,便實(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)重配置

注意:如果權(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:

demo

再次訪問 http://localhost:8083/request/now融师,日志報(bào)錯(cuò):
日志報(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)擊新增:


1

然后在彈出的表單中,填寫配置信息,填寫完畢诡右,點(diǎn)擊發(fā)布:


新增配置

發(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)先級有高低之分,如下圖:


配置優(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ù)大禮包哦!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末尺迂,一起剝皮案震驚了整個(gè)濱河市笤妙,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌枪狂,老刑警劉巖危喉,帶你破解...
    沈念sama閱讀 222,729評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件宋渔,死亡現(xiàn)場離奇詭異州疾,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)皇拣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評論 3 399
  • 文/潘曉璐 我一進(jìn)店門严蓖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來薄嫡,“玉大人,你說我怎么就攤上這事颗胡『辽睿” “怎么了?”我有些...
    開封第一講書人閱讀 169,461評論 0 362
  • 文/不壞的土叔 我叫張陵毒姨,是天一觀的道長哑蔫。 經(jīng)常有香客問我,道長弧呐,這世上最難降的妖魔是什么闸迷? 我笑而不...
    開封第一講書人閱讀 60,135評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮俘枫,結(jié)果婚禮上腥沽,老公的妹妹穿的比我還像新娘。我一直安慰自己鸠蚪,他們只是感情好今阳,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,130評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著茅信,像睡著了一般盾舌。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蘸鲸,一...
    開封第一講書人閱讀 52,736評論 1 312
  • 那天矿筝,我揣著相機(jī)與錄音,去河邊找鬼棚贾。 笑死窖维,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的妙痹。 我是一名探鬼主播铸史,決...
    沈念sama閱讀 41,179評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼怯伊!你這毒婦竟也來了琳轿?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,124評論 0 277
  • 序言:老撾萬榮一對情侶失蹤耿芹,失蹤者是張志新(化名)和其女友劉穎崭篡,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體吧秕,經(jīng)...
    沈念sama閱讀 46,657評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡琉闪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,723評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了砸彬。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片颠毙。...
    茶點(diǎn)故事閱讀 40,872評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡斯入,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蛀蜜,到底是詐尸還是另有隱情刻两,我是刑警寧澤,帶...
    沈念sama閱讀 36,533評論 5 351
  • 正文 年R本政府宣布滴某,位于F島的核電站磅摹,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏霎奢。R本人自食惡果不足惜偏瓤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,213評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望椰憋。 院中可真熱鬧厅克,春花似錦、人聲如沸橙依。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽窗骑。三九已至女责,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間创译,已是汗流浹背抵知。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留软族,地道東北人刷喜。 一個(gè)月前我還...
    沈念sama閱讀 49,304評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像立砸,于是被迫代替她去往敵國和親掖疮。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,876評論 2 361

推薦閱讀更多精彩內(nèi)容