springcloud

tech2024-05-24  70

微服务

微服务的关键:服务治理、服务监控

Spring Cloud 是一个一站式解决微服务的服务治理和服务监控的工具集框架

架构的演变

微服务的解决方案

1、Dubbo

2、Spring Cloud

Spring Cloud

Spring Cloud 是一个一站式解决微服务的服务治理和服务监控的工具集框架

1、核心组件

1. 先要有一个服务注册中心,将所有服务注册 eureka、consul、nacos(alibaba) 2. 开发一个一个的微服务 spring boot 3. 解决微服务之间的调用问题 openfeign 4. 每个微服务集群的负载均衡问题 rabbion 5. 给所有服务提供一个同一的访问口 Gateway网关 6. 对所有微服务的配置文件进行统一管理 config 7. 配置修改后通过消息总线完成配置的刷新 bus【RabbitMQ】

2、版本适配(Spring Boot和Spring Cloud)

3、环境搭建

创建一个 spring boot 工程

修改spring boot的版本号 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.5.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> 引入spring cloud的版本管理 <properties> <java.version>1.8</java.version> <spring-cloud.version>Hoxton.SR6</spring-cloud.version> </properties> <!--全局管理springcloud版本,并不会引入具体依赖--> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>

此时版本环境搭建完成,在使用的时候,进入具体的组件的依赖就可以了

Spring Cloud 组件的学习

1、服务注册中心

服务注册中心是在整个的服务架构中单独的提出的一个服务,这个服务不完成任何业务功能。仅仅用来完成整个微服务系统的服务注册和服务发现,以及对服务健康状态的监控和管理功能。


可以对所有的微服务的信息进行存储,如:微服务的名称、IP、端口可以在进行服务调用的时候,通过服务发现查询可用的微服务列表及网络地址进行服务调用可以对所有的微服务进行心跳检测,如果发现某个服务实例长时间无法访问,就会在服务注册表中移除
# Spring Cloud 支持多种服务注册中心组件 - Eureka 【NetFlix,已经停止维护】 - Consul 【谷歌采用 go语言开发的】 - ZooKeeper 【之前Dubbo常用的注册中心】 - Nacos 【阿里巴巴推出的】

本质都是服务的注册和发现以及服务状态的检查

1.1、Eureka

Eureka 包含两个组件:Eureka Server 和 Eureka Client

# 单体应用:分类服务、商品服务、订单服务、用户服务 - Eureka Server 组件:服务注册中心组件 管理所有服务、支持所有服务注册 - Eureka Client 组件:分类服务、商品服务、订单服务、用户服务(微服务)

开发Eureka Server

1、创建spring-cloud 项目并引入Eureka Server 依赖 <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> 2、编写配置 application.properties server.port=8761 spring.application.name=eurekaserver eureka.client.service-url.defaultZone=http://localhost:8761/eureka # 不再将自己同时作为客户端进行注册 eureka.client.register-with-eureka=false #关闭作为客户端从server获取服务信息 eureka.client.fetch-registry=false 3、开启 Eureka Server,入口类加注解 @EnableEurekaServer @SpringBootApplication @EnableEurekaServer public class SpringCloud01Application { public static void main(String[] args) { SpringApplication.run(SpringCloud01Application.class, args); } }

访问:http://localhost:8761/

开发Eureka Client

注意:每一个 Client 就是一个微服务

1、在微服务项目中引入 Client 依赖 <properties> <java.version>1.8</java.version> <spring-cloud.version>Hoxton.SR6</spring-cloud.version> </properties> <!--全局管理springcloud版本,并不会引入具体依赖--> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> 2、编写配置 application.properties server.port=8888 spring.application.name=eurekaclient eureka.client.service-url.defaultZone=http://localhost:8761/eureka 3、在启动类上加上注解 @SpringBootApplication @EnableEurekaClient public class EurekaClient8888Application { public static void main(String[] args) { SpringApplication.run(EurekaClient8888Application.class, args); } } # 4、注意:启动注册中心,再启动客户端【微服务】

1.2、Consul

go语言开发的一个服务注册中心软件

开发Consul 服务端

1. 下载安装 consul 软件 - https://www.consul.io/downloads 2. 点击 exe 直接启动(需要配环境变量) 或者,直接在控制台输入(不需要配置环境变量) consul agent -dev 3. 访问 - http://localhost:8500

开发Consul客户端【微服务】

1、创建项目并引入 consul 客户端依赖 <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-discovery</artifactId> </dependency> <!--引入健康检查依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> 2、编写 properties 配置文件 server.port=8889 spring.application.name=consulclient8889 spring.cloud.consul.host=localhost spring.cloud.consul.port=8500 3、因为引入了客户端依赖,启动类上可以不加注解 @SpringBootApplication public class EurekaClient8888Application { public static void main(String[] args) { SpringApplication.run(EurekaClient8888Application.class, args); } }
1.3、CAP(不同注册中心的区别)

2、服务间的通信方式

在 spring cloud 中服务间的调用方式主要是使用HTTP restful 的方式

案例: 在商品服务中有一个展示商品的方法现在用户要有一个查看商品信息的方法此时,我们就需要在用户服务的查看信息的方法调用商品服务的展示商品的方法

2.1、基于 Rest Template 的服务调用

我们创建一个用户服务、一个商品服务

我们现在要解决的就是这两个服务之间的通信【用户服务怎么调用商品服务】

商品服务中的展示商品的方法

//前后端分离开发、微服务开发都是基于 Rest 风格的。【因为 跨系统 要 传输的 是数据 而 不是页面】 @RestController public class ProductController { @Value("${server.port}") private int port; @GetMapping("/product/showMsg") public String showMsg() { return "展示商品信息" + port; } }

用户服务调用商品服务的展示商品的方法

@RestController public class UserController { @GetMapping("/user/showProductMsg") public String showProductMsg(){ //1、第一种服务端的调用方式 restTemplate //服务地址:http://localhost:9999/product/showMsg RestTemplate restTemplate = new RestTemplate(); //因为产品设置的是get方式,只能get方式取出 //参数1:请求路径 参数2:返回值类型 return restTemplate.getForObject("http://localhost:9999/product/showMsg", String.class); } }

如果现在商品服务是一个集群

此时,路径写死在代码中,无法进行负载均衡

如何在 idea 中快速创建某个服务的集群

# 问题: - 这种方式,是直接基于服务地址调用的,并没有经过服务注册中心,不能在服务器宕机的时候高效剔除服务 - 调用服务地址直接写死在了代码中,不利于维护,无法进行负载均衡
2.2、基于 Ribbon 的服务调用

Spring Could Ribbon 是一个基于 HTTP和TCP 的客户端负载均衡工具

通过此组件,我们可以轻松的将面向服务的Rest模板请求自动转换成客户端负载均衡的服务调用

# 1. 项目中引入依赖 - 说明: 1. 如果使用的是eureka client 和 consul client,无须引入依赖【默认集成了ribbon组件】 2. 如果没有集成ribbon组件,我们需要显式的引入如下的依赖 <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency>

# 2. 使用restTemplate + ribbon进行服务调用 - 使用`discovery client` 进行客户端调用 - 使用`loadBalanceClient` 进行客户端调用 - 使用`@loadBalance` 进行客户端调用

discovery client 拉去所有的服务主机和端口【但是没有负载均衡策略】

@Autowired private DiscoveryClient discoveryClient; public List<ServiceInstance> showProductMsg(){ //参数是服务名-----》spring.application.name=consulclient9999 List<ServiceInstance> serviceInstances = discoveryClient.getInstances("consulclient9999"); for (ServiceInstance serviceInstance : serviceInstances) { //获得ip System.out.println(serviceInstance.getHost()); //获得port System.out.println(serviceInstance.getPort()); } return serviceInstances; } //DESKTOP-AI2685R //9997 //DESKTOP-AI2685R //9999

获得的实例 json 数据

load Balance Client 直接根据负载均衡返回一个商品服务实例【但是需要自己拼接】

@Autowired private LoadBalancerClient loadBalancerClient; public ServiceInstance showProductMsg(){ //参数是服务名 ServiceInstance serviceInstance = loadBalancerClient.choose("consulclient9999"); return serviceInstance; } //默认是轮询 //DESKTOP-AI2685R //9997 结合 RestTemplate 完成 @GetMapping("/user/showProductMsg") public String showProductMsg(){ //参数是服务名 ServiceInstance serviceInstance = loadBalancerClient.choose("consulclient9999"); System.out.println(serviceInstance.getHost()); System.out.println(serviceInstance.getPort()); //通过restTemplate RestTemplate restTemplate = new RestTemplate(); String url = "http://"+serviceInstance.getHost()+":"+serviceInstance.getPort()+"/product/showMsg"; String forObject = restTemplate.getForObject(url, String.class); return forObject;@GetMapping("/user/showProductMsg") public String showProductMsg(){ //参数是服务名 ServiceInstance serviceInstance = loadBalancerClient.choose("consulclient9999"); System.out.println(serviceInstance.getHost()); System.out.println(serviceInstance.getPort()); //通过restTemplate RestTemplate restTemplate = new RestTemplate(); String url = "http://"+serviceInstance.getHost()+":"+serviceInstance.getPort()+"/product/showMsg"; String forObject = restTemplate.getForObject(url, String.class); return forObject; }

@loadBalance不需要拼接就可以拼接,也可以完成负载均衡【这种方法底层就是封装了第二种方法】

在服务的调用方:此处是users--------------》创建一个config类

@Configuration public class RestConfig { //在工厂中创建一个RestTemplate对象 @Bean @LoadBalanced //代表ribbon负载均衡的RestTemplate客户端对象 public RestTemplate getRestTemplate(){ return new RestTemplate(); } }

之后我们就有了一个整合了负载均衡的 restTemplate 对象

直接注入就可以使用

@RestController public class UserController { @Autowired private RestTemplate restTemplate; @GetMapping("/user/showProductMsg") public String showProductMsg(){ //在url中的host:port写服务的名称 String forObject = restTemplate.getForObject("http://consulclient9999/product/showMsg", String.class); return forObject; } }

最后一种最常用

2.3、 OpenFeign

3、Hystrix

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DqZqTLXi-1599127099293)(C:\Users\Hasee\AppData\Roaming\Typora\typora-user-images\image-20200811095500277.png)]

熔断是对调用链路的保护

降级是对系统的保护

熔断一定是降级

4、Gateway 组件【网关】

微服务层面的拦截器

用网关不能使用 原先的web依赖(冲突)

Filter

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NizxxXDh-1599127099340)(C:\Users\Hasee\AppData\Roaming\Typora\typora-user-images\image-20200811144043735.png)]

使用官方的filte

5、Config

6、Bus组件

微服务企业级开发maven结构

spring cloud alibaba

spring cloud alibaba主要 改变了:服务注册中心、配置中心、熔断器

1、Nacos

Nacos (Name Service & Configurations Service)【替换了原先的注册中心组件和配置中心组件】

2、sentinel

docker 安装

docker pull bladex/sentinel-dashboard

docker run --name sentinel -d -p 13306:8858 -d bladex/sentinel-dashboard

访问dashboard 地址:http://xx.xx.xx.xx:8858 账号密码都为:sentinel

spring cloud + spring alibaba的整合 maven 架构开发

1、创建一个项目的父工程

父工程只管理所有依赖的版本号和springcloud、springcloudalibaba的下载仓库地址

<!--继承springboot的父项目--> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.5.RELEASE</version> </parent> <!--维护springcloud 和 springcloud alibaba 和 其他的版本号--> <properties> <java.version>1.8</java.version> <spring.cloud.version>Hoxton.SR6</spring.cloud.version> <spring.cloud.alibaba.version>2.2.1.RELEASE</spring.cloud.alibaba.version> </properties> <!--全局管理springcloud和alibaba的下载位置,并不会引入具体依赖--> <dependencyManagement> <dependencies> <!--springcloud的下载仓库地址--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring.cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!--alibaba的下载仓库地址--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>${spring.cloud.alibaba.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>

2、创建一个公共依赖的模块

公共模块主要放的是项目中公共的实体类,工具类、和一些公共的依赖



<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <!--引入 nacos client--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!--引入springcloud netflix 的openfeign组件--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <!--引入 alibaba sentinel--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> <!--引入 alibaba nacos config--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> </dependencies> <!--可以将build标签全部去掉-->

3、创建各个微服务模块

我们可以用quickstart模块来创建,但是之后需要将模块变为springboot形式

我们用idea的快捷方式创建springboot,但是,创建完成后必须将标签修改为commons中的

具体的可以在commons模块中找到 <parent> <artifactId>dangdang_parent</artifactId> <groupId>cf.duanzifan</groupId> <version>1.0-SNAPSHOT</version> </parent>
引入依赖 commons <dependency> <groupId>cf.duanzifan</groupId> <artifactId>dangdang_commons</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
3.1、将微服务注册到nacos

配置文件

# 指定当前服务的端口号 server.port=9999 # 指定服务名 spring.application.name=users # 指定nacos服务地址 spring.cloud.nacos.server-addr=localhost:8848 # 指定注册中心的地址 spring.cloud.nacos.discovery.server-addr=${spring.cloud.nacos.server-addr} # 暴露所有的web端点 management.endpoint.web.exposure.include=*

访问nacos网站

http://localhost:8848/nacos

启动程序后我们可以在服务列表找到服务实例

怎么在idea中完成一个伪集群:-Dserver.port=9998

3.2、服务间的调用 openFeign 组件

使用 open Feign 组件,在启动类上要加注解 @EnableFeignClients

3.3、流量卫兵 sentinel
# 开启sentinel 默认开启(可以不写) spring.cloud.sentinel.enabled=true # 连接 dashboard spring.cloud.sentinel.transport.dashboard=localhost:8858 # 与dashboard通信的端口(传输日志)端口号是 8719【必须写】 spring.cloud.sentinel.transport.port=8719 # 关闭懒加载【服务启动的时候就开启监控】 spring.cloud.sentinel.eager=true

访问http://localhost:8858/

用户名/密码:sentinel

3.4、将配置存放在 nacos

。。。



注意:此处的命名空间

回到代码中,将application.properties 改为 bootstrap.properties

并开始写远程调用配置的配置

# 指定nacos的地址 spring.cloud.nacos.server-addr=local:8848 # 指定配置中心地址 spring.cloud.nacos.config.server-addr=${spring.cloud.nacos.server-addr} # 指定配置中心的命名空间 spring.cloud.nacos.config.namespace=b8d2c71d-bb0c-44b9-92d0-cf65cd40fd7a # 指定具体的组 spring.cloud.nacos.config.group=DangDang # 指定配置文件的名字 spring.application.name=books # 指定配置文件的后缀 spring.cloud.nacos.config.file-extension=properties

重新启动服务

3.5、路由 gateway

因为采用了新的springweb框架,所以不能引入原先的springweb依赖

做一个网关服务

在 pom.xml 中改变

<parent> <artifactId>dangdang_parent</artifactId> <groupId>cf.duanzifan</groupId> <version>1.0-SNAPSHOT</version> </parent> <dependency> <groupId>cf.duanzifan</groupId> <artifactId>dangdang_commons</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <!--actuator--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>

因为网关服务的路径特殊所以配置文件改为yum格式

server: port: 8891 spring: application: name: gateway cloud: nacos: server-addr: 121.89.207.234:8848 discovery: server-addr: ${spring.cloud.nacos.server-addr} gateway: routes: - id: users_route uri: lb://users predicates: - Path=/user/** - id: users_route uri: lb://books predicates: - Path=/book/** management: endpoints: web: exposure: include: "*"

访问路由管理的地址:http://localhost:8891/actuator/gateway/routes

groupId>cf.duanzifan dangdang_commons 1.0-SNAPSHOT org.springframework.cloud spring-cloud-starter-gateway

org.springframework.boot spring-boot-starter-actuator ```

因为网关服务的路径特殊所以配置文件改为yum格式

server: port: 8891 spring: application: name: gateway cloud: nacos: server-addr: 121.89.207.234:8848 discovery: server-addr: ${spring.cloud.nacos.server-addr} gateway: routes: - id: users_route uri: lb://users predicates: - Path=/user/** - id: users_route uri: lb://books predicates: - Path=/book/** management: endpoints: web: exposure: include: "*"

访问路由管理的地址:http://localhost:8891/actuator/gateway/routes

最新回复(0)