** 微服务 **
01 认识 微服务
- 服务架构演变
- SpringCloud
1.单体架构
将 业务 的 所有 功能 集中 在 一个 项目 中 开发 , 打成 一个 包 部署。
优点:架构简单 , 部署成本低
缺点: 耦合度高
2. 分布式架构
根据 业务功能 对 系统 进行 拆分 ,每个 业务 模块 作为 独立项目 开发, 称为 一个 服务。
优点: 降低服务耦合,有利于服务升级拓展
3.微服务
微服务 是 一种 经过 良好 架构设计 的 分布式 架构 方案, 微服务 架构 特征 :
- 单一职责 : 微服务 拆分粒度 更小 ,每一个 服务 都对应 唯一的 业务能力 , 做到 单一职责 ,避免 重复业务开发
- 面向服务: 微服务 对外 暴露 业务接口
- 自治: 团队独立 , 技术独立, 数据独立,部署独立。
- 隔离性强:服务调用 做好隔离, 容错, 降级, 避免 出现 级联问题。
2. 服务拆分 及 远程调用
- 服务拆分
- 服务间 调用
服务拆分 注意事项
- 不同 微服务, 不要 重复 开发 相同业务
- 微服务 数据独立 ,不要 访问 其他 微服务的 数据库
- 微服务 可以 将 自己 的 业务 暴露 为接口, 供 其他 微服务 调用
3. 远程 调用 分析
@Autowired
private RestTemplate restTemplate;
//利用RestTemplate 发起http请求,查询用户
restTemplate.postForObject();//post请求
restTemplate.getForObject();//get请求
//利用RestTemplate 发起http请求,查询用户
//1. url 路径
String url="http://localhost:8081/user"+ order.getUserId();
//2.发送请求
User user= restTemplate.getForObject(url, User.class);//get请求
//封装user到Order
order.setUser(user);
//返回
return order;
4. 提供者 和 消费者
一个 服务 既可以 是 消费者 也可以 是 提供者 。( 以业务为准)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OeJQMuaU-1636935929599)(C:\Users\城市\AppData\Roaming\Typora\typora-user-images\1636640304918.png)]
5. Eureka 注册中心
- 远程调用问题
- eureka原理
- 搭建 EurekaServer
- 服务注册
- 服务发现
Eureka 作用:
- 注册服务信息
- 拉取服务 信息
- 负载均衡
- 远程调用
- 使用 心跳监控 判断 服务 是否 存活
-
消费者 该如何 获取 服务 提供者 具体信息?
-
服务提供者 启动 时 向 eureka 注册 自己的信息
-
eureka 保存这些 信息
-
消费者 根据 服务名称 向 eureka 拉取 提供者信息
-
-
如果有 多个 服务提供者 , 消费者 该 如何 选择?
- 服务消费者 利用 负载均衡 算法 ,从 服务 列表 中 挑选 一个
-
消费者 如何 感知 服务 提供者 健康状态?
- 服务提供者 会 每隔 30秒 向 eurekaServer 发送 心跳请求 , 报告 健康状态
- eureka 会 更新 记录 服务列表 信息, 心跳 不正常 会被 剔除
- 消费者 就可以 拉取到 最新的 信息
5.1 服务端配置
1.启动类配置
@EnableEurekaServer
@SpringBootApplication
public class EurekaApplication {
public static void main(String[] args){
SpringApplication.run(EurekaApplication.class,args);
}
}
2.导入依赖
<!--eureka服务端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
3.配置文件
server:
port: 10086 # 服务端口
spring:
application:
name: eurekaserver # eureka的服务名称
eureka:
client:
service-url: # eureka的地址信息
defaultZone: http://127.0.0.1:10086/eureka
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aeEaAfHq-1636935929601)(C:\Users\城市\AppData\Roaming\Typora\typora-user-images\1636642899040.png)]
5.2 客户端配置
<!--eureka客户端依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
spring:
application:
name: userservice # userservice的服务名称
eureka:
client:
service-url: # eureka的地址信息
defaultZone: http://127.0.0.1:10086/eureka
String url="http://userservice/user"+ order.getUserId();
@Bean
@LoadBalanced //负载均衡注解
public RestTemplate restTemplate(){
return new RestTemplate();
}
6. Ribbon 负载均衡
- 负载均衡原理
- 负载均衡策略
- 懒加载
负载均衡流程 :
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5xgcF6u5-1636935929603)(C:\Users\城市\AppData\Roaming\Typora\typora-user-images\1636790776578.png)]
<重点流程>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wN0gFqG2-1636935929604)(C:\Users\城市\AppData\Roaming\Typora\typora-user-images\1636790776578.png)]
负载均衡策略 :
Ribbon 的 负载 均衡 规则 是 一个 叫做 IRule 的 接口 来定义, 每一个 子接口 都是 一种 规则。
具体策略 :(7种)
配置负载均衡规则
通过定义 IRule 实现 修改 负载均衡规则的 两种方法 :
- 代码方法 设置 Bean 实现 (服务范围 : 全局)
@Bean
public IRule randomRule(){
//可以通过 return new 6种 策略
return new RandomRule();
}
- 基于 配置文件 配置 ( 服务范围 : 某个 微服务的)
饥饿加载
Ribbon 默认 是采用 懒加载, 即 第一次 访问 才会 去 创建 LoadBalanceClient , 请求时间 很长。
而 饥饿加载 会在 项目 启动的 时候 创建 ,降低 第一次 访问的 耗时 , 通过配置 开启 饥饿 加载。
7. Nacos 注册中心
- 认识和 安装 Nacos
- Nacos 快速入门
- Nacos 服务分级 存储模型
- Nacos 环境隔离
Nacos 是 阿里巴巴的产品, 现在是 Spring Cloud 的产品。
进入 bin目录下输入
开启命令
startup.cmd -m standalone
http://127.0.0.1:8848/nacos/index.html
默认 账号密码 nacos nacos;
Nacos 配置流程:
<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>
<!-- nacos客户端依赖包 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
配置
spring:
cloud:
nacos:
server-addr: localhost:8848 #nacos服务地址
Nacos 服务分级存储模型
一个服务 可以 包含 多个 实例
服务跨 集群 调用 问题
-
服务调用 尽可能 选择 本地集群的 服务 ,跨集群 调用 延迟 较高
-
本地集群不可用的情况下, 再去 访问 其他集群
**服务集群 属性 **
spring:
cloud:
nacos:
server-addr: localhost:8848 #nacos服务地址
discovery:
cluster-name: GD #集群名称
根据集群 负载均衡
userservice:
ribbon:
NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule
Nacos 负载均衡策略
-
- 优先选择 同 集群服务实例列表
-
- 本地集群 找不到 提供者 ,才去 其他集群 寻找 , 并且 会 报警告
-
- 确定了 可用实例 列表 后 , 在 采用 随机 负载均衡 挑选 实例
Nacos 根据 权重 负载均衡
解决办法 : Nacos 提供了 权重配置 来 控制 访问频率 , 权重 越大 则 访问 频率 越高
注意 权重为0 时候, 服务 将不会 被访问。
操作 办法 :
- 直接 页面控制
**总结 **: 实例的 权重 设置
- Nacos 控制台 可以 设置 实例的权重值, 0-1之间
- 同集群 内的 多个 实例, 权重 越高 被访问 的 频率 越高
- 权重 设置 为 0 则 完全不会被访问
Nacos 环境隔离
— namespace
Nacos 中 服务 存储 和 数据存储 的 最外层 都是 一个 名为 namespace 的 东西 ,用来做 最外层隔离
创建步骤 :
namespace: 5246f234-7a6a-4d7b-8cd4-060708b14916 #命名空间 填入 ID
java.lang.IllegalStateException: No instances available for userservice 设置了命名空间不一致,导致的异常
Nacos注册中心细节分析
ephemeral: false #默认为true 是否为临时实例
8.Nacos 和 Eureka 的 比对
注意: 服务消费者 在每次拉取 pull 成功的时候 都会 产生 一个 服务列表缓存 拉取数据,每隔 30秒 重新拉取并更新 缓存
差别: 服务调用者的 健康检测 , Nacos 会把服务提供者 划分成 临时实例 和 非临时实例;默认 所有的实例为 临时实例。
临时实例的 健康检测 : 采用 心跳检测,与 Eureka 的 心跳检测 一致,频率不一致, Eureka 快点;
非临时实例 的 健康 检测 : Nacos 主动 发送请求 询问 服务 提供者 是否 存活。
Nacos 不会把非临时实例剔除,只会 等待 非临时实例 恢复
服务消费者 :
Eureka 采取的 是 定时 拉取;更新的效率 差 ,不知道 服务提供者是否 宕机。
Nacos 采取的 是 主动 推送变更消息 push,如果 发现 服务提供者 宕机 会 立即 发送信息给 服务消费者 它已经宕机,服务开始变更 ,请及时更新。
9. Nacos 配置管理
- 统一配置管理
- 配置 热更新
- 配置 共享
- 搭建 Nacos 集群
统一配置管理
- 配置 更改 热更新
配置流程:
1.在 Nacos 中 添加 配置信息
2.在 弹出 表单中 填写 配置信息
正常 读取 配置 文件 步骤:
项目启动 —> 读取 本地 配置文件 (yml) --> 创建 Spring容器 —> 加载 bean
bootstrap.yml — > nacos中的配置文件 —> 本地配置文件
配置拉取:
<!--nacos配置管理依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
bootstrap.yml
spring:
application:
name: userservice
profiles:
active: dev #开发环境
cloud:
nacos:
server-addr: localhost:8848 # nacos地址
config:
file-extension: yaml #文件后缀名
@Value("${pattern.dateformat}")
private String dateformat;
@GetMapping("now")
public String now(){
return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateformat, Locale.CHINA));
}
配置热更新
-
配置自动刷新
Nacos 中的 配置文件 变更后, 微服务 无需重启 就可以 感知。
-
两种 配置方式:
-
-
在 @Value 注入的 变量 所在 类 上 添加 注解 @RefreshScope
@Value("${pattern.dateformat}")private String dateformat;
-
-
- 使用 @ConfigurationProperties 注解
@Component @ConfigurationProperties(prefix = "pattern") @Data public class PropertiesConfig { private String dateformat; } } @Autowired private PropertiesConfig propertiesConfig; propertiesConfig.getDateformat()
-
多环境配置共享
微服务 之间的 配置共享 问题
多种 配置下 的 优先级 :
-
服务名- profile.yaml > 服务名称 .yml > 本地配置
Nacos 集群
Nacos 生产环境下 一定 要部署 成 集群环境。
10. HTTP 客户端 Fegin
- Fegin代替 RestTemplate
- 自定义配置
- Fegin 使用优坏
- 最佳实践
RestTemplate 方式 调用 存在的 问题
Fegin 介绍 :
Fegin 是 一个 声明式的 http 客户端 , 其 作用 就是 帮助 我们 优雅 的 实现 http 请求的 发送。
官方地址:https://github.com/OpenFeign/feign
使用 Fegin 步骤:
<!--feign 客户端依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
@EnableFeignClients //启动类添加这个注解
/**
* date 2021/11/1422:24
*
* @author mzr
* @target :user客户端
**/
@FeignClient("userservice")
public interface UserClients {
@GetMapping("/user/{id}")
User findById(@PathVariable("id") Long id);
}
@Autowired
private UserClients userClients;
@GetMapping("{orderId}")
public Order queryOrderByUserId(@PathVariable("orderId") Long orderId) {
// 根据id查询订单并返回
final Order order = orderService.queryOrderById(orderId);
//使用Feign 远程调用
final User user = userClients.findById(orderId);
//封装user到Order
order.setUser(user);
//返回
return order;
}
自定义 Feign 的 配置
两种配置 方式 : 1. 配置文件 2. java代码
feign.client.config.default.logger-level=FUll
Fegin 性能优化
Fegin — 连接池 配置
Fegin 的 最佳实践
11. 统一网关 Gateway
- 为什么需要网关
- gateway 快速入门
- 断言工厂
- 过滤器工厂
- 全局过滤器
- 跨域问题
1.为什么需要网关
2. 网关 技术实现
基于 Springcloud 的 网关 实现 两种:
- gateway (推荐)
- zuul
Zuul 基于 Servlet 实现 , 属于 阻塞式 编程。
SpringcloudGateway 基于 Spring5 中 提供 的 webflux, 属于 响应式编程, 性能更好。