Alibaba微服务组件Nacos单机+集群配置 & prometheus+grafana监控配置及注册中心实战【收获满满】

一、什么是 Nacos

官方文档: https://nacos.io/zh-cn/docs/what-is-nacos.html

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

Nacos的关键特性包括:

  • 服务发现和服务健康监测
  • 动态配置服务
  • 动态 DNS 服务
  • 服务及其元数据管理

主流的注册中心对比:
在这里插入图片描述

1.1 Nacos 架构

在这里插入图片描述
NamingService: 命名服务,注册中心核心接口
ConfigService:配置服务,配置中心核心接口


OpenAPI文档https://nacos.io/zh-cn/docs/open-api.html
nacos版本: v1.1.4 升级到v1.4.1

1.2 Nacos Server部署

你可以通过源码和发行包两种方式来获取 Nacos。

下载源码编译:
源码下载地址:https://github.com/alibaba/nacos/ | 可以用迅雷下载

cd nacos/
mvn -Prelease-nacos clean install -U

下载安装包:
下载地址:https://github.com/alibaba/Nacos/releases

当前推荐的稳定版本是2.0.3。
在这里插入图片描述
在这里插入图片描述
这次学习,我们暂时使用v1.4.1版本…

下载好nacos-server-1.4.1.tar.gz之后,我们将其上传到linux服务器上。
在这里插入图片描述

1.2.1 单机模式

官方文档: https://nacos.io/zh-cn/docs/deployment.html

解压:

tar -axvf nacos-server-1.4.1.tar.gz

然后进入nacos目录:
在这里插入图片描述
单机启动nacos,执行命令

sh ./bin/startup.sh -m standalone

在这里插入图片描述
查看服务是否启动

ps -ef | grep nacos

在这里插入图片描述

在nacos的启动脚本startup.sh中可以看到,默认的启动方式为集群方式。
在这里插入图片描述
我们可以修改默认启动方式:
在这里插入图片描述
访问nocas的管理端:http://192.168.131.172:8848/nacos ,默认的用户名密码是 nocas/nocas 。
在这里插入图片描述
在这里插入图片描述
成功启动!成功访问!很棒!!!

1.2.2 集群模式

官网文档: https://nacos.io/zh-cn/docs/cluster-mode-quick-start.html

集群部署架构图:
在这里插入图片描述
1、单机搭建伪集群,复制nacos安装包,修改为nacos8849,nacos8850,nacos8851
在这里插入图片描述
2、创建mysql数据库,sql文件位置:conf\nacos-mysql.sql

注意,nacos1.4.1版本搭配mysql5.x版本的时候,启动总是报错说数据库连接错误!后来换成mysql8.x之后成功解决这个错误!!!

注意: 使用内置数据源时,无需进行任何配置。使用外置数据源,生产使用建议至少主备模式,或者采用高可用数据库。

我们此时是要使用外部数据源,所以要配置。我们创建一个名为nacos的数据库,并执行一下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 CURRENT_TIMESTAMP COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
  `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';

/******************************************/
/*   数据库全名 = 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 CURRENT_TIMESTAMP COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
  `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';

/******************************************/
/*   数据库全名 = 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 '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
  `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';

/******************************************/
/*   数据库全名 = 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 CURRENT_TIMESTAMP COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP 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 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='多租户改造';


/******************************************/
/*   数据库全名 = 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 CURRENT_TIMESTAMP COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP 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,
	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数据库并执行以上sql脚本得到结果如下:
在这里插入图片描述

3、以nacos8849为例,进入nacos8849目录

3.1)修改conf\application.properties的配置,使用外置数据源

#修改端口号
server.port=8849

#使用外置mysql数据源 
spring.datasource.platform=mysql 

### Count of DB:
db.num=1

### Connect URL of DB:
db.url.0=jdbc:mysql://192.168.131.172:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=123456

注意填写正确的数据库连接用户名和密码。我的密码是123456。
在这里插入图片描述

3.2)将conf\cluster.conf.example文件copy一份改为cluster.conf,并添加节点配置。请每行配置成ip:port。(请配置3个或3个以上节点)

cp ./cluster.conf.example ./cluster.conf

vim cluster.conf
# 192.168.131.172:8849 注意,本服务的IP:端口不用自己配置,启动的时候刽自动生成,只需要配置其他集群节点的信息!
192.168.131.172:8850
192.168.131.172:8851

nacos8850,nacos8851 按同样的方式配置(端口分别改为8850,8851)。

4、修改启动脚本(bin\startup.sh)的jvm参数(nacos8850,nacos8851 按同样的方式配置JVM参数)
在这里插入图片描述
注意,我们此时是集群模式,应该修改else分支下的JVM参数!!!

5、别启动nacos8849,nacos8850,nacos8851

使用内置数据源
sh startup.sh -p embedded

使用外置数据源
sh startup.sh

以nacos8849为例,进入nacos8849目录,启动nacos

bin/startup.sh

然后分别启动nacos8850,nacos8851服务。

然后我们再来访问http://192.168.131.172:8849/nacos,登录后查看集群信息:
在这里插入图片描述
可以看到,集群已经成功启动!!!

注意,nacos默认启动方式就是集群模式!

1.2.2.1 nginx反向代理配置

修改/conf/nginx.conf配置文件,添加反向代理配置:

upstream nacoscluster {
        server 192.168.131.172:8849;
        server 192.168.131.172:8850;
        server 192.168.131.172:8851; 
}

server {
    listen        8847;
    server_name   192.168.131.172;

    location /nacos/ {
        proxy_pass http://nacoscluster/nacos/;
    }
}

访问: http://192.168.131.172:8847/nacos
在这里插入图片描述
在这里插入图片描述
即,此时我们客户端要使用nacos集群服务的时候,只需要配置这个nginx代理的地值http://192.168.131.172:8847地址即可,并且nginx端已经帮我们处理好了负载均衡,默认为轮训算法,可以配置权重,一致hash等其他算法。

server:
  port: 8045

spring:
  application:
    name: mall-order

# 配置nacos注册中心地址
cloud:
  nacos:
    discovery:
      server-addr: 192.168.131.172:8847

在这里插入图片描述

1.2.2.2 nacos+nginx启动总结

1、启动nginx(记得nginx中配置好nacos反向代理)

# 默认编译的nginx路径为这个,也可以使用whereid nginx 查看地址
/usr/local/nginx/sbin/nginx

2、分别启动nacos8849,nacos8850,nacos8851服务

# 分别在集群服务的bin目录下启动
sh startup.sh

在这里插入图片描述
3、使用nginx中配置的nacos地址在浏览器中访问测试集群是否成功:

http://192.168.131.172:8847/nacos
在这里插入图片描述

1.3 prometheus+grafana监控Nacos

官方监控文档地址:https://nacos.io/zh-cn/docs/monitor-guide.html

Nacos 0.8.0版本完善了监控系统,支持通过暴露metrics数据接入第三方监控系统监控Nacos运行状态,目前支持prometheus、elastic search和influxdb,下面结合prometheus和grafana如何监控Nacos,官网grafana监控页面。与elastic search和influxdb结合可自己查找相关资料。

下面我们开始配置。(为了简单测试,这里我们暂时使用nacos单机模式实战吧… 妥协了)

1.3.1 配置application.properties文件,暴露metrics数据

management.endpoints.web.exposure.include=*

注:上面的这个配置原来是注释掉的,现在去掉注释,放开。(集群中每个都要修改)

在这里插入图片描述
访问{ip}:8848/nacos/actuator/prometheus,看是否能访问到metrics数据。
在这里插入图片描述

1.3.2 搭建prometheus采集Nacos metrics数据

下载你想安装的prometheus版本,地址为: https://prometheus.io/download/

我们使用linux Centos7,所以下载linux版本:
在这里插入图片描述
上传后解压prometheus压缩包:

tar -zxvf prometheus-2.31.1.linux-amd64.tar.gz 

在这里插入图片描述

修改配置文件prometheus.yml采集Nacos metrics数据:

添加如下配置:

- job_name: "nacos"
    metrics_path: '/nacos/actuator/prometheus'
    static_configs:
      # 这里配置nacos服务地址,可以看到这里可以配置一个集合,即集群信息可以配置在这里 
      # - targets: ['192.168.131.172:8849','192.168.131.172:8850','192.168.131.172:8851'] 	
      # 如果是单机模式,集合中只配置一个元素即可
      - targets: ['192.168.131.172:8848']

在这里插入图片描述

注意yml中空格不要多写,格式一定要严格对齐!否则启动可能会报错说配置文件出错!

启动prometheus服务:

./prometheus --config.file="prometheus.yml"

在这里插入图片描述

通过访问http://{ip}:9090/graph可以看到prometheus的采集数据,在搜索栏搜索nacos_monitor可以搜索到Nacos数据说明采集数据成功。
在这里插入图片描述
查看nacos(集群)状态:
在这里插入图片描述
在这里插入图片描述
配制采集nacos metrics数据:
如下图,进入Graph这个tab后,输入nacos,选中nacos_monitor :
在这里插入图片描述
点"Execute",有数据显示,就说明采集到数据成功:
在这里插入图片描述
在这里插入图片描述
可以看到,此时数据已经采集成功。但是这样可能显示还不是很直观,接下来我们再集成grafana来展示数据。

1.4 搭建grafana图形化展示metrics数据

和prometheus在同一台机器上安装grafana,使用 yum 安装grafana。

下载grafana
本地下载地址:https://dl.grafana.com/oss/release/grafana-7.3.4.linux-amd64.tar.gz

linux推荐使用yum安装:

sudo yum install https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.2.4-1.x86_64.rpm

如果下载太慢,使用国内镜像:https://www.newbe.pro/Mirrors/Mirrors-Grafana/
在这里插入图片描述
注意要下载第五个,这个大小为51.8M的,其他的无法使用…
在这里插入图片描述
下载后解压:

ar -zxvf grafana-5.2.4.linux-amd64.tar.gz

在这里插入图片描述
进入查看结构,有bin目录证明是正确的。
在这里插入图片描述

启动服务:

# 直接启动并在直接输入日志
./bin/grafana-server

在这里插入图片描述
也可以静默启动,将日志输入到指定的文件中:

nohup ./bin/grafana-server >> nuhup.log 2>&1 &

在这里插入图片描述

访问grafana: http://{ip}:3000:
在这里插入图片描述
可以到此页面说明启动成功!默认用户名和密码都是admin。登录之后可以会要求修改密码,可以选择skip跳过:在这里插入图片描述
然后会进入主页面:
在这里插入图片描述

配置prometheus数据源:
在这里插入图片描述
点"Add data source":
在这里插入图片描述
Name:prometheus
类型选择Prometheus:
在这里插入图片描述
URL填写prometheus的地址(注意:http要写上,最后地址后的’/'也最好加上,即完整地址为:http://192.168.131.172:9090/),http method选择get方法,其他不用填写,然后点"Save & Test":
在这里插入图片描述
接下来我们需要引入nacos监控展示模板:
在这里插入图片描述
github模板下载链接:https://github.com/nacos-group/nacos-template/blob/master/nacos-grafana.json

如果网速慢,可以使用gitee,gitee模板下载连接:https://gitee.com/jakhyd/nacos-template

点“Upload JSON file”上传模板文件,然后点"Load"
在这里插入图片描述
在这里插入图片描述
然后再点击"import"按钮:
在这里插入图片描述
然后就可以看到监控数据了:
在这里插入图片描述
Nacos监控分为三个模块:

  • nacos monitor展示核心监控项
    在这里插入图片描述

  • nacos detail展示指标的变化曲线
    在这里插入图片描述

  • nacos alert为告警项
    在这里插入图片描述

配置grafana告警:

当Nacos运行出现问题时,需要grafana告警通知相关负责人。grafana支持多种告警方式,常用的有邮件,钉钉和webhook方式

具体配置连接:https://nacos.io/zh-cn/docs/monitor-guide.html

二、.Nacos注册中心实战

2.1 注册中心演变及其设计思想

在这里插入图片描述

2.2 Nacos注册中心架构

在这里插入图片描述

2.3 核心功能

服务注册:Nacos Client会通过发送REST请求的方式向Nacos Server注册自己的服务,提供自身的元数据,比如ip地址、端口等信息。Nacos Server接收到注册请求后,就会把这些元数据信息存储在一个双层的内存Map中。

服务心跳:在服务注册后,Nacos Client会维护一个定时心跳来持续通知Nacos Server,说明服务一直处于可用状态,防止被剔除。默认5s发送一次心跳。

服务同步:Nacos Server集群之间会互相同步服务实例,用来保证服务信息的一致性。 leader raft

服务发现:服务消费者(Nacos Client)在调用服务提供者的服务时,会发送一个REST请求给Nacos Server,获取上面注册的服务清单,并且缓存在Nacos Client本地,同时会在Nacos Client本地开启一个定时任务定时拉取服务端最新的注册表信息更新到本地缓存。

服务健康检查:Nacos Server会开启一个定时任务用来检查注册服务实例的健康情况,对于超过15s没有收到客户端心跳的实例会将它的healthy属性置为false(客户端服务发现时不会发现),如果某个实例超过30秒没有收到心跳,直接剔除该实例(被剔除的实例如果恢复发送心跳则会重新注册) 。

2.4 服务注册表结构

在这里插入图片描述
官方图:
在这里插入图片描述

nacos可以以namespace来隔离服务,我们可以为不同的环境创建不同的命名空间。注意,不同命名空间中的服务是无法相互调用的。
在这里插入图片描述
再往下划分,还有group::serviceName、ClusterName等划分。

#配置nacos注册中心地址
cloud:
  nacos:
    discovery:
      server-addr: 192.168.131.172:8848
      namespace: 39e1e969-15f9-46d2-832d-fa052da55377
      group: mall-user
      cluster-name: Shanghai

总结:
NameSpace可以用来区分不同的环境,如dev、qa、prod等。所以说一套nacos可以支持多个环境的服务注册。

Group用来区分不同的微服务组,如交易微服务、仓储微服务组等。不同的微服务可以属于一个微服务组。

Service对应一个具体的服务,如订单服务、支付服务。而一个具体的服务中还可以进行区分:Cluster。Cluster可以用来描述一个服务的异地多机房部署。比如一个订单服务,可能在北京有部署,也可能在上海有部署。

2.5 服务领域模型

在这里插入图片描述

2.6 配置领域模型

围绕配置,主要有两个关联的实体,一个是配置变更历史,一个是服务标签(用于打标分类,方便索引),由 ID 关联。
在这里插入图片描述

三、Spring Cloud Alibaba Nacos快速开始

3.1 Spring Cloud Alibaba版本选型

在这里插入图片描述
在这里插入图片描述

3.2 搭建Nacos-client服务

1、引入依赖

父Pom中支持spring cloud&spring cloud alibaba, 引入依赖:

<?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>
    <modules>
        <module>mall-order</module>
        <module>mall-common</module>
    </modules>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>org.jihu.mall</groupId>
    <artifactId>spring-cloud-alibaba-mall</artifactId>
    <version>1.0-SNAPSHOT</version>
    <name>spring-cloud-alibaba-mall</name>
    <packaging>pom</packaging>
    <description>Demo project for Spring Cloud Alibaba</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.SR8</spring-cloud.version>
        <spring-cloud-alibaba.version>2.2.5.RELEASE</spring-cloud-alibaba.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

</project>

当前项目orderpom中引入依赖:

<!-- nacos服务注册与发现 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

完整pom:

<?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">
    <parent>
        <artifactId>vip-spring-cloud-alibaba</artifactId>
        <groupId>com.tuling.mall</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    
    <artifactId>mall-user-consumer-demo</artifactId>

    <dependencies>
        <dependency>
            <groupId>com.tuling.mall</groupId>
            <artifactId>mall-common</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
    
        <!-- nacos服务注册与发现 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        
    </dependencies>
</project>

2、application.yml中配置

server:
  port: 8046

spring:
  application:
    name: mall-order

  # 配置nacos注册中心地址
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.131.172:8848
        # 配置是否为持久化实例
        #ephemeral: false

更多配置连接:https://github.com/alibaba/spring-cloud-alibaba/wiki/Nacos-discovery

在这里插入图片描述
3、启动springboot应用,nacos管理端界面查看是否成功注册

// 由于common模块中引入了数据库相关的,所以这里暂时排除相关自动化配置
// @EnableDiscoveryClient 该注解可以不写,springCloudAlibaba已经完成了配置
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, DruidDataSourceAutoConfigure.class})
public class MallOrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(MallOrderApplication.class, args);
    }
}

启动成功之后,登录nacos去查看服务列表:
http://192.168.131.172:8848/nacos
在这里插入图片描述
4、测试是否可用

使用RestTemplate进行服务调用,可以使用微服务名称 (spring.application.name)。

我们之前使用RestTemplate调用的时候必须写ip:port或者hostname:port,此时我们已经使用nacos完成了服务mall-order的注册,思考是否可以直接使用服务名称来调用。

// 之前url;
 String url = "http://localhost:8040/order/findOrderByUserId/"+id;

// 现在url:
String url = "http://mall-order/order/findOrderByUserId/"+id;

我们使用另一个服务mall-user中的如下controller方法来测试,该方法中使用RestTemplate调用mall-order服务,但是此时url地址中写的是服务名称,而并不是具体的ip:port。

@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping(value = "/findOrderByUserId/{id}")
    public Result findOrderByUserId(@PathVariable("id") Integer id) {
        log.info("根据userId {} 查询订单信息", id);
    
        String url = "http://mall-order/order/findOrderByUserId/"+id;
        Result result = restTemplate.getForObject(url, Result.class);
        return result;
    }
}

打开浏览器,我们来访问mall-user服务中的:http://localhost:8040/user/findOrderByUserId/1,以此来触发restTemplate去调用mall-order中的方法。

但是结果却是报错了:

-11-08 11:31:07.218 ERROR 14448 --- [nio-8040-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.web.client.ResourceAccessException: I/O error on GET request for "http://mall-order/order/findOrderByUserId/1": mall-order; nested exception is java.net.UnknownHostException: mall-order] with root cause

java.net.UnknownHostException: mall-order

什么意思呢?不知道的主机名mall-order

分析,依旧是说我们此时调用的是普通的restTemplate服务,虽然我们将服务已经注册到nacos中了,但是restTemplate并不认识这个服务名称,自然就无法通过服务名称解析具体的ip:port了。


所以说,此时要有一个组件,能够去动态的从nacos中读取服务列表,并且选择其中一个获得其ip:port,并将mall-order服务名转化为ip:port真实地址之后再使用restTemplate去调用服务。

其实Spring中的httpClient中提供有一个扩展点拦截器:ClientHttpRequestInterceptor。而其中负载均衡器组件Ribbon就实现了这个拦截器
在这里插入图片描述

public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {
    private LoadBalancerClient loadBalancer;
    private LoadBalancerRequestFactory requestFactory;

    public LoadBalancerInterceptor(LoadBalancerClient loadBalancer, LoadBalancerRequestFactory requestFactory) {
        this.loadBalancer = loadBalancer;
        this.requestFactory = requestFactory;
    }

    public LoadBalancerInterceptor(LoadBalancerClient loadBalancer) {
        this(loadBalancer, new LoadBalancerRequestFactory(loadBalancer));
    }

    public ClientHttpResponse intercept(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) throws IOException {
        URI originalUri = request.getURI();
        // 获取url中的服务名称,比如mall-order
        String serviceName = originalUri.getHost();
        Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);
        // 调用execute,我们跟进去看看这个方法是如何解析服务名的
        return (ClientHttpResponse)this.loadBalancer.execute(serviceName, this.requestFactory.createRequest(request, body, execution));
    }
}

在这里插入图片描述
我们进入到这个RibbonLoadBalancerClient是实现类中对应的这个方法中:

// serviceId就是serverName
public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {
    return this.execute(serviceId, (LoadBalancerRequest)request, (Object)null);
}

// 继续跟进去
public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint) throws IOException {
	// 根据服务名称从Map<String, AnnotationConfigApplicationContext> contexts = new ConcurrentHashMap();
	// 中获取一个服务的instance
    ILoadBalancer loadBalancer = this.getLoadBalancer(serviceId);
    // 获取到具体的server
    Server server = this.getServer(loadBalancer, hint);
    if (server == null) {
        throw new IllegalStateException("No instances available for " + serviceId);
    } else {
        RibbonLoadBalancerClient.RibbonServer ribbonServer = new RibbonLoadBalancerClient.RibbonServer(serviceId, server, this.isSecure(server, serviceId), this.serverIntrospector(serviceId).getMetadata(server));
        return this.execute(serviceId, (ServiceInstance)ribbonServer, (LoadBalancerRequest)request);
    }
}

// --------
protected Server getServer(ILoadBalancer loadBalancer, Object hint) {
	// 根据不同的算法选择一个server
    return loadBalancer == null ? null : loadBalancer.chooseServer(hint != null ? hint : "default");
}

Ps:Ribbon的源码我们后面会仔细研究,现在只是大概了解一下。

总结来说,就是此时我们其实可以使用Ribbon负载均衡器来实现服务选择,它默认实现了如上的功能,即拉取服务列表并通过算法选择其中一个服务来进行调用。

mall-order(localhost:8040, localhost:8041, localhost:8042) — 选择一个并替换mall-order名称—> localhost:8040 -------> 最终服务调用

所以说我们此时要给我们的RestTemplate配置这个负载均衡器,让其可以自动实现这个功能。

那么该如何配置呢?其实RestTemplate中是可以设置拦截器的:

@Configuration
public class RestTemplateConfig {

    @Autowired
    LoadBalancerClient loadBalancerClientl;

    @Bean
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();

        // 构造方法需要一个List<LoadBalancerClient>参数, 此时LoadBalancerClient在spring容器中是已经存在的
        restTemplate.setInterceptors(Collections.singletonList(new LoadBalancerInterceptor(loadBalancerClientl)));
        return restTemplate;
    }
}

配置好重启项目之后,我们再来测试:http://localhost:8040/user/findOrderByUserId/1
在这里插入图片描述
可以看到,此时已经restTemplate已经可以成功通过服务名mall-order来访问了。

优化:
在我们实际的使用中,其实可以不用手动的给restTemplate设置这个拦截器,可以直接使用Ribbon提供的注解 @LoadBalence 来完成拦截器的设置!

@Configuration
public class RestTemplateConfig {

    @Autowired
    LoadBalancerClient loadBalancerClientl;

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

这样也可以实现如上功能。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值