微服务-SpringCloud

SpringCloud 是目前国内使用最广泛的微服务框架。SpringCloud 集成了各种微服务功能组件,并基于 SpringBoot 实现了这些组件的自动装配,从而提供了良好的开箱即用体验。官网地址:https://spring.io/projects/spring-cloud

文章目录

前言

一、含义

二、单体架构&微服务

1.什么是单体架构

2.什么是微服务架构

3.微服务的拆分原则

4.微服务的拆分方式

三、远程调用---RestTemplate

1.注入RestTemplate到Spring容器

2.发起远程调用

四、服务治理

1.服务治理中的三个角色

 2.注册中心原理

3.服务注册

(1)添加依赖

(2)application.yml中添加nacos地址配置:

4.服务发现

(1)添加依赖 

(2)配置nacos地址

(3)服务发现

五、OpenFeign

1.快速入门

(1)引入依赖

(2)启用OpenFeign

(3)编写OpenFeign客户端

(4)使用FeignClient

2.连接池---OKHttp

(1)引入依赖

(2)开启连接池

3.最佳实践

(1)抽取Feign客户端

(2)然后把需要用到的实体类放在一个包里

(3)扫描包

4.日志配置

(1)OpenFeign的日志级别

(2)定义日志级别

(3)配置

六、网关

1.含义

2.快速入门

(1)创建项目添加依赖

(2)新建启动类

(3)配置application.yml

(4)路由过滤

3.配置热更新

七、服务保护

1.雪崩问题

2.保护方案

(1)请求限流

(2)线程隔离

(3)服务熔断

3.服务保护技术 --- Sentinel

(1)安装

(2)OpenFeign整合Sentinel

八、分布式事务

1.含义

2.seata

(1)安装

(2)架构

(3)XA 模式

(4)AT模式

(5)AT 模式与 XA 模式最大的区别是什么


前言

之前我们学习的项目都是单体架构项目,可以满足小型项目或传统项目的开发。而在互联网时代,越来越多的一线互联网公司都在使用微服务技术。从谷歌搜索指数来看,国内从自2016年底开始,微服务热度突然暴涨。


一、含义

微服务是一种软件架构风格,它是以专注于单一职责的很多小型项目为基础,组合出复杂的大型应用。

二、单体架构&微服务

1.什么是单体架构

含义:单体架构就是将所有的项目集中在一个项目里开发,打成一个jar包部署

优点:

  • 架构简单
  • 部署成本低

缺点:

  • 团队协作成本高
  • 系统发布效率低
  • 系统可用性差

2.什么是微服务架构

微服务架构是服务化思想指导下的一套最佳实践架构方案。服务化就是把单体架构中的功能模块拆分为多个独立项目。

3.微服务的拆分原则

高内聚:每个微服务的职责要尽量单一,包含的业务相互关联度高、完整度高。
低耦合:每个微服务的功能要相对独立,尽量减少对其它微服务的依赖。

4.微服务的拆分方式

纵向拆分:按照业务模块来拆分
横向拆分:抽取公共服务,提高复用性

三、远程调用---RestTemplate

Spring给我们提供了一个RestTemplate工具,可以方便的实现Http请求的发送。使用步骤如下:

1.注入RestTemplate到Spring容器

package com.hmall.cart.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RemoteCallConfig {

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

}

2.发起远程调用

public <T> ResponseEntity<T> exchange(
	String url, // 请求路径
	HttpMethod method, // 请求方式
	@Nullable HttpEntity<?> requestEntity, // 请求实体,可以为空
 	Class<T> responseType, // 返回值类型
	Map<String, ?> uriVariables // 请求参数
)

注意:但是这种方法存在漏洞,如果恰巧远程调用的服务挂掉了那么当前方法的执行是不会通过的。

四、服务治理

1.服务治理中的三个角色

  • 服务提供者:暴露服务接口,供其它服务调用
  • 服务消费者:调用其它服务提供的接口
  • 注册中心:记录并监控微服务各实例状态,推送服务变更信息

 2.注册中心原理

流程如下:

  • 服务启动时就会注册自己的服务信息(服务名、IP、端口)到注册中心

  • 调用者可以从注册中心订阅想要的服务,获取服务对应的实例列表(1个服务可能多实例部署)

  • 调用者自己对实例列表负载均衡,挑选一个实例

  • 调用者向该实例发起远程调用

当服务提供者的实例宕机或者启动新实例时,调用者如何得知呢?

  • 服务提供者会定期向注册中心发送请求,报告自己的健康状态(心跳请求)

  • 当注册中心长时间收不到提供者的心跳时,会认为该实例宕机,将其从服务的实例列表中剔除

  • 当服务有新实例启动时,会发送注册服务请求,其信息会被记录在注册中心的服务实例列表

  • 当注册中心服务列表变更时,会主动通知微服务,更新本地服务列表

3.服务注册

(1)添加依赖

​​​​​​​<!--nacos 服务注册发现--> 
<dependency> 
    <groupId>com.alibaba.cloud</groupId> 
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> 
</dependency>

(2)application.yml中添加nacos地址配置:

spring:
  application:
    name: item-service # 服务名称
  cloud:
    nacos:
      server-addr: 192.168.150.101:8848 # nacos地址

4.服务发现

消费者需要连接nacos以拉取和订阅服务,因此服务发现的前两步与服务注册是一样,后面再加上服务调用即可: 

(1)添加依赖 

​​​​​​​<!--nacos 服务注册发现--> 
<dependency> 
    <groupId>com.alibaba.cloud</groupId> 
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> 
</dependency>

(2)配置nacos地址

spring:
  application:
    name: item-service # 服务名称
  cloud:
    nacos:
      server-addr: 192.168.150.101:8848 # nacos地址

(3)服务发现

private final DiscoveryClient discoveryClient;
    private void handleCartItems(List<CartVO> vos) {
    // 1.根据服务名称,拉取服务的实例列表
    List<ServiceInstance> instances = discoveryClient.getInstances("item-service");
    // 2.负载均衡,挑选一个实例
    ServiceInstance instance = instances.get(RandomUtil.randomInt(instances.size()));
    // 3.获取实例的IP和端口
    URI uri = instance.getUri();
    // ...略
}

五、OpenFeign

1.快速入门

(1)引入依赖

在服务调用者的pom.xml中引入OpenFeign的依赖和LoadBalancer依赖:

  <!--openFeign-->
  <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-openfeign</artifactId>
  </dependency>
  <!--负载均衡器-->
  <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-loadbalancer</artifactId>
  </dependency>

(2)启用OpenFeign

在服务调用者的启动类上添加 @EnableFeignClients 注解,表示启动OpenFeign

(3)编写OpenFeign客户端

在服务调用者中定义一个新的接口,编写Feign客户端。其中代码如下:

package com.hmall.cart.client;

import com.hmall.cart.domain.dto.ItemDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;

@FeignClient("item-service") //生命服务名称
public interface ItemClient {

    @GetMapping("/items") //生命请求方式和请求路径
    List<ItemDTO> queryItemByIds(@RequestParam("ids") Collection<Long> ids);

}

(4)使用FeignClient

最后在服务调用者的ServiceImpl中直接调用ItemClient方法

2.连接池---OKHttp

(1)引入依赖

在服务调用者的pom.xml中引入依赖:

<!--OK http 的依赖 -->
<dependency>
  <groupId>io.github.openfeign</groupId>
  <artifactId>feign-okhttp</artifactId>
</dependency>

(2)开启连接池

在服务i调用者的application.yml配置文件中开启Feign的连接池功能:

feign:
  okhttp:
    enabled: true # 开启OKHttp功能

重启服务,连接池就生效了。

3.最佳实践

在写项目的过程中有可能会发生一个情况,就是同一个接口有可能会被多个微服务调用。那么为了避免重复编码,可以把这些重复代码抽取到一个单独的模块中

(1)抽取Feign客户端

在项目下定义一个新的module并为它设置名称,其依赖如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>hmall</artifactId>
        <groupId>com.heima</groupId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>hm-api</artifactId>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <dependencies>
        <!--open feign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!-- load balancer-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>
        <!-- swagger 注解依赖 -->
        <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-annotations</artifactId>
            <version>1.6.6</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
</project>

(2)然后把需要用到的实体类放在一个包里

现在任何微服务想要调用其他微服务的直接,只需要引入这个模块的依赖即可,无需再自己编写Feign客户端了

(3)扫描包

接下来,我们在服务调用者的pom.xml中引入刚才创建的模块的依赖

  <!--feign模块-->
  <dependency>
      <groupId>com.heima</groupId>
      <artifactId>hm-api</artifactId>
      <version>1.0.0</version>
  </dependency>

如果重启项目报错的话,在启动类上添加@EnableFeignClients(basePackages = "OpenFeign客户端所在的包") 

4.日志配置

OpenFeign只会在FeignClient所在包的日志级别为DEBUG时,才会输出日志。

(1)OpenFeign的日志级别

  • NONE:不记录任何日志信息,这是默认值。

  • BASIC:仅记录请求的方法,URL以及响应状态码和执行时间

  • HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息

  • FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据。

Feign默认的日志级别就是NONE,所以默认我们看不到请求日志。

(2)定义日志级别

在刚在新建的模块下新建一个配置类,定义Feign的日志级别:

package com.hmall.api.config;

import feign.Logger;
import org.springframework.context.annotation.Bean;

public class DefaultFeignConfig {
    @Bean
    public Logger.Level feignLogLevel(){
        return Logger.Level.FULL;
    }
}

(3)​​​​​​​配置

接下来,要让日志级别生效,还需要配置这个类。有两种方式:

  • 局部生效:在某个FeignClient中配置,只对当前的FeignClient生效

@FeignClient(value = "item-service", configuration = DefaultFeignConfig.class)
  • 全局生效:在@EnableFeiginClients中配置,仅对所有的FeignClient生效

@EnableFeignClients(defaultConfiguration = DefaultFeignConfig.class)

六、网关

1.含义

就是网络的关口,负责请求的路由、转发、身份校验。

2.快速入门

(1)创建项目添加依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>hmall</artifactId>
        <groupId>com.heima</groupId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>hm-gateway</artifactId>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>
    <dependencies>
        <!--common-->
        <dependency>
            <groupId>com.heima</groupId>
            <artifactId>hm-common</artifactId>
            <version>1.0.0</version>
        </dependency>
        <!--网关-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <!--nacos discovery-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--负载均衡-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>
    </dependencies>
    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

(2)新建启动类

package com.hmall.gateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class GatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
}

(3)配置application.yml

server:
  port: 8080
spring:
  application:
    name: gateway
  cloud:
    nacos:
      server-addr: 192.168.150.101:8848
    gateway:
      routes:
        - id: item # 路由规则id,自定义,唯一
          uri: lb://item-service # 路由的目标服务,lb代表负载均衡,会从注册中心拉取服务列表
          predicates: # 路由断言,判断当前请求是否符合当前规则,符合则路由到目标服务
            - Path=/items/**,/search/** # 这里是以请求路径作为判断规则
        - id: cart
          uri: lb://cart-service
          predicates:
            - Path=/carts/**
        - id: user
          uri: lb://user-service
          predicates:
            - Path=/users/**,/addresses/**
        - id: trade
          uri: lb://trade-service
          predicates:
            - Path=/orders/**
        - id: pay
          uri: lb://pay-service
          predicates:
            - Path=/pay-orders/**

(4)路由过滤

路由规则的定义语法如下:

spring:
  cloud:
    gateway:
      routes:
        - id: item
          uri: lb://item-service
          predicates:
            - Path=/items/**,/search/**

四个属性含义如下:

  • id:路由的唯一标示

  • predicates:路由断言,其实就是匹配条件

  • filters:路由过滤条件,后面讲

  • uri:路由目标地址,lb://代表负载均衡,从注册中心获取目标微服务的实例列表,并且负载均衡选择一个访问。

3.配置热更新

参考:【Nacos】配置管理、微服务配置拉取、实现配置热更新、多环境配置

七、服务保护

1.雪崩问题

微服务调用链路中的某个服务故障,引起整个链路中的所有微服务都不可用,这就是雪崩。

2.保护方案

(1)请求限流

请求限流:限制访问接口的请求的并发量,避免服务因流量激增出现故障。

(2)线程隔离

线程隔离:也叫做舱壁模式,模拟船舱隔板的防水原理。通过限定每个业务能使用的线程数量而将故障业务隔离,避免故障扩散。

线程隔离的思想来自轮船的舱壁模式:

轮船的船舱会被隔板分割为N个相互隔离的密闭舱,假如轮船触礁进水,只有损坏的部分密闭舱会

(3)服务熔断

服务熔断:由断路器统计请求的异常比例或慢调用比例,如果超出阈值则会熔断该业务,则拦截该接口的请求。熔断期间,所有请求快速失败,全都走 fallback 逻辑。

3.服务保护技术 --- Sentinel

(1)安装

SpringCloud之Sentinel概述和安装及简单整合

(2)OpenFeign整合Sentinel

修改服务调用者的application.yml文件,开启Feign的sentinel功能:

feign:
  sentinel:
    enabled: true # 开启feign对sentinel的支持

八、分布式事务

1.含义

在分布式系统中,如果一个业务需要多个服务合作完成,而且每一个服务都有事务,多个事务必须同时成功或失败,这样的事务就是分布式事务。其中的每个服务的事务就是一个分支事务。整个业务称为全局事务。

2.seata

(1)安装

Seata安装与使用以及部分常见问题(保姆级教程)​​​​​​​

(2)架构

Seata 事务管理中有三个重要的角色:

TC (Transaction Coordinator) - 事务协调者:维护全局和分支事务的状态,协调全局事务提交或回滚。
TM (Transaction Manager) - 事务管理器:定义全局事务的范围、开始全局事务、提交或回滚全局事务。
RM (Resource Manager) - 资源管理器:管理分支事务,与 TC 交谈以注册分支事务和报告分支事务的状态

(3)XA 模式

XA 规范 是 X/Open 组织定义的分布式事务处理( DTP , Distributed Transaction Processing )标准, XA 规范 描述了全局的 TM 与局部的 RM 之间的接口,几乎所有主流的数据库都对 XA 规范 提供了支持。 Seata 的 XA 模式如下:

(4)AT模式

AT模式同样是分阶段提交的事务模型,不过缺弥补了XA模型中资源锁定周期过长的缺陷。

(5)AT 模式与 XA 模式最大的区别是什么?

• XA 模式一阶段不提交事务,锁定资源; AT 模式一阶段直接提交,不锁定资源。
• XA 模式依赖数据库机制实现回滚; AT 模式利用数据快照实现数据回滚。
• XA 模式强一致; AT 模式最终一致


总结

欢迎各位阅读并提出宝贵建议,本文旨在分享个人对于SpringCloud的学习总结

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值