主要内容:
1、Gateway 过滤器返回Json数据
2、基于Nginx的Gateway 集群搭建
3、sleuth+zipkin 链路追踪
4、nacos管理微服务的配置中心
一、Gateway 过滤器返回Json数据
1.1 在过滤器pom文件中引入fastjsony依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.72</version>
</dependency>
1.2 具体代码如下:
package com.dhy.gateway.filter;
import com.alibaba.fastjson.JSON;
import org.apache.commons.lang.StringUtils;
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.HttpStatus;
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.util.HashMap;
import java.util.Map;
/**
* @program: springcloud-father
* @description: dengluquanxian
* @author: XXX
* @create: 2021-07-08 17:12
**/
//@Component
public class LoginFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response= exchange.getResponse();
// 1.请求头是否携带token
String token = request.getHeaders().getFirst("token");//获取token
System.out.println(token);
if (!StringUtils.isEmpty(token)){
if("admin".equals(token)){
return chain.filter(exchange); //如果token存在,且输入的登录名与tokenz中的一直,放行
}
}
// 2.判断请求路径是否为登录路径,如果是登录路径,放行
String path=request.getPath().toString();
System.out.println(path);
if (path.contains("/login")){
return chain.filter(exchange);//放行
}
//响应一个结果哦--请先登录
Map data=new HashMap(); // 声明一个Result
DataBuffer buffer=null;
try {
data.put("status",401);
data.put("msg","请先登录");
// 需要引入fastjson
byte[] datas= JSON.toJSONString(data).getBytes("utf-8");
buffer=response.bufferFactory().wrap(datas);
response.setStatusCode(HttpStatus.UNAUTHORIZED);
response.getHeaders().add("Content-Type","application/json;charset=UTF-8");
}catch (Exception e){
e.printStackTrace();
}
return response.writeWith(Mono.just(buffer));
}
@Override
public int getOrder() {
return 0;
}
}
1.3 测试
二、基于Nginx部署GateWay 集群
只需要在Nginx的配置文件中做以下配置即可
upstream gateways {
server 127.0.0.1:81;
server 127.0.0.1:82;
}
server {
listen 80;
server_name localhost;
logs/host.access.log main;
...
location / {
proxy_pass http://gateways/;
}
...
}
三、sleuth和zipkin 链路追踪
3.1 Spring Cloud Sleuth 介绍
Spring Cloud Sleuth是Spring Cloud的一个组件,它的主要功能是在分布式系统中提供服务链路追踪的解决方案。
3.1.1 为什么需要Spring Cloud Sleuth?
微服务架构是一个分布式架构,微服务系统按业务划分为服务单元,一个微服务系统会有多个服务单元。因为服务单元数量多,业务的复杂度较高,如果出现了错误或异常,很难去定位。原因主要是一个请求可能会调用很多个微服务,而内部服务的调用复杂性决定了问题的难以定位,所以在微服务中,必须实现分布式链路追踪,去跟进一个请求到底有哪些服务参与,参与的顺序又是怎样的,从而达到每个请求步骤清晰可见,出现问题能快速定位的目的。
3.1.3 Spring Cloud Sleuth基本术语
(1)Span:基本工作单元,发送一个远程调度任务就会产生一个Span,Span是用一个64位ID唯一标识的,Trace是用另一个64位ID唯一标识的。Span还包含了其他的信息,例如摘要、时间戳事件、Span的ID以及进程ID。
(2)Trace:由一系列Span组成的,呈树状结构。请求一个微服务系统的API接口,这个API接口需要调用多个微服务单元,调用每个微服务单元都会产生一个新的Span,所有由这个请求产生的Span组成了这个Trace。
(3)Annotation:用于记录一个事件,一些核心注解用于定义一个请求的开始和结束,这些注解如下。
cs-Client Sent:客户端发送一个请求,这个注解描述了Span的开始。
sr-Server Received:服务端获得请求并准备开始处理它,如果将其sr减去cs时间戳,便可得到网络传输的时间。
ss-Server Sent:服务端发送响应,该注解表明请求处理的完成(当请求返回客户端),用ss的时间戳减去sr时间戳,便可以得到服务器请求的时间。
cr-Client Received:客户端接收响应,此时Span结束,如果cr的时间戳减去cs时间戳,便可以得到整个请求所消耗的时间。
Spring Cloud Sleuth提供了一套完整的链路解决方案,它可以结合Zipkin,将链路数据发送到Zipkin,并利用Zipkin来存储链路信息,也可以利用Zipkin UI来展示数据。
3.2 Zipkin介绍
Zipkin 是 Twitter 的一个开源项目,它基于Google Dapper实现,它致力于收集服务的定时数据,以解决微服务架构中的延迟问题,包括数据的收集、存储展现、查找和我们可以使用它来收集各个服务器上请求链路的跟踪数据,并通过它提供的REST API接口来辅助我们查询跟踪数据以实现对分布式系统的监控程序,从而及时地发现系统中出现的延迟升高问题并找出系统性能瓶颈的根源
除了面向开发的 API 接口之外,它也提供了方便的UI组件来帮助我们直观的搜索跟踪信息和分析请求链路明细,比如:可以查询某段时间内各用户请求的处理时间等。
Zipkin 提供了可插拔数据存储方式:In-Memory、MySql、Cassandra 以及 Elasticsearch。
Zipkin架构图
3.2.2 zipkin服务端安装
步骤1:下载zipkin的jar包
步骤2:通过命令行,使用以下命令启动zipkin java -jar zipkin-server-2.12.9-exec.jar
步骤3:通过浏览器访问 http://localhost:9411访问
3.2.3 Zipkin客户端集成
步骤1:在各个微服务的pom文件中引入zipkin依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
步骤2:在各个微服务的配置文件中添加以下配置
zipkin:
base-url: http://localhost:9411
discovery-client-enabled: false #不要让nacos把zipkin注册进去
sleuth:
sampler:
probability: 1.0 # 概率
步骤3:访问微服务
http://localhost:8000/order/saveOrder?pid=2&num=10
步骤4:查看Zipkin界面,查看结果
步骤5:点击其中的一条记录,可以看到具体的调用线路
3.3 ZipKin数据持久化
Zipkin Server默认会将追踪数据信息保存到内存,但这种方式不适合生产环境。Zipkin支持将追踪数据持久化到mysql数据库或elasticsearch中。我们这里使用mysql.
步骤1:创建数据库 注意这里的设置与以往有所不同
步骤2:创建mysql数据环境
CREATE TABLE IF NOT EXISTS zipkin_spans (
`trace_id_high` BIGINT NOT NULL DEFAULT 0 COMMENT 'If non zero, this means the trace uses 128 bit traceIds instead of 64 bit',
`trace_id` BIGINT NOT NULL,
`id` BIGINT NOT NULL,
`name` VARCHAR(255) NOT NULL,
`parent_id` BIGINT,
`debug` BIT(1),
`start_ts` BIGINT COMMENT 'Span.timestamp(): epoch micros used for endTs query and to implement TTL',
`duration` BIGINT COMMENT 'Span.duration(): micros used for minDuration and maxDuration query' )
ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci;
ALTER TABLE zipkin_spans ADD UNIQUE KEY(`trace_id_high`, `trace_id`, `id`) COMMENT 'ignore insert on duplicate';
ALTER TABLE zipkin_spans ADD INDEX(`trace_id_high`, `trace_id`, `id`) COMMENT 'for joining with zipkin_annotations';
ALTER TABLE zipkin_spans ADD INDEX(`trace_id_high`, `trace_id`) COMMENT 'for getTracesByIds';
ALTER TABLE zipkin_spans ADD INDEX(`name`) COMMENT 'for getTraces and getSpanNames';
ALTER TABLE zipkin_spans ADD INDEX(`start_ts`) COMMENT 'for getTraces ordering and range';
CREATE TABLE IF NOT EXISTS zipkin_annotations (
`trace_id_high` BIGINT NOT NULL DEFAULT 0 COMMENT 'If non zero, this means the trace uses 128 bit traceIds instead of 64 bit',
`trace_id` BIGINT NOT NULL COMMENT 'coincides with zipkin_spans.trace_id',
`span_id` BIGINT NOT NULL COMMENT 'coincides with zipkin_spans.id',
`a_key` VARCHAR(255) NOT NULL COMMENT 'BinaryAnnotation.key or Annotation.value if type == -1',
`a_value` BLOB COMMENT 'BinaryAnnotation.value(), which must be smaller than 64KB',
`a_type` INT NOT NULL COMMENT 'BinaryAnnotation.type() or -1 if Annotation',
`a_timestamp` BIGINT COMMENT 'Used to implement TTL; Annotation.timestamp or zipkin_spans.timestamp',
`endpoint_ipv4` INT COMMENT 'Null when Binary/Annotation.endpoint is null',
`endpoint_ipv6` BINARY(16) COMMENT 'Null when Binary/Annotation.endpoint is null, or no IPv6 address',
`endpoint_port` SMALLINT COMMENT 'Null when Binary/Annotation.endpoint is null',
`endpoint_service_name` VARCHAR(255) COMMENT 'Null when Binary/Annotation.endpoint is null' )
ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci;
ALTER TABLE zipkin_annotations ADD UNIQUE KEY(`trace_id_high`, `trace_id`, `span_id`, `a_key`, `a_timestamp`) COMMENT 'Ignore insert on duplicate';
ALTER TABLE zipkin_annotations ADD INDEX(`trace_id_high`, `trace_id`, `span_id`) COMMENT 'for joining with zipkin_spans';
ALTER TABLE zipkin_annotations ADD INDEX(`trace_id_high`, `trace_id`) COMMENT 'for getTraces/ByIds';
ALTER TABLE zipkin_annotations ADD INDEX(`endpoint_service_name`) COMMENT 'for getTraces and getServiceNames';
ALTER TABLE zipkin_annotations ADD INDEX(`a_type`) COMMENT 'for getTraces';
ALTER TABLE zipkin_annotations ADD INDEX(`a_key`) COMMENT 'for getTraces';
ALTER TABLE zipkin_annotations ADD INDEX(`trace_id`, `span_id`, `a_key`) COMMENT 'for dependencies job';
CREATE TABLE IF NOT EXISTS zipkin_dependencies (
`day` DATE NOT NULL,
`parent` VARCHAR(255) NOT NULL,
`child` VARCHAR(255) NOT NULL,
`call_count` BIGINT )
ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci;
ALTER TABLE zipkin_dependencies ADD UNIQUE KEY(`day`, `parent`, `child`);
步骤3:启动zipkin Server,这里需要指定保存mysql的信息
java -jar zipkin-server-2.12.9-exec.jar --STORAGE_TYPE=mysql --MYSQL_HOST=localhost --MYSQL_TCP_PORT=3306 --MYSQL_DB=zipkin --MYSQL_USER=root --MYSQL_PASS=xxxxxx
注意:这里需要关闭前边已经打开过的zipkin,不然报错端口被占用;
另外,启动过程中如果出现上边的错误,用以下方法解决:
1、数据库做一下修改,允许被外界连接
2、在端口输入命令:
alter user 'username'@'%' identified with mysql_native_password by 'password';
步骤4:测试
访问连接:http://localhost:8000/order/saveOrder?pid=2&num=10
查看数据库,发现日志信息已存入数据库
四、nacos管理微服务的配置中心
4.1 为什么使用微服务配置中心
4.2 可以作为配置中心使用的组件

4.3.1 在微服务中使用配置中心的配置文件