1. nacos注册中心集群的搭建
要想搭建nacos集群模式,这些集群中的每台nacos服务,都必须连接同一个数据库。因为我们的nacos都放在同一台主机上,所以我们必须为每台nacos起不同的端口。
(1)修改端口号 8849 8850 8851
/conf/application.properties
(2) 连接mysql数据库
/conf/application.properties
创建nacos数据库并导入相关的表结构和数据
nacos-mysql.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');
(3)修改集群配置文件
cluster.conf
(4)启动nacos每台主机
2 . 网关
什么是网关?
大家都知道,从一个房间走到另一个房间,必然要经过一扇门。同样,从一个网络向另一个网络发送信息,也必须经过一道“关口”,这道关口就是网关。顾名思义,网关(Gateway)就是一个网络连接到另一个网络的“关口”。
网关(Gateway)又称网间连接器、协议转换器。网关在传输层上以实现网络互连,是最复杂的网络互连设备,仅用于两个高层协议不同的网络互连。网关的结构也和路由器类似,不同的是互连层。网关既可以用于广域网互连,也可以用于局域网互连。 网关是一种充当转换重任的计算机系统或设备。在使用不同的通信协议、数据格式或语言,甚至体系结构完全不同的两种系统之间,网关是一个翻译器。与网桥只是简单地传达信息不同,网关对收到的信息要重新打包,以适应目的系统的需求。同时,网关也可以提供过滤和安全功能。大多数网关运行在OSI 7层协议的顶层--应用层。
为什么使用网关?
网关api:封装了系统内部架构,为每个客户端提供一个定制的 API。在微服务架构中,服务网关的核心要点是,所有的客户端和消费端都通过统一的网关接入微服务,在网关层处理所有的非业务功能。
解决方案: 需要再所有微服务前,搞一个代理服务器。让前端记住代理服务器的地址。由代理把请求转发给后面的微服务。
所谓的API网关,就是指系统的统一入口,它封装了应用程序的内部结构,为客户端提供统一服 务,一些与业务本身功能无关的公共逻辑可以在这里实现,诸如认证、鉴权、监控(黑白名单)、路由转发等等。 添加上API网关之后,系统的架构图变成了如下所示:
常见的代理组件有哪些?
nginx:
l Kong
基于Nginx+Lua[再nginx中可以编写代码]开发,性能高,稳定,有多个可用的插件(限流、鉴权等等)可以开箱即用。 问题: 只支持Http协议;二次开发,自由扩展困难;提供管理API,缺乏更易用的管控、配置方式。
l Zuul 1.0(慢 servlet 2.0 ) zuul2.0 没出来。
Netflix开源的网关,功能丰富,使用JAVA开发,易于二次开发 问题:缺乏管控,无法动态配
置;依赖组件较多;处理Http请求依赖的是Web容器,性能不如Nginx
l Spring Cloud Gateway
Spring公司为了替换Zuul而开发的网关服务,将在下面具体介绍。
注意:**SpringCloud alibaba技术栈中并没有提供自己的网关,我们可以采用Spring Cloud Gateway来做网关**
2.1 springcloud -gateway网关的简介
Spring Cloud Gateway是Spring公司基于Spring 5.0,Spring Boot 2.0 和 Project Reactor 等术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。它的目标是替代 Netflix Zuul,其不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控和限流。
优点:
l 性能强劲:是第一代网关Zuul的1.6倍
l 功能强大:内置了很多实用的功能,例如转发、监控、限流等
l 设计优雅,容易扩展.
缺点:
gateway内置了服务器 netty服务器。千万不要在使用tomcat作为服务器。
2.1 springcloud -gateway网关的使用
(1) 创建gateway模块
(4)引入 pom 依赖
<dependencies>
<!--因为gateway依赖中内置netty服务器 所以千万不能引用spring-boot-starter-web依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
</dependencies>
(3) 创建主启动类
@SpringBootApplication
public class GatewayApp {
public static void main(String[] args) {
SpringApplication.run(GatewayApp.class,args);
}
}
(4)配置文件
#端口号
server:
port: 7000
#服务名称
spring:
application:
name: qy165-gateway
#配置路由
cloud:
gateway:
routes:
- id: qy163-product #唯一即可,如果没有默认UUID生成
order: 0 #优先级 值越小优先级越高
uri: http://localhost:8080 #真实要转发的微服务地址 http://localhost:8080/product/getById/1
predicates:
- Path=/product/** #断言:当满足该断言,则会转发到uri地址。 path:路径断言
- id: qy163-order
uri: http://localhost:8090
predicates:
- Path=/order/**
(5)测试访问
2.2 增强版
现在在配置文件中写死了转发路径的地址, 前面我们已经分析过地址写死带来的问题,. 接下来我们从注册中心获取此地址。
(1 ) gateway微服务中引入nacos依赖
<!--引入nacos注册中心-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
(2)修改配置文件
#端口号
server:
port: 7000
#服务名称
spring:
application:
name: qy163-gateway
#配置路由
cloud:
gateway:
routes:
- id: qy163-product #唯一即可,如果没有默认UUID生成
order: 0 #优先级 值越小优先级越高
#uri: http://localhost:8080 #真实要转发的微服务地址 http://localhost:8080/product/getById/1 等
uri: lb://qy163-product #lb://微服务名称
predicates:
- Path=/product/** #断言:当满足该断言,则会转发到uri地址。 path:路径断言
- id: qy163-order
#uri: http://localhost:8090
uri: lb://qy163-order
predicates:
- Path=/order/**
#注册中心地址
nacos:
discovery:
server-addr: 192.168.28.147:8849,192.168.28.147:8850,192.168.28.147:8851
2.3 简约版
思考: 如果后面增加一个微服务-那么我们就得修改gateway的配置。 自动定位微服务。
(1)修改配置文件
#端口号
server:
port: 7000
#服务名称
spring:
application:
name: qy163-gateway
#配置路由
#开启自动定位
cloud:
gateway:
discovery:
locator:
enabled: true
#注册中心地址
nacos:
discovery:
server-addr: 192.168.28.147:8849,192.168.28.147:8850,192.168.28.147:8851
(2)浏览器访问
2.4 gateway基本概念
路由(Route) 是 gateway 中最基本的组件之一,表示一个具体的路由信息载体。主要定义了下面的几个信息:
l id,路由标识符,区别于其他 Route。默认生成一个
l uri,路由指向的目的地 uri,即客户端请求最终被转发到的微服务。
l order,用于多个 Route 之间的排序,数值越小排序越靠前,匹配优先级越高。--不改
l predicate,断言的作用是进行条件判断,只有断言都返回真,才会真正的执行路由。
l filter,过滤器用于修改请求和响应信息。
2.5 gateway路由的流程
2.6 gateway提供了哪些断言
l *基于**Datetime**类型的断言工厂*
此类型的断言根据时间做判断,主要有三个:
AfterRoutePredicateFactory: 接收一个日期参数,判断请求日期是否晚于指定日期
BeforeRoutePredicateFactory: 接收一个日期参数,判断请求日期是否早于指定日期
BetweenRoutePredicateFactory: 接收两个日期参数,判断请求日期是否在指定时间段内
-After=2019-12-31T23:59:59.789+08:00[Asia/Shanghai]
l *基于远程地址的断言工厂* *RemoteAddrRoutePredicateFactory**:*
接收一个IP地址段,判断请求主机地址是否在地址段中
-RemoteAddr=192.168.1.1/24
l *基于**Cookie**的断言工厂*
CookieRoutePredicateFactory:接收两个参数,cookie 名字和一个正则表达式。 判断请求
cookie是否具有给定名称且值与正则表达式匹配。
-Cookie=chocolate, ch.
l *基于**Header**的断言工厂*
HeaderRoutePredicateFactory:接收两个参数,标题名称和正则表达式。 判断请求Header是否
具有给定名称且值与正则表达式匹配。 key value
-Header=X-Request-Id, \d+
l *基于**Host**的断言工厂*
HostRoutePredicateFactory:接收一个参数,主机名模式。判断请求的Host是否满足匹配规则。
-Host=**.testhost.org
l *基于**Method**请求方法的断言工厂*
MethodRoutePredicateFactory:接收一个参数,判断请求类型是否跟指定的类型匹配。
-Method=GET
l *基于**Path**请求路径的断言工厂*
PathRoutePredicateFactory:接收一个参数,判断请求的URI部分是否满足路径规则。
-Path=/foo/{segment}基于Query请求参数的断言工厂
QueryRoutePredicateFactory :接收两个参数,请求param和正则表达式, 判断请求参数是否具
有给定名称且值与正则表达式匹配。
-Query=baz, ba.
l *基于路由权重的断言工厂*
WeightRoutePredicateFactory:接收一个[组名,权重], 然后对于同一个组内的路由按照权重转发
routes:
-id: weight_route1 uri: host1 predicates:
-Path=/product/**
-Weight=group3, 1
-id: weight_route2 uri: host2 predicates:
-Path=/product/**
-Weight= group3, 9
2.7 过滤器
分成两种:
第一种局部过滤:只对当前路由有效
第二种全局过滤器: 对所有的路由都有效
全局过滤器:
认证校验功能
l 当客户端第一次请求服务时,服务端对用户进行信息认证(登录)
l 认证通过,将用户信息进行加密形成token,返回给客户端aaaa,作为登录凭证
l 以后每次请求,客户端都携带认证的token
l 服务端对token进行解密,判断是否有效。
如上图,对于验证用户是否已经登录鉴权的过程可以在网关统一检验。
检验的标准就是请求中是否携带token凭证以及token的正确性。
下面的我们自定义一个GlobalFilter,去校验所有请求的请求参数中是否包含“token”,如何不包含请求参数“token”则不转发路由,否则执行正常的逻辑
自定义全局过滤器 要求:必须实现GlobalFilter,Ordered接口
创建 MyGlobalFilter 类
(1) 导入依赖
<!--fastjson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
(2)
package com.dxh.gateway.filter;
import com.alibaba.fastjson.JSON;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
/**
* @program: springcloud_02
* @author: ♥丁新华
* @create: 2023-05-15 19:51
**/
@Component
public class MyGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
//获取请求路径
String path = request.getPath().toString();
//该路径是否为放行路径
if(path!=null && path.equals("/login")){//因为不满足断言
return chain.filter(exchange);// 放行
}
//获取当前请求是否携带token令牌---请求头中放置
String token = request.getHeaders().getFirst("token");
if(token!=null && token.equals("admin")){ //注意值:admin随便写。
return chain.filter(exchange);// 放行
}
//请先登录----
//3.2封装返回数据
Map<String, Object> map = new HashMap<>();
map.put("msg", "未登录");
map.put("code", 401);
//3.3作JSON转换--fastjson
byte[] bytes = JSON.toJSONString(map).getBytes(StandardCharsets.UTF_8);
//3.4调用bufferFactory方法,生成DataBuffer对象
DataBuffer buffer = response.bufferFactory().wrap(bytes);
//4.调用Mono中的just方法,返回要写给前端的JSON数据
return response.writeWith(Mono.just(buffer));
}
//获取优先级 值约大优先级越高
@Override
public int getOrder() {
return 0;
}
}
(3) 访问测试
3. 链路追踪
链路追踪是分布式系统下的一个概念,它的目的就是要解决上面所提出的问题,也就是将一次分布式请求还原成调用链路,将一次分布式请求的调用情况集中展示,比如,各个服务节点上的耗时、请求具体到达哪台机器上、每个服务节点的请求状态等等。
3.1 链路追踪介绍
在大型系统的微服务化构建中,一个系统被拆分成了许多模块。这些模块负责不同的功能,组合成系统,最终可以提供丰富的功能。在这种架构中,一次请求往往需要涉及到多个服务。互联网应用构建在不同的软件模块集上,这些软件模块,有可能是由不同的团队开发、可能使用不同的编程语言来实现、有可能布在了几千台服务器,横跨多个不同的数据中心,也就意味着这种架构形式也会存在一些问题:
如何快速发现问题?
如何判断故障影响范围?
如何梳理服务依赖以及依赖的合理性?
如何分析链路性能问题以及实时容量规划?
分布式链路追踪(Distributed Tracing),就是将一次分布式请求还原成调用链路,进行==日志记录==,==性能监控==并将一次分布式请求的调用情况集中展示。比如各个服务节点上的耗时、请求具体到达哪台机器上IP、每个服务节点的请求状态200 500等等。
3.2 链路追踪使用的组件由哪些?
1.cat 由大众点评开源,基于Java开发的实时应用监控平台,包括实时应用监控,业务监控 。 集成 方案是通过代码埋点的方式来实现监控,比如: 拦截器,过滤器等。 对代码的侵入性很大,集成成本较高。风险较大。
2.pinpoint Pinpoint是韩国人开源的基于字节码注入的调用链分析,以及应用监控分析工具。特点 是支持多种插件,UI功能强大,接入端无代码侵入。 你开源
3.skywalking 【未来企业会使用的多】
SkyWalking是本土开源的基于字节码注入的调用链分析,以及应用监控分析工具。特点是支持多
种插件,UI功能较强,接入端无代码侵入。目前已加入Apache孵化器--开源。
4.Sleuth **(日志记录每一条链路上的所有节点,以及这些节点所在的机器,和耗时。)
-
zipkin** 由Twitter公司开源,开放源代码分布式的跟踪系统,用于收集服务的定时数据,以解决微 服务架构中的延迟问题,包括:==数据的收集、存储、查找和展现《图形化》==。该产品结合spring-cloud-sleuth 使用较为简单, 集成很方便, 但是功能较简单。
SpringCloud 提供的分布式系统中链路追踪解决方
开源组件对比
及开源组件的地址:
-
zipkin -> https://zipkin.io/
-
Jaeger -> https://www.jaegertracing.io/
-
Pinpoint -> https://github.com/pinpoint-apm/pinpoint
-
SkyWalking -> http://skywalking.apache.org/
主要了解 sleuth+zipkin
4. sleuth
4.1 sleuth 介绍
springCloud Sleuth主要功能就是在分布式系统中提供追踪解决方案。它大量借用了Google Dapper的设计, 先来了解一下Sleuth中的术语和相关概念。
*1.Trace* *(一条完整链路--包含很多span(微服务接口))*
由一组Trace Id(贯穿整个链路)相同的Span串联形成一个树状结构。为了实现请求跟踪,当请求到达分布式系统的入口端点时,只需要服务跟踪框架为该请求创建一个唯一的标识(即TraceId),同时在分布式系统内部流转的时候,框架始终保持传递该唯一值,直到整个请求的返回。那么我们就可以使用该唯一标识将所有的请求串联起来,形成一条完整的请求链路。
*2.Span*
代表了一组基本的工作单元。为了统计各处理单元的延迟,当请求到达各个服务组件的时候,也通过一个唯一标识(SpanId)来标记它的开始、具体过程和结束。通过SpanId的开始和结束时间戳,就能统计该span的调用时间,除此之外,我们还可以获取如事件的名称。请求信息等元数据。
*3. Annotation*
用它记录一段时间内的事件,内部使用的重要注释:
l cs(Client Send)客户端发出请求,开始一个请求的命令
l sr(Server Received)服务端接受到请求开始进行处理, sr-cs = 网络延迟(服务调用的时间)
l ss(Server Send)服务端处理完毕准备发送到客户端,ss - sr = 服务器上的请求处理时间
l cr(Client Reveived)客户端接受到服务端的响应,请求结束。 cr - cs = 请求的总时间
4.2 使用sleuth
(1) 引入依赖 在父工程中
<!-- sleuth -->
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
</dependencies>
(2) 启动微服务,调用之后,我们可以在控制台观察到sleuth的日志输出
思考: 我们可以通过sleuth的日志,观察每个微服务执行的时间。但是这样会非常麻烦。能否把这些sleuth生成的日志,以图形化的形式展示。--我们可以使用zipkin来搜集sleuth生成的日志,并以图形化展示。
4.3 使用 zipkin
(1)zipkin介绍:
Zipkin是一个分布式链路跟踪系统,可以采集时序数据来协助定位延迟等相关问题。数据可以存储在cassandra,MySQL,ES,mem中。分布式链路跟踪是个老话题,国内也有类似的框架,比如阿里的skywalking。 zipkin目前和SpringCloud生态结合紧密,有相关的支持。
架构
主要包括客户端和一个管理服务端。在客户端采集数据后,发送给服务端,用来展示数据。在每个instrumented的客户端,写入了traceId,然后统一收集数据在服务端存储。这里instrumented翻译过来是仪器化,设备化,为了简单我把他称作标识实体
,代表一个接入了zipkin的客户端。
结构和概念
zipkin包括四个组件,collector,storage,search,webUI。其中collector中重点有两个
- Span表示一个追踪节点,有唯一标识
- Trace 表示一条调用链路,根据Span的parentId串联起来
从上面的图可以看出zipkin需要一个服务端,而每个微服务就是客户端。
(2) zipkin启动
下载
启动zipkin
java -jar zipkin-server-2.12.9-exec.jar
访问:localhost:9411
微服务接入zipkin服务端
(1) 引入依赖
<!--zipkin-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
(2) 配置文件
每个微服务接入zipkin服务端
(3) 启动访问
随机访问product
5. 配置中心
思考: 商品微服务--搭建n个集群---它的配置一模一样。如果修改某个配置内容。你需要给每个微服务都要修改配置内容 商品微服务和订单微服务他们之间有没有公共配置。---需要对每个微服务都要修改,比较麻烦。
可以使用配置中心来管理每个微服务的配置文件。
5.1 哪些组件可以作为配置中心
开源配置中心基本介绍
目前市面上用的比较多的配置中心有:(按开源时间排序)
Disconf
2014年7月百度开源的配置管理中心,同样具备配置的管理能力,不过目前已经不维护了,最近的一次提交是两年前了。
Spring Cloud Config
2014年9月开源,Spring Cloud 生态组件,可以和Spring Cloud体系无缝整合。
Apollo
2016年5月,携程开源的配置管理中心,具备规范的权限、流程治理等特性。
Nacos
2018年6月,阿里开源的配置中心,也可以做DNS和RPC的服务发现。
(1)在nacos配置中心创建微服务配置文件
(2)微服务使用配置中心中指定配置文件 导入依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
(3) 创建一个bootstrap.properties配置文件
#微服务名称
spring.application.name=qy163-product01
#指定配置中心地址
spring.cloud.nacos.server-addr=192.168.28.147:8848
(4)在controller验证读取到配置中的内容
@Value ("${student.name}")
private String name;
@GetMapping("getInfo")
public String getInfo(){
return "我叫:" + name + "16岁,矮矬穷";
}
bootstarp 和 application 的区别:
bootstarp 和 application 都是springcloud 中的配置文件 区别主要有以下几个方面
(1) 加载顺序区别
bootstarp 文件 比 application文件 优先加载 因为 bootstrap 是由spring父上下文加载,
application 是 由子上下文加载
(2)优先级区别
bootstrap 加载的配置文件是不能被application 相同配置进行覆盖,如果两个配置文件同时存在,则以bootstrap 文件为主,
(3) 应用场景区别
bootstrap 的应用场景
1. 配置一些固定的 不能覆盖的属性 用于一些系统级别的参数配置
本地配置文件默认不能覆盖远程配置
2. 一些需要加密和解密的场景
当你使用了nacos配置中心时,这时需要在boostrap配置文件中添加连接到配置中心的配置属性来加载外部配置中心的配置信息
6 . nacos实时刷新
(1) 加入实时刷新注解
在controller 层中 加 @RefreshScope
//实时刷新
@RefreshScope
7. 微服务集群共享一个配置文件
应该把每个微服务的配置放入对应配置中心文件中。
#???:8080~8089 []
server.port=8081
#???
spring.datasource.url=jdbc:mysql://localhost:3306/spring_cloud?serverTimezone=Asia/Shanghai
spring.datasource.password=abc123
spring.datasource.username=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#??sql??
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
#??????
spring.cloud.nacos.discovery.server-addr=192.168.28.147:8848
#192.168.28.147:8849,192.168.28.147:8850,192.168.28.147:8851
#微服务名称
spring.application.name=qy163-product
#zipkin
spring.zipkin.base-url=http://localhost:9411/
8. 多个微服务共享一些公共 的 配置内容 例如端口号
(1)nacos创建一个公共配置文件
spring.cloud.nacos.discovery.server-addr=192.168.28.147:8848
(2)在微服务bootstrap文件中
#指定组名
spring.cloud.nacos.config.group=DEFAULT_GROUP
#额外的配置
#扩展文件的ID
spring.cloud.nacos.config.extension-configs[0].data-id=datasource.properties
spring.cloud.nacos.config.extension-configs[0].group=DEFAULT_GROUP
#进行实时刷新
spring.cloud.nacos.config.extension-configs[0].refresh=true