Skip to content

微服务治理

认识微服务

服务架构演变

单体架构

单体架构:将业务的所有功能集中在一个项目中开发,打成一个包部署。

优点:架构简单、部署成本低

缺点:耦合度高

image-20240216105242865

分布式架构

分布式架构:根据业务功能对系统进行拆分,每个业务模块作为独立项目开发,称为一个服务。

优点:降低服务耦合、有利于服务升级拓展

缺点:架构复杂,难度大

微服务

微服务是一种经过良好架构设计的分布式架构方案,微服务架构特征:

  1. 单一职责:微服务拆分粒度更小,每一个服务都对应唯一的业务能力,做到单一职责,避免重复业务开发
  2. 面向服务:微服务对外暴露业务接口
  3. 自治:团队独立、技术独立、数据独立、部署独立
  4. 隔离性强:服务调用做好隔离、容错、降级,避免出现级联问题

微服务技术对比

微服务结构

image-20240216110317964

微服务技术对比

DubboSpringCloudSpringCloudAlibaba
注册中心zookeeper、RedisEureka、ConsulNacos、Eureka
服务远程调用Dubbo协议Feign(http协议)Dubbo、Feign
配置中心SpringCloudConfigSpringCloudConfig、Nacos
服务网关SpringCloudGateway、ZuulSpringCloudGateway、Zuul
服务监控和保护dubbo-admin,功能弱HystixSentinel

企业需求

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实现了这些组件的自动装配,从而提供了良好的开箱即用体验

image-20240217111431381

SpringCloud与SpringBoot的版本兼容关系

image-20240217111438305

服务拆分及远程调用

服务拆分

  1. 单一职责:不同微服务,不要重复开发相同业务
  2. 数据独立:不要访问其它微服务的数据库
  3. 面向服务:将自己的业务暴露为接口,供其它微服务调用

image-20240217112154444

服务间调用

RestTemplate

1、注册RestTemplate

在Application中注册RestTemplate

java
@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

java
@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:,注册中心

  1. 记录服务信息
  2. 心跳监控

EurekaClient:客户端

  1. Provider:服务提供者,例如案例中的 user-service
    1. 注册自己的信息到EurekaServer
    2. 每隔30秒向EurekaServer发送心跳
  2. consumer:服务消费者,例如案例中的 order-service
    1. 根据服务名称从EurekaServer拉取服务列表
    2. 基于服务列表做负载均衡,选中一个微服务后发起远程调用

消费者该如何获取服务提供者具体信息?

  1. 服务提供者启动时向eureka注册自己的信息
  2. eureka保存这些信息
  3. 消费者根据服务名称向eureka拉取提供者信息

如果有多个服务提供者,消费者该如何选择?

  1. 服务消费者利用负载均衡算法,从服务列表中挑选一个

消费者如何感知服务提供者健康状态?

  1. 服务提供者会每隔30秒向EurekaServer发送心跳请求,报告健康状态
  2. eureka会更新记录服务列表信息,心跳不正常会被剔除
  3. 消费者就可以拉取到最新的信息

搭建EurekaServer

1、创建新模块

image-20240217133042038

2、引入依赖

需要JDK8版本

xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

3、创建启动类

image-20240217134945127
java
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication.class, args);
    }
}

4、编辑配置

yaml
server:
  port: 10086
spring:
  application:
    name: eurekasever
eureka:
  client:
    service-url:
      # 服务注册:把自己注册到euraka
      defaultZone: http://127.0.0.1:10086/eureka

5、打开eureka页面查看注册列表

注册service

1、引入依赖

xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

2、添加相关配置

name属性不能有下划线

yaml
spring:
  application:
    name: orderservice
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka

3、打开eureka页面查看服务列表

可以将启动多个service, 模拟多实例部署,但为了避免端口冲突,需要修改端口设置。

在Eureka服务列表中可以看到部署的多个实例。

服务拉取

服务拉取:基于服务名称获取服务列表,然后在对服务列表做负载均衡

1、修改OrderService的代码,修改访问的url路径,用服务名代替ip、端口

java
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添加负载均衡注解

java
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
    return new RestTemplate();
}

Ribbon负载均衡

负载均衡流程

image-20240220201328984

负载均衡策略

Ribbon的负载均衡规则是一个叫做IRule的接口来定义的,每一个子接口都是一种规则

image-20240220201608194

通过定义IRule实现可以修改负载均衡规则

1、代码方式

java
@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、配置方式

yaml
userservice:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡规则

饥饿加载

Ribbon默认是采用懒加载,即第一次访问时才会去创建LoadBalanceClient,请求时间会很长。

饥饿加载则会在项目启动时创建,降低第一次访问的耗时。

yaml
ribbon:
  eager-load:
    enabled: true
    clients:
      - userservice

Nacos注册中心

安装Nacos

Nacos是阿里巴巴的产品,现在是SpringCloud中的一个组件。相比Eureka功能更加丰富,在国内受欢迎程度较高。

解压安装包,在nacos/bin目录中,输入命令启动Nacos。

shell
# Win
startup.cmd -m standalone
# 类Unix
sh startup.sh -m standalone

打开控制台页面

image-20240217212921125

注册到Nacos

1、在父工程添加依赖

xml
<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依赖

xml
<!-- nacos客户端依赖包 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

3、修改客户端配置

yaml
spring:
  cloud:
    nacos:
      server-addr: http://127.0.0.1:8848/

Nacos服务分级存储模型

模型分层:服务 → 集群 → 实例

服务调用尽可能选择本地集群的服务,跨集群调用延迟较高。在本地集群不可访问时,再去访问其它集群。

配置集群信息

yaml
spring:
  cloud:
    nacos:
      server-addr: localhost:8848
      discovery:
        cluster-name: TS

根据权重进行负载均衡:

1、在Nacos控制台可以设置实例的权重值,首先选中实例后面的编辑按钮

image-20240219201820804

2、将权重设置为0.1,测试可以发现8081被访问到的频率大大降低

image-20240219201826362

环境隔离

Nacos中服务存储和数据存储的最外层都是一个名为namespace的东西,用来做最外层隔离

image-20240219201937866

可以用来隔离生产环境和开发环境等

1、在Nacos控制台可以创建namespace,用来隔离不同环境

image-20240219202034546

2、然后填写一个新的命名空间信息

image-20240219202052383

3、保存后会在控制台看到这个命名空间的id

image-20240219202103993

5、修改order-service的application.yml,添加namespace

yaml
spring:
  cloud:
    nacos:
      server-addr: localhost:8848
      discovery:
        cluster-name: TS
        namespace: 492a7d5d-237b-46a1-a99a-fa8e98e4b0f9 # 命名空间,填ID

6、重启order-service后,再来查看控制台:

image-20240219202158589

7、此时访问order-service,因为namespace不同,会导致找不到userservice,控制台会报错

image-20240219202206290

临时实例和非临时实例

Nacos支持服务端主动检测提供者状态:

  1. 临时实例采用心跳模式,非临时实例采用主动检测模式
  2. 临时实例心跳不正常会被剔除,非临时实例则不会被剔除
yaml
spring:
  cloud:
    nacos:
      server-addr: localhost:8848
      discovery:
        cluster-name: TS
        # 是否为临时实例
        ephemeral: false

Nacos与Eureka对比

  • Nacos支持服务列表变更的消息推送模式,服务列表更新更及时
  • Nacos集群默认采用AP方式,当集群中存在非临时实例时,采用CP模式;Eureka采用AP方式

Released under the MIT License.