Spring Cloud学习笔记
想要学习 Spring Cloud 先要了解下面几点
-
什么是集群
集群简单来说就是将一个系统部署在多台服务器上,每台服务器提供的都是相同的服务
优点:
1.本来是一台服务器去处理访问数据,现在有两台服务器去处理了,分担了压力
2.如果一台服务器宕机,那么另一台服务器也可以起到作用
-
什么是分布式
分布式就是将一个单体应用拆分成模块部署在不同的服务器上,这些模块就是服务 多个服务器之间是松耦合的 服务之间相互依赖通过RPC组件或是Result Ful 接口AP I实现通信去完成一个共同的目标
优点
- 资源利用率高 合理的分配了需要被访问的资源
- 如果某一个服务不可用了 不会影响其他的服务,其他的服务还可以继续提供服务。
-
什么是SOA
SOA是一种面向服务架构的思想 侧重点在于提取核心服务,减少代码冗余,增加业务代码的复用,解决信息孤岛等一些问题。
SOA有如下几个特点:分布式、可重用、扩展灵活、松耦合
-
什么是微服务
微服务是一种架构风格,主张将复杂的软件应用拆分成一个或者多个微服务,各个微服务时间是松耦合的,可以独立的进行开发、测试和部署等,每个微服务仅关注完成一件事情,服务之间通过基于HTTP的RESTful API进行通信协作,微服务比SOA更细粒度的服务思想,侧重点在于服务之间的解耦。
-
什么是Spring Cloud
Spring Cloud是由Spring提供的一套微服务标准里面含有一系列框架的有序集合,它可以利用Spring Boot的开发便利性巧妙地简化了分布式开发的一些基础设施的构建,比如说服务发现注册,配置中心,消息总线,负载均衡,断路器这些等等
拆分出多个模块以后,模块与模块之间管理就会比较复杂,就会出现各种各样的问题,比如服务注册与发现、服务之间的调用、负载均衡、熔断、鉴权等。而Spring Cloud就是这样一个提供了一整套的服务治理解决方案的框架。
Spring Cloud提供的功能都是组件化的,想要哪个功能就导入哪个功能的依赖。
市面上常用的微服务治理组件:
- 注册中心 Eureka Zookeeper Consul Nacos
- 服务调用 Ribbon Feign Open Feign
- 服务熔断降级 Hystrix sentinel
- 服务网关 zuul Geteway
- 配置中心 config nacos
- 消息总线 bus nacos
- 链路追踪 sleuth
- 服务监控 spring boot admin
微服务的环境搭建
1.创建一个Maven父工程 springcloud-study
<groupId>com.zksb</groupId>
<artifactId>springcloud-study</artifactId>
<version>1.0-SNAPSHOT</version>
2.导入以下依赖
<?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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.zksb</groupId>
<artifactId>springcloud-study</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
</parent>
<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>
<springcloud.version>Hoxton.SR8</springcloud.version>
<mybatis.springboot.version>2.1.4</mybatis.springboot.version>
<mysql.java.version>5.1.46</mysql.java.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- Spring Cloud -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${springcloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- mybatis-springboot -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.springboot.version}</version>
</dependency>
<!-- mysql驱动包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.java.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
创建商品服务模块
-
创建一个Maven子模块 study-product
<artifactId>study-product</artifactId> <groupId>com.zksb</groupId> <version>1.0-SNAPSHOT</version>
-
添加依赖
<dependencies> <!--mybatis依赖--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency> <!--mysql驱动包依赖--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!--web--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>
-
添加application.yml配置文件
server: port: 9000 spring: application: name: study-product #给服务起一个名称 #编写连接数据库 datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/ordersystem username: root password: 456852 #编写mybatis配置文件 mybatis: mapper-locations: classpath:mapper/*.xml #所有mapper文件位置 type-aliases-package: com.zksb.entity #所有实体类别名 configuration: map-underscore-to-camel-case: true #开启驼峰命名
-
编写实体类、controller、service、dao接口、mapper映射文件代码省略
-
编写启动类并启动后可以访问测试http://localhost:9000/food/1
创建订单服务模块
-
新建一个maven子模块 study-order
<artifactId>study-order</artifactId> <groupId>com.zksb</groupId> <version>1.0-SNAPSHOT</version>
-
导入依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
-
添加配置文件application.yml
server: port: 8001 spring: application: name: study-order
-
编写controller、启动类
服务调用
我们已经搭建好环境创建好商品服务和订单服务了,用户下单时需要获取商品服务的数据,这时这两个服务是独立的,应该怎么做呢?这其实就是系统与系统之间通信的问题,那就需要远程调用RPC,这两个服务都是Web应用,可以通过HTTP请求调用,我们可以使用HttpClient、OkHttp等工具包调用,也可以使用Spring提供的RestTemplate工具类调用。
RestTemplate简介
RestTemplate是Spring提供的用于访问Rest服务的工具类,RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大简化http请求调用方式。
RestTemplate是Spring用于同步client端的核心类,简化了与http服务的通信,并满足Restful原则,程序代码可以给它提供URL,并提取结果。默认情况下,RestTemplate默认依赖JDK的HTTP连接工具。当然你也可以 通过setRequestFactory属性切换到不同的HTTP源,比如Apache HttpComponents、Netty和OkHttp。
常用方法
请求方式 | RestTemplate方法 |
---|---|
GET | getForObject getForEntity |
POST | postForEntity postForObject PostForLocation |
PUT | put |
DELETE | delete() |
HEAD | headForHeaders |
OPTIONS | optionsForAllow |
any | exchange execute |
通过RestTemplate调用服务
- 在启动类将RestTemplate对象交给Spring容器管理
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
2.修改订单服务Controller
@RestController
@RequestMapping("orders")
public class OrderController {
@Autowired
RestTemplate restTemplate;
@GetMapping("{id}")
public Object getOrders(@PathVariable("id") Integer id){
String url = "http://localhost:9000/food/"+id;
String forObject = restTemplate.getForObject(url, String.class);
return forObject;
}
}
3.启动订单服务
浏览器输入http://localhost:8001/orders/1测试
输出结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l3dNMnFb-1611654141914)(C:\Users\75041\AppData\Roaming\Typora\typora-user-images\image-20210126150537354.png)]
这时我们已经实现了通过RestTemplate在订单服务访问到商品模块的服务数据了,但是我们把ip和端口都硬编码在代码中,不利于程序的灵活部署,也不能实现客户端之间的负载均衡,有很大的局限性,该如何解决这个问题,这时候就需要通过我们的注册中心动态的对服务进行注册和发现
注册中心
注册中心又被称为服务中心,这里管理各种服务功能包括服务的注册、发现、熔断、降级、负载等等,比如double admin后台的各种功能
注册中心可以把它看成一个微服务的通讯录,它记录着服务和服务地址的映射关系。
在分布式架构中、服务会注册到这里、当服务需要调用其他服务时,就在这里找到服务的地址进行调用。
常用的注册中心:
1.Zookeeper
zookeeper它是一个分布式服务框架,是Apache Hadoop的一个子项目,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。简单来说zookeeper=文件系统+监听通知机制。
2.Euereka
Eureka是在Java语言上,基于Restful Api开发的服务注册与发现组件,Spring Cloud Netflix中的重要组件。
3.consul
Consul是由HashiCorp基于Go语言开发的支持多数据中心分布式高可用的服务发布和注册服务软件,采用Raft算法保证服务的一致性,且支持健康检查。
4.Nacos
Nacos是阿里巴巴推出来的一个新开源项目,是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。简单来说Nacos就是注册中心 + 配置中心的组合,提供简单易用的特性集,帮助我们解决微服务开发必会涉及到的服务注册与发现,服务配置,服务管理等问题。Nacos还是Spring Cloud Alibaba 组件之一,负责***服务注册与发现***。
最后我们通过一张表格大致了解Eureka、Consul、Zookeeper的异同点。选择什么类型的服务注册与发现组件可以根据自身项目要求决定。
组件名 | 语言 | CAP | 一致性算法 | 服务健康检查 | 对外暴露接口 |
---|---|---|---|---|---|
Eureka | Java | AP | 无 | 可配支持 | HTTP |
Consul | Go | CP | Raft | 支持 | HTTP/DNS |
Zookeeper | Java | CP | Paxos | 支持 | 客户端 |
Nacos | Java | AP | Raft | 支持 | HTTP |
Eureka注册中心
Eureka是Netflix开发的服务发现框架,Spring Cloud将它集成在自己的子项目spring-cloud-netflix中,实现Spring Cloud的服务发现功能。
Eureka由两个组件组成:Eureka Server和Eureka Client。它们的作用如下:
- Eureka Client 是一个java客户端,用于简化与Eureka Server的交互
- Eureka Server提供服务的发现能力,各个微服务启动时都会通过Eureka Client向Eureka Server注册自己的信息,Eureka Server会存储该服务的信息
- 微服务启动注册成功后,会每隔30秒地向Eureka Server发送心跳续约自己的信息,如果Eureka Server在一定时间内没有接收到某个微服务的节点心跳信息,Eureka Server会注销该服务节点(默认为90s)
- Eureka Client会缓存Eureka Server中的信息,即使所有的Eureka Server节点都宕机掉,服务调用者依然可以使用缓存中的信息找到服务提供者。
综上,Eureka通过心跳检测、健康检查和客户端缓存机制,提高了系统的灵活性,可伸缩性和可用性
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iiqkvUZX-1611654141917)(file:///C:\Users\75041\AppData\Local\Temp\ksohtml13652\wps1.jpg)]
Eureka由3个角色组成:
1、Eureka Server
- 提供服务注册和发现
2、Service Provider
- 服务提供方
- 将自身服务注册到Eureka,从而使服务消费方能够找到
3、Service Consumer
- 服务消费方
- 从Eureka获取注册服务列表,从而能够消费服务
搭建Eureka注册中心
1.在之前的maven父工程springcloud-study内新建一个子模块study-eureka
<artifactId>study-eureka</artifactId>
<groupId>com.zksb</groupId>
<version>1.0-SNAPSHOT</version>
2.导入依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
3.编写配置文件
server:
port: 3001
eureka:
client:
service-url:
defaultZone: http://localhost:${server.port}/eureka #注册中心的交互地址
register-with-eureka: false #是否将自己注册到注册中心
fetch-registry: false #是否从注册中心获取数据
spring:
application:
name: zksb-eureak #给服务取个名字,服务之间的调用就是用这个命名。
4.编写启动类
@SpringBootApplication
@EnableEurekaServer//启用Eureka
public class EurekaApp {
public static void main(String[] args) {
SpringApplication.run(EurekaApp.class,args);
}
}
/localhost:${server.port}/eureka #注册中心的交互地址
register-with-eureka: false #是否将自己注册到注册中心
fetch-registry: false #是否从注册中心获取数据
spring:
application:
name: zksb-eureak #给服务取个名字,服务之间的调用就是用这个命名。
4.编写启动类
```java
@SpringBootApplication
@EnableEurekaServer//启用Eureka
public class EurekaApp {
public static void main(String[] args) {
SpringApplication.run(EurekaApp.class,args);
}
}
5.运行启动类浏览器访问:http://localhost:3001/eureka