【微服务学习笔记(一)】Nacos、Feign、Gateway基础使用
- 总览
- Nacos
- Feign
- 统一网关Gateway
-
- 搭建网关
-
- [路由断言工厂(Route Predicate Factory)](#路由断言工厂(Route Predicate Factory))
- 路由过滤器(GatewayFliter)
- 全局过滤器(GlobalFilter)
- 过滤器执行顺序
- 跨域
本篇内容为学习笔记,学习链接为SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈课
课程资料链接可在视频下方找到,此处不粘贴,而以下的代码都是资料中有的,只不过做为记录单独粘贴,做为学习使用的参考步骤。
总览
微服务中需要用到的内容:
服务网关、 服务集群、 注册中心、配置中心、消息队列,在和数据库连接过程中则用到分布式缓存、分布式搜索,还需要的额外服务为分布式日志、系统监控链路追踪。
在以上的完成后,使用Jenkins完成自动化编译的过程,由Docker打包成镜像。
各个内容中所需的技术:
- 微服务注册发现
- Eureka
- Nacos
- Consul
- 服务远程调用
- OpenFegin
- Dubbo
- 服务链路监控
- Zipkin
- Sleuth
- 统一配置管理
- SpringCloudConfig
- Nacos
- 统一网关路由
- SpringCloudGateway
- Zuul
- 流量监控、降级、保护
- Hystix
- Sentinel
Nacos
Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service的首字母简称,一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
安装配置
可以参考文档下载Nacos。
Windows启动命令(standalone代表着单机模式运行,非集群模式):
java
startup.cmd -m standalone
打开nacos -> bin目录中,使用cmd启动,输入以上命令,点击生成的地址即可进入Nacos页面。
使用
项目中:
父工程pom文件:
java
<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>
子工程pom文件:
java
<!-- nacos客户端依赖包 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
客户端子配置文件(application.yml)中:
java
spring:
application:
name: userService
cloud:
nacos:
server-addr: localhost:8848
Nacos注册中心
服务多级存储模型
一级为服务、二级为集群、三级为实例。
项目中采用配置:
java
nacos:
server-addr: localhost:8848
discovery:
cluster-name: CQ #自定义集群名称
集群的设置可让某一个服务被集群内的服务请求优先访问。
负载均衡规则
NacosRule优先选择本地集群访问,本地集群内随机访问各个服务,本地集群无服务时进行跨集群访问:
在Nacos页面中,根据权重调整(0~1),权重越小,访问的概率越小:
环境隔离
通过namespace进行环境隔离:
1、nacos命名空间中创建
2、客户端服务中放入namespace生成的id号
3、重启服务,刷新nacos页面
java
spring:
cloud:
nacos:
server-addr: localhost:8848
discovery:
cluster-name: HZ #自定义集群名称
namespace: c2a69c6f-995c-4cc0-a3e1-8f545ece5875
默认情况下服务为临时实例,心跳检测即为每隔一段时间,向注册中心发送内容证明还在服务。
而非临时实例的主动询问,询问结果为服务关闭时,注册中心会等待服务恢复。
临时实例修改为非临时实例:
java
spring:
cloud:
nacos:
server-addr: localhost:8848
discovery:
cluster-name: HZ #自定义集群名称
namespace: c2a69c6f-995c-4cc0-a3e1-8f545ece5875
ephemeral: false #是否为临时实例
修改后在Nacos中心查看:
配置管理
获取配置原理:
添加配置,打开Nacos页面:
配置拉取
客户端依赖
java
<!-- nacos配置管理依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
resouces中新建bootstrp.yml文件,内容符合在nacos配置管理中的配置:
java
spring:
application:
name: userservice
profiles:
active: dev #环境
cloud:
nacos:
server-addr: localhost:8848
config:
file-extension: yaml #文件后缀名
配置热更新
方法一:
通过@Value注解注入,@RefreshScope刷新
java
@RefreshScope
public class UserController {
@Autowired
private UserService userService;
@Autowired
private PatternProperties patternProperties;
@Value("${pattern.dateformat}")
private String dateformat;
}
方法二:
注入后自动刷新,声明于类前
java
@ConfigurationProperties(prefix = "pattern")
多服务共享配置
多服务共享配置会根据读取优先级来进行配置,在此处主要介绍各个配置文件的优先级,以此来完成所想达到的共享配置目标。
微服务会从nacos读取的配置文件:
- [服务名]-[spring.profile.active].yaml,环境配置
- [服务名].yaml,默认配置,多环境共享
优先级:
[服务名]-[环境].yaml > [服务名].yaml > 本地配置
Feign
Feign为声明式Http客户端,帮助实现http请求发送,其中已经集成了ribbn,不需担心负载均衡。
远程调用
客户端依赖:
java
<!--feign客户端依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
@EnableFeignClients,自动装配开关
java
@EnableFeignClients(clients = UserClient.class,defaultConfiguration = DefaultFeignConfiguration.class)
public class OrderApplication {
}
创建新类UserClient
java
@FeignClient(value = "userservice")
public interface UserClient {
@GetMapping("/user/{id}")
User findById(@PathVariable("id") Long id);
}
OrderService
java
@Autowired
private UserClient userClient;
public Order queryOrderById(Long orderId) {
// 1.查询订单
Order order = orderMapper.findById(orderId);
// 2.用Feign远程调用
User user = userClient.findById(order.getUserId());
// 3.封装user到Order
order.setUser(user);
// 4.返回
return order;
}
配置
日志配置
方法一:
配置文件中:
java
feign:
client:
config:
default:
loggerLevel:FULL #看所有的日志
方法二:
性能优化
方法一:使用连接池HttClient或者OKHttp代替默认URLConnection
客户端依赖配置:
java
<!--引入HttpClient依赖-->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
客户端配置:
java
feign:
httpclient:
enabled: true # 支持HttpClient的开关
max-connections: 200 # 最大连接数
max-connections-per-route: 50 # 单个路径的最大连接数
方法二:日志级别尽量不使用basic或none
Fegin使用
统一网关Gateway
网关功能:
- 身份认证和权限校验
- 服务路由、负载均衡
- 请求限流
在SpringCloud中网关的实现包括两种:
- Gateway
- zuul
Zuul是基于Servlet的实现,属于阻塞式编程。而SpringCloudGateway则是基于Spring5中提供的WebFlux,属于响应式编程的实现,具备更好的性能。
搭建网关
1、引入依赖
网关模块pom:
java
<!--nacos服务注册发现依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--网关gateway依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
2、编写路由配置以及nacos地址
java
server:
port: 10010
logging:
level:
cn.itcast: debug
pattern:
dateformat: MM-dd HH:mm:ss:SSS
spring:
application:
name: gateway
cloud:
nacos:
server-addr: nacos:8848 # nacos地址
gateway:
routes:
- id: user-service # 路由标示,必须唯一
uri: lb://userservice # 路由的目标地址
predicates: # 路由断言,判断请求是否符合规则
- Path=/user/** # 路径断言,判断路径是否是以/user开头,如果是则符合
- id: order-service
uri: lb://orderservice
predicates:
- Path=/order/**
default-filters: #过滤器,处理请求或响应
- AddRequestHeader=Truth,Itcast is freaking awesome!
路由断言工厂(Route Predicate Factory)
我们在配置文件中写的断言规则只是字符串,这些字符串会被 Predicate Factory读取并处理,转变为路由判断的条件。
例如Path=/user/**是按照路径匹配,这个规则是由
org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory类来处理的。
路由过滤器(GatewayFliter)
网关过滤器,对进入网关的请求和微服务返回的响应做处理。
作用:对路由的请求或响应做加工处理,比如添加请求头配置在路由下的过滤器。
java
spring:
cloud:
gateway:
routes:
filters: #给单独微服务添加过滤器,只对当前路由的请求生效
- AddRequestHeader=Truth,Itcast is freaking awesome!
全局过滤器(GlobalFilter)
全局过滤器的作用也是处理一切进入网关的请求和微服务响应,与GatewayFilter的作用一样。
区别在于GatewayFilter通过配置定义,处理逻辑是固定的。
而Globalfiter的逻辑需要自己写代码实现,定义方式是实现GlobalFilter接口。
java
@Component
public class AuthorizeFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1.获取请求参数
ServerHttpRequest request = exchange.getRequest();
MultiValueMap<String, String> params = request.getQueryParams();
// 2.获取参数中的 authorization 参数
String auth = params.getFirst("authorization");
// 3.判断参数值是否等于 admin
if ("admin".equals(auth)) {
// 4.是,放行
return chain.filter(exchange);
}
// 5.否,拦截
// 5.1.设置状态码,给用户合适的报错
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
// 5.2.拦截请求
return exchange.getResponse().setComplete();
}
@Override
public int getOrder() {//设置过滤优先级,数值越大优先级越低
return -1;
}
}
在以上代码中,使用getOrder()方法设置过了优先级,除此之外,还可以在该类声明上使用@Order(-1)注解规定优先级。
过滤器执行顺序
所有过滤器都来自于GatewayFilter,因此得以进行排序。
路由过滤器和defaultFilter的order由Spring指定,默认是按照声明顺序从1递增
跨域
跨域问题:浏览器禁止请求的发起者与服务端发生跨域ajax请求,请求被浏览器拦截的问题
通过CORS方案,让浏览器询问服务器,判断是否可以进行跨域。
java
spring:
cloud:
gateway:
globalcors: # 全局的跨域处理
add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
corsConfigurations:
'[/**]':
allowedOrigins: # 允许哪些网站的跨域请求
- "http://localhost:8090"
- "http://www.leyou.com"
allowedMethods: # 允许的跨域ajax的请求方式
- "GET"
- "POST"
- "DELETE"
- "PUT"
- "OPTIONS"
allowedHeaders: "*" # 允许在请求中携带的头信息
allowCredentials: true # 是否允许携带cookie
maxAge: 360000 # 这次跨域检测的有效期