文章目录
一、Nacos
Nacos是SpringCloudAlibaba的组件,而SpringCloudAlibaba也遵循SpringCloud中定义的服务注册、服务发现规范。因此使用Nacos和使用Eureka对于微服务来说,并没有太大区别。
Nacos的服务类型分为两类:
-
临时实例:如果实例宕机超过一定时间,会从服务列表剔除,默认的类型。
-
非临时实例:如果实例宕机,不会从服务列表剔除,也可以叫永久实例。
spring:
cloud:
nacos:
discovery:
ephemeral: false # 设置为非临时实例
Nacos与eureka的共同点
- 都支持服务注册和服务拉取
- 都支持服务提供者心跳方式做健康检测
Nacos与eureka的区别
- Nacos支持服务端主动检测提供者状态:临时实例采用心跳模式,非临时实例采用主动检测模式
- 临时实例心跳不正常会被剔除,非临时实例则不会被剔除
- Nacos支持服务列表变更的消息推送模式,服务列表更新更及时
- Nacos集群默认采用AP方式,当集群中存在非临时实例时,采用CP模式;Eureka采用AP方式
二、Nacos注册中心
- 1)引入依赖
//父工程中引入SpringCloudAlibaba的依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.6.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
//引入nacos-discovery依赖:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
- 2)配置nacos地址
//application.yml中添加nacos地址:
spring:
cloud:
nacos:
server-addr: localhost:8848
- 3)重启微服务,登录nacos管理界面
三、服务分级存储模型
1).集群
一个服务可以包含多个集群,每个集群下可以有多个实例,形成分级模型,如图:
微服务互相访问时,应该尽可能访问同集群实例,因为本地访问速度更快。当本集群内不可用时,才访问其它集群。
- 配置集群: 修改application.yml文件,添加集群配置
spring:
cloud:
nacos:
server-addr: localhost:8848
discovery:
cluster-name: HN # 集群名称
- 权重配置
在实际部署项目中,服务器性能存在差异,默认情况下NacosRule是同集群随机选择,Nacos提供了通过配置权重来控制访问频率,权重越大访问频率越高。
2).环境隔离
Nacos提供了namespace来实现环境隔离功能
- nacos中可以有多个namespace
- namespace下可以有group、service等
- 不同namespace之间相互隔离,例如不同namespace的服务互相不可见
- 给微服务配置namespace
//yml文件中添加
namespace: 492a7d5d-237b-46a1-a99a-fa8e98e4b0f9 # 命名空间,填ID
四.Nacos配置管理
1)统一配置管理
从微服务拉取配置
微服务要拉取nacos中的配置信息,并且与本地yml文件中的配置合并才能完成项目启动。
spring引入了一种新的配置文件:bootstrap.yaml文件,会在application.yml之前被读取,流程如下:
- 引入依赖
<!--nacos配置管理依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
- 添加bootstrap.yml文件
spring:
application:
name: userservice # 服务名称
cloud: #nacos注册中心配置内容
nacos:
discovery:
server-addr: 192.168.94.129:8848
cluster-name: HZ
#开发环境的区别
namespace: 73be46a4-c53c-4b10-a68f-205698afef0e
#区分统一环境下的不同项目组
group: cloud_project
config:
server-addr: 192.168.94.129:8848
cluster-name: HZ
namespace: 73be46a4-c53c-4b10-a68f-205698afef0e
group: cloud_project
file-extension: yml
#修改日志级别,可以显示出读取的配置信息
logging:
level:
cn.itcast: debug
com:
alibaba:
cloud:
nacos:
client: debug
2)配置热更新
热更新的作用是在修改nacos的配置后,微服务不用重启也可以让配置生效。
- 方式1、在@Value注入的变量所在类上添加注解@RefreshScope:
@Slf4j
@RestController
@RequestMapping("/user")
@RefreshScope
public class UserController {
@Value("${pattern.dateformat}")
private String dateformat;
}
- 方式2、使用@ConfigurationProperties注解代替@Value注解。
在user-service服务中,添加一个类,读取patterrn.dateformat属性:
@Component
@Data
@ConfigurationProperties(prefix = "pattern")
public class PatternProperties {
private String dateformat;
}
在userController中替代@Value
@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private PatternProperties properties;
}
3)多环境支持
项目开发过程中,可能会存在多种环境,并且每一种环境所设置的配置都是不同的。nacos可以同时支持多环境配置,可以满足生产环境下的需求。
不同的开发环境:namespace 区分
不同的开发组:group 区分
不同的项目: dataid 区分
不同种类的配置:profile
在nacos配置中心中根据dataid进行区分即可。dataid 完整的拼接格式如下:
$ {prefix}-$ {spring.profiles.active}.${file-extension}
prefix
默认为spring.application.name
的值,也可以通过配置项spring.cloud.nacos.config.prefix
来配置。spring.profiles.active
即为当前环境对应的 profilefile-extension
为配置内容的数据格式,可以通过配置项spring.cloud.nacos.config.file-extension
来配置。
4)配置共享
微服务开发时,多个微服务中会配有相同的配置信息,造成配置冗余。
- 在nacos中添加配置
- 在bootstrap.yml中添加:
spring:
cloud:
nacos:
config:
shared-configs:
- dataId:
5)持久化配置
nacos对于服务的配置信息保存到了自己内部的数据库:derby,一般在开发环境下需要让nacos读取外部数据库配置信息,方便后期的维护:
- 1)新建数据库
- 2)进入nccos容器中
docker exec -it nacos /bin/bash
- 3)修改application.properties文件
spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://ip:3306/库名?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.user=
db.password=
- 4)重启nacos容器
五、Feign远程调用
Feign是一个声明式的http客户端,官方地址:https://github.com/OpenFeign/feign
Fegin的使用步骤如下:
- 1)引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
- 2)添加注解开启Feign功能
@EnableFeignClients
//开启全局日志记录
//@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration.class)
@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
- 3)编写FeignClient接口
- 4)使用FeignClient中定义的方法代替RestTemplate
1)Feign的自定义配置
类型 | 作用 | 说明 |
---|---|---|
feign.Logger.Level | 修改日志级别 | 包含四种不同的级别:NONE、BASIC、HEADERS、FULL |
feign.codec.Decoder | 响应结果的解析器 | http远程调用的结果做解析,例如解析json字符串为java对象 |
feign.codec.Encoder | 请求参数编码 | 将请求参数编码,便于通过http请求发送 |
feign. Contract | 支持的注解格式 | 默认是SpringMVC的注解 |
feign. Retryer | 失败重试机制 | 请求失败的重试机制,默认是没有,不过会使用Ribbon的重试 |
例:
- 日志配置方式1、配置文件方式
feign:
client:
config:
userservice: # 针对某个微服务的配置
// default: 这里用default就是全局配置
loggerLevel: FULL # 日志级别
//- NONE:不记录任何日志信息,这是默认值。
//- BASIC:仅记录请求的方法,URL以及响应状态码和执行时间
//- HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息
//- FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据。
- 方式2、代码格式
先声明一个类,并设置日志级别
public class DefaultFeignConfiguration {
@Bean
public Logger.Level feignLogLevel(){
return Logger.Level.BASIC; // 日志级别为BASIC
}
}
@EnableFeignClients
//开启全局日志记录
@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration.class)
@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
2)Feign使用优化
Feign底层发起http请求,依赖于其它的框架。其底层客户端实现包括:
•URLConnection:默认实现,不支持连接池
•Apache HttpClient :支持连接池
•OKHttp:支持连接池
优化Feign:
使用其他连接池代替URL默认
日志级别使用basic
例:
- 1)连接Apache HttpClient 引入依赖
<!--httpClient的依赖 -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
- 2)配置连接池信息
feign:
httpclient:
enabled: true # 开启feign对HttpClient的支持
max-connections: 200 # 最大的连接数
max-connections-per-route: 100 # 每个路径的最大连接数
六、Gateway服务网关
Spring Cloud Gateway 是 Spring Cloud 的一个全新项目,该项目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等响应式编程和事件流技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。
核心功能特性:
权限控制:网关作为微服务入口,需要校验用户是是否有请求资格,如果没有则进行拦截。
路由和负载均衡:一切请求都必须先经过gateway,但网关不处理业务,而是根据某种规则,把请求转发到某个微服务,这个过程叫做路由。当然路由的目标服务有多个时,还需要做负载均衡。
限流:当请求流量过高时,在网关中按照下流的微服务能够接受的速度来放行请求,避免服务压力过大。
在SpringCloud中网关的实现包括两种:
- gateway
- zuul
Zuul是基于Servlet的实现,属于阻塞式编程。而SpringCloudGateway则是基于Spring5中提供的WebFlux,属于响应式编程的实现,具备更好的性能。
1)gateway入门操作
- 1)引入依赖
<!--网关-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--nacos服务发现依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
- 2)编写启动类
- 3)编写yml文件,(基本服务信息,nacos地址,路由等)
server:
port: 10010 # 网关端口
spring:
application:
name: gateway # 服务名称
cloud:
nacos:
server-addr: localhost:8848 # nacos地址
gateway:
routes: # 网关路由配置
- id: user-service # 路由id,自定义,只要唯一即可
# uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址
uri: lb://userservice # 路由的目标地址 lb就是负载均衡,后面跟服务名称
predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
- Path=/user/** # 这个是按照路径匹配,只要以/user/开头就符合要求
# 全局的跨域处理
globalcors:
add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
corsConfigurations:
'[/**]':
allowedOrigins:
- "http://localhost:9001"
- "http://localhost:9002"
- "http://127.0.0.1:9001"
- "http://127.0.0.1:9002"
allowedMethods: # 允许的跨域ajax的请求方式
- "GET"
- "POST"
- "DELETE"
- "PUT"
- "OPTIONS"
allowedHeaders: "*" # 允许在请求中携带的头信息
allowCredentials: true # 是否允许携带cookie
maxAge: 360000 # 这次跨域检测的有效期
访问流程如下
2)断言工厂
yml配置文件中的断言规则是会被Predicate Factory读取处理,转换为路由判断的条件。
例:
名称 | 说明 | 示例 |
---|---|---|
After | 是某个时间点后的请求 | - After=2037-01-20T17:42:47.789-07:00[America/Denver] |
Before | 是某个时间点之前的请求 | - Before=2031-04-13T15:14:47.433+08:00[Asia/Shanghai] |
Between | 是某两个时间点之前的请求 | - Between=2037-01-20T17:42:47.789-07:00[America/Denver], 2037-01-21T17:42:47.789-07:00[America/Denver] |
Cookie | 请求必须包含某些cookie | - Cookie=chocolate, ch.p |
Header | 请求必须包含某些header | - Header=X-Request-Id, \d+ |
Host | 请求必须是访问某个host(域名) | - Host=.somehost.org,.anotherhost.org |
Method | 请求方式必须是指定方式 | - Method=GET,POST |
Path | 请求路径必须符合指定规则 | - Path=/red/{segment},/blue/** |
Query | 请求参数必须包含指定参数 | - Query=name, Jack或者- Query=name |
RemoteAddr | 请求者的ip必须是指定范围 | - RemoteAddr=192.168.1.1/24 |
Weight | 权重处理 |
3)过滤器工厂:
Spring提供了31种不同的路由过滤器工厂。
例:
名称 | 说明 |
---|---|
AddRequestHeader | 给当前请求添加一个请求头 |
RemoveRequestHeader | 移除请求中的一个请求头 |
AddResponseHeader | 给响应结果中添加一个响应头 |
RemoveResponseHeader | 从响应结果中移除有一个响应头 |
RequestRateLimiter | 限制请求的流量 |
例:
- 修改yml添加过滤器配置:
filters: # 过滤器 对当前路由的请求生效
- AddRequestHeader=Truth, Itcast is freaking awesome! # 添加请求头
//default-filters: # 默认过滤项 对所有路由生效
-
4)全局过滤器:
全局过滤器的作用和GatewayFilter的作用一样,不过处理逻辑需要自己定义。
实现方法是实现GlobaFilter接口。
例:
//过滤器的执行顺序,order值一样时,会按照 defaultFilter > 路由过滤器 > GlobalFilter的顺序执行。
@Order(-1)
@Component
public class AuthorizeFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1.获取请求参数
MultiValueMap<String, String> params = exchange.getRequest().getQueryParams();
// 2.获取authorization参数
String auth = params.getFirst("authorization");
// 3.校验
if ("admin".equals(auth)) {
// 放行
return chain.filter(exchange);
}
// 4.拦截
// 4.1.禁止访问,设置状态码
exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
// 4.2.结束处理
return exchange.getResponse().setComplete();
}
}
5)跨域问题:
跨域问题:协议,域名,端口三者中任意一者不同即为跨域。浏览器禁止请求的发起者与服务端发生跨域ajax请求,请求被浏览器拦截的问题
解决方式:yml文件中添加以下配置
spring:
cloud:
gateway:
# 。。。
globalcors: # 全局的跨域处理
add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
corsConfigurations:
'[/**]':
allowedOrigins: "*" # 允许哪些网站的跨域请求
allowedMethods: # 允许的跨域ajax的请求方式
- "GET"
- "POST"
- "DELETE"
- "PUT"
- "OPTIONS"
allowedHeaders: "*" # 允许在请求中携带的头信息
allowCredentials: true # 是否允许携带cookie
maxAge: 360000 # 这次跨域检测的有效期