微服务治理
认识微服务
服务架构演变
单体架构
单体架构:将业务的所有功能集中在一个项目中开发,打成一个包部署。
优点:架构简单、部署成本低
缺点:耦合度高
分布式架构
分布式架构:根据业务功能对系统进行拆分,每个业务模块作为独立项目开发,称为一个服务。
优点:降低服务耦合、有利于服务升级拓展
缺点:架构复杂,难度大
微服务
微服务是一种经过良好架构设计的分布式架构方案,微服务架构特征:
- 单一职责:微服务拆分粒度更小,每一个服务都对应唯一的业务能力,做到单一职责,避免重复业务开发
- 面向服务:微服务对外暴露业务接口
- 自治:团队独立、技术独立、数据独立、部署独立
- 隔离性强:服务调用做好隔离、容错、降级,避免出现级联问题
微服务技术对比
微服务结构
微服务技术对比
Dubbo | SpringCloud | SpringCloudAlibaba | |
---|---|---|---|
注册中心 | zookeeper、Redis | Eureka、Consul | Nacos、Eureka |
服务远程调用 | Dubbo协议 | Feign(http协议) | Dubbo、Feign |
配置中心 | 无 | SpringCloudConfig | SpringCloudConfig、Nacos |
服务网关 | 无 | SpringCloudGateway、Zuul | SpringCloudGateway、Zuul |
服务监控和保护 | dubbo-admin,功能弱 | Hystix | Sentinel |
企业需求
1、SpringCloud + Feign
- 使用SpringCloud技术栈
- 服务接口采用Restful风格
- 服务调用采用Feign方式
2、SpringCloudAlibaba + Feign
- 使用SpringCloudAlibaba技术栈
- 服务接口采用Restful风格
- 服务调用采用Feign方式
3、SpringCloudAlibaba + Dubbo
- 使用SpringCloudAlibaba技术栈
- 服务接口采用Dubbo协议标准
- 服务调用采用Dubbo方式
4、Dubbo原始模式
- 基于Dubbo老旧技术体系
- 服务接口采用Dubbo协议标准
- 服务调用采用Dubbo方式
SpringCloud
SpringCloud集成了各种微服务功能组件,并基于SpringBoot实现了这些组件的自动装配,从而提供了良好的开箱即用体验
SpringCloud与SpringBoot的版本兼容关系
服务拆分及远程调用
服务拆分
- 单一职责:不同微服务,不要重复开发相同业务
- 数据独立:不要访问其它微服务的数据库
- 面向服务:将自己的业务暴露为接口,供其它微服务调用
服务间调用
RestTemplate
1、注册RestTemplate
在Application中注册RestTemplate
@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
2、在Service中使用RestTemplate
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private RestTemplate restTemplate;
public Order queryOrderById(Long orderId) {
Order order = orderMapper.findById(orderId);
String url = "http://127.0.0.1:8080/user/" + order.getUserId();
User user = restTemplate.getForObject(url, User.class);
order.setUser(user);
return order;
}
}
提供者与消费者
服务提供者:被其它微服务调用的服务。(提供接口给其它微服务)
服务消费者:调用其它微服务的服务。(调用其它微服务提供的接口)
- 提供者与消费者角色其实是相对的
- 一个服务可以同时是服务提供者和服务消费者
Eureka注册中心
Eureka作用
EurekaServer:,注册中心
- 记录服务信息
- 心跳监控
EurekaClient:客户端
- Provider:服务提供者,例如案例中的 user-service
- 注册自己的信息到EurekaServer
- 每隔30秒向EurekaServer发送心跳
- consumer:服务消费者,例如案例中的 order-service
- 根据服务名称从EurekaServer拉取服务列表
- 基于服务列表做负载均衡,选中一个微服务后发起远程调用
消费者该如何获取服务提供者具体信息?
- 服务提供者启动时向eureka注册自己的信息
- eureka保存这些信息
- 消费者根据服务名称向eureka拉取提供者信息
如果有多个服务提供者,消费者该如何选择?
- 服务消费者利用负载均衡算法,从服务列表中挑选一个
消费者如何感知服务提供者健康状态?
- 服务提供者会每隔30秒向EurekaServer发送心跳请求,报告健康状态
- eureka会更新记录服务列表信息,心跳不正常会被剔除
- 消费者就可以拉取到最新的信息
搭建EurekaServer
1、创建新模块
2、引入依赖
需要JDK8版本
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
3、创建启动类
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
4、编辑配置
server:
port: 10086
spring:
application:
name: eurekasever
eureka:
client:
service-url:
# 服务注册:把自己注册到euraka
defaultZone: http://127.0.0.1:10086/eureka
5、打开eureka页面查看注册列表
注册service
1、引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2、添加相关配置
name属性不能有下划线
spring:
application:
name: orderservice
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
3、打开eureka页面查看服务列表
可以将启动多个service, 模拟多实例部署,但为了避免端口冲突,需要修改端口设置。
在Eureka服务列表中可以看到部署的多个实例。
服务拉取
服务拉取:基于服务名称获取服务列表,然后在对服务列表做负载均衡
1、修改OrderService的代码,修改访问的url路径,用服务名代替ip、端口
public Order queryOrderById(Long orderId) {
Order order = orderMapper.findById(orderId);
String url = "http://user_service/user/" + order.getUserId();
User user = restTemplate.getForObject(url, User.class);
order.setUser(user);
return order;
}
2、order-service项目的启动类OrderApplication中的RestTemplate添加负载均衡注解
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
Ribbon负载均衡
负载均衡流程
负载均衡策略
Ribbon的负载均衡规则是一个叫做IRule的接口来定义的,每一个子接口都是一种规则
通过定义IRule实现可以修改负载均衡规则
1、代码方式
@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
@Bean
public IRule randomRule() {
return new RandomRule();
}
}
2、配置方式
userservice:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡规则
饥饿加载
Ribbon默认是采用懒加载,即第一次访问时才会去创建LoadBalanceClient,请求时间会很长。
饥饿加载则会在项目启动时创建,降低第一次访问的耗时。
ribbon:
eager-load:
enabled: true
clients:
- userservice
Nacos注册中心
安装Nacos
Nacos是阿里巴巴的产品,现在是SpringCloud中的一个组件。相比Eureka功能更加丰富,在国内受欢迎程度较高。
解压安装包,在nacos/bin目录中,输入命令启动Nacos。
# Win
startup.cmd -m standalone
# 类Unix
sh startup.sh -m standalone
打开控制台页面
注册到Nacos
1、在父工程添加依赖
<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>
2、在客户端添加z依赖
<!-- nacos客户端依赖包 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
3、修改客户端配置
spring:
cloud:
nacos:
server-addr: http://127.0.0.1:8848/
Nacos服务分级存储模型
模型分层:服务 → 集群 → 实例
服务调用尽可能选择本地集群的服务,跨集群调用延迟较高。在本地集群不可访问时,再去访问其它集群。
配置集群信息
spring:
cloud:
nacos:
server-addr: localhost:8848
discovery:
cluster-name: TS
根据权重进行负载均衡:
1、在Nacos控制台可以设置实例的权重值,首先选中实例后面的编辑按钮
2、将权重设置为0.1,测试可以发现8081被访问到的频率大大降低
环境隔离
Nacos中服务存储和数据存储的最外层都是一个名为namespace的东西,用来做最外层隔离
可以用来隔离生产环境和开发环境等
1、在Nacos控制台可以创建namespace,用来隔离不同环境
2、然后填写一个新的命名空间信息
3、保存后会在控制台看到这个命名空间的id
5、修改order-service的application.yml,添加namespace
spring:
cloud:
nacos:
server-addr: localhost:8848
discovery:
cluster-name: TS
namespace: 492a7d5d-237b-46a1-a99a-fa8e98e4b0f9 # 命名空间,填ID
6、重启order-service后,再来查看控制台:
7、此时访问order-service,因为namespace不同,会导致找不到userservice,控制台会报错
临时实例和非临时实例
Nacos支持服务端主动检测提供者状态:
- 临时实例采用心跳模式,非临时实例采用主动检测模式
- 临时实例心跳不正常会被剔除,非临时实例则不会被剔除
spring:
cloud:
nacos:
server-addr: localhost:8848
discovery:
cluster-name: TS
# 是否为临时实例
ephemeral: false
Nacos与Eureka对比
- Nacos支持服务列表变更的消息推送模式,服务列表更新更及时
- Nacos集群默认采用AP方式,当集群中存在非临时实例时,采用CP模式;Eureka采用AP方式