spring cloud 入门
初识 Spring Cloud
Spring Cloud 服务治理【掌握】
负载均衡Ribbon【掌握】
疑问: 什么是微服务?有什么用?
分析:
系统演变:
演变的原因是由于项目的内容越来越复杂,开发的人员越来越多,项目访问的并发度越来越高。
什么是微服务?
• "微服务”一词源于 Martin Fowler的名为 Microservices的博文,可以在他的官方博客上找到
http://martinfowler.com/articles/microservices.html
• 微服务是系统架构上的一种设计风格,它的主旨是将一个原本独立的系统拆分成多个小型服务,这些小型服务都在各自独立的进程中运行,服务之间一般通过 HTTP 的 RESTfuLAPI 进行通信协作。
有什么用?解决什么问题?什么时候用?
• 被拆分成的每一个小型服务都围绕着系统中的某一项或某些耦合度较高的业务功能进行构建,并且每个服务都维护着自身的数据存储、业务开发自动化测试案例以及独立部署机制。
• 由于有了轻量级的通信协作基础,所以这些微服务可以使用不同的语言来编写。
总结:
解决互联网大型项目的开发,测试,部署,运维问题。
dubbo和springcloud之间的区别?
两项技术,都是用于微服务(不同的服务)之间进行调用。
dubbo: RPC协议,效率高,只支持JAVA。
springcloud: HTTP协议,支持各种语言,更加灵活。
疑问:spring cloud是什么?能为我们做什么?
分析:
spring cloud是什么?
• Spring Cloud 是一系列框架的有序集合。
• Spring Cloud 并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来。
• 通过 Spring Boot 风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。
• 它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、 断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。
• Spring Cloud项目官方网址:https://spring.io/projects/spring-cloud
spring cloud能为我们做什么?
Spring 公司将其他公司中微服务架构常用的组件整合起来,并使用 SpringBoot 简化其开发、配置。称为 Spring Cloud
spring cloud的版本信息
Spring Cloud 版本命名方式采用了伦敦地铁站的名称,同时根据字母表的顺序来对应版本时间顺序,比如:最早的Release版本:Angel,第二个Release版本:Brixton,然后是Camden、Dalston、Edgware,Finchley,Greenwich,Hoxton。
目前最新的是Hoxton版本。
我们课程学习的版本Greenwich,使用spring cloud就要使用和他对应的spring boot的版本。
Spring Cloud 与 Dubbo 都可以完成微服务的搭建,它们有什么区别?面试题
分析:
• Spring Cloud 与 Dubbo 都是实现微服务有效的工具。
• Dubbo 只是实现了服务治理,而 Spring Cloud 子项目分别覆盖了微服务架构下的众多部件。
• Dubbo 使用 RPC 通讯协议,Spring Cloud 使用 RESTful 完成通信,Dubbo 效率略高于 Spring Cloud。
• Dubbo只能用于JAVA工程之间的微服务搭建。Spring Cloud对调用方无要求.
总结:
• 微服务就是将项目的各个模块拆分为可独立运行、部署、测试的架构设计风格。
• Spring 公司将其他公司中微服务架构常用的组件整合起来,并使用 SpringBoot 简化其开发、配置。称为 Spring Cloud
• Spring Cloud 与 Dubbo都是实现微服务有效的工具。Dubbo 性能更好,而 Spring Cloud 功能更全面。
疑问:
服务治理就是注册中心?那么Spring Cloud使用什么软件作为注册中心?
分析:
微服务之间相互调用需要知道对方服务器的IP和端口,服务治理就是管理各个服务的地址和状态。
Eureka 注册中心
• Eureka 是 Netflix 公司开源的一个服务注册与发现的组件 。
• Eureka 和其他 Netflix 公司的服务组件(例如负载均衡、熔断器、网关等) 一起,被 Spring Cloud 社区整合为
Spring-Cloud-Netflix 模块。
• Eureka 包含两个组件:Eureka Server (注册中心) 和 Eureka Client (服务提供者、服务消费者)。
步骤:
总结:
Provider 和 Consumer 服务就是使用spring boot搭建的普通应用。
为了保证Provider 和 Consumer 服务基于相同的实体对象,一般会抽成新模块,双方都依赖。
微服务比较小,内容单一,内部不对外暴漏信息。所以可以不用接口。通过HTTP的方式对外提供服务。
疑问:
Consumer 如何调用Provider 服务?
使用RestTemplate
分析:
配置RestTemplate
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
注入RestTemplate并远程调用
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/goods/{id}")
public Goods findGoodsById(@PathVariable("id") int id){
System.out.println("findGoodsById..."+id);
String url = "http://localhost:8000/goods/findOne/"+id;
Goods goods = restTemplate.getForObject(url, Goods.class);
}
}
总结:
RestTemplate的方法:
//发送get请求
//url: 请求的url
//Goods.class : 将返回的JSON自动转换成对象
Goods goods = restTemplate.getForObject(url, Goods.class);
// 发送post请求
//第二个参数:Object类型 param ,将该对象转为JSON作为请求体的内容发送
Goods goods = restTemplate.postForObject(url,param,Goods.class);
疑问:
远程调用的服务器IP和端口都是写死的,如果环境发生变化怎么办?
分析:
搭建Eureka Server,注册中心进行服务治理。
步骤:
① 创建 eureka-server 模块
<parent>
<artifactId>spring-cloud-parentartifactId>
<groupId>com.itheimagroupId>
<version>1.0-SNAPSHOTversion>
parent>
② 引入 SpringCloud 和 euraka-server 相关依赖
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
dependency>
dependencies>
③ 完成 Eureka Server 相关配置
server:
port: 8761
# eureka 配置
# eureka 一共有4部分 配置
# 1. dashboard:eureka的web控制台配置
# 2. server:eureka的服务端配置
# 3. client:eureka的客户端配置
# 4. instance:eureka的实例配置
eureka:
instance:
hostname: localhost # 主机名
client:
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
register-with-eureka: false # 是否将自己的路径 注册到eureka上。eureka server 不需要的,eureka provider client 需要
fetch-registry: false # 是否需要从eureka中抓取路径。eureka server 不需要的,eureka consumer client 需要
server:
enable-self-preservation: false # 关闭自我保护机制
eviction-interval-timer-in-ms: 3000 # 检查服务的时间间隔
④ 启动该模块
@SpringBootApplication
// 启用EurekaServer
@EnableEurekaServer
public class EurekaApp {
public static void main(String[] args) {
SpringApplication.run(EurekaApp.class,args);
}
}
疑问:
如何查看Eureka注册中心?
分析:
控制台地址: http://localhost:8761/
疑问:
搭建好了注册中心怎么使用?
不管是Provider 还是 Consumer都是Eureka Client。他们都是Eureka 的客户端。
分析:
搭建Eureka Client的步骤:
① 引 eureka-client 相关依赖
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
② 完成 eureka client 相关配置
server:
port: 9000
eureka:
instance:
hostname: localhost # 主机名
client:
service-url:
defaultZone: http://localhost:8761/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
spring:
application:
name: eureka-consumer # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径
③ 启动 测试
@EnableEurekaClient //该注解 在新版本中可以省略
@SpringBootApplication
public class ProviderApp {
public static void main(String[] args) {
SpringApplication.run(ProviderApp.class,args);
}
}
疑问:
现在Provider 和 Consumer都注册到Eureka 注册中心了,那么如何通过Eureka 来获取请求的路径。
分析:
在Consumer中动态获取Provider 的IP和端口:
启动类激活DiscoveryClient
@EnableDiscoveryClient // 激活DiscoveryClient
@EnableEurekaClient
@SpringBootApplication
public class ConsumerApp {
controller注入DiscoveryClient
@Autowired
private DiscoveryClient discoveryClient;
根据配置的应用名称来动态获取IP和端口
//演示discoveryClient 使用
//参数就是配置文件中设置的
/* application.yml
spring:
application:
name: eureka-provider
*/
List<ServiceInstance> instances = discoveryClient.getInstances("EUREKA-PROVIDER");
//判断集合是否有数据
if(instances == null || instances.size() == 0){
//集合没有数据
return null;
}
ServiceInstance instance = instances.get(0);
String host = instance.getHost();//获取ip
int port = instance.getPort();//获取端口
总结:
疑问: Eureka的属性比较复杂,关于实例的配置。
注意:使用spring cloud就是为了快速搭建,框架设置的默认值都非常合理,一般在开发中并不修改。
分析:
Eureka默认注册主机名,但是如果不是局域网,我们希望将当前实例的IP地址注册到Eureka中。
prefer-ip-address
ip-address
配置:
eureka:
instance:
hostname: localhost # 主机名
prefer-ip-address: true # 将当前实例的ip注册到eureka server 中。默认是false 注册主机名
ip-address: 127.0.0.1 # 设置当前实例的ip
instance-id: ${eureka.instance.ip-address}:${spring.application.name}:${server.port} # 设置web控制台显示的 实例id
lease-renewal-interval-in-seconds: 3 # 每隔3 秒发一次心跳包
lease-expiration-duration-in-seconds: 9 # 如果9秒没有发心跳包,服务器呀,你把我干掉吧~
疑问: Eureka关于服务端的配置。
分析:
配置信息:
eureka:
server:
enable-self-preservation: false # 关闭自我保护机制
eviction-interval-timer-in-ms: 3000 # 检查服务的时间间隔
自我保护机制
Eureka作为注册中心,需要知道其中注册的应用的状态是否可用
客户端应用需要设置向注册中心Eureka发生心跳检查的时间,和超时删除应用的时间
eureka:
instance:
lease-renewal-interval-in-seconds: 30 # 每隔30 秒发一次心跳包
lease-expiration-duration-in-seconds: 90 # 如果90秒没有发心跳包,服务器呀,你把我干掉吧~
服务器设置了检查应用的时间间隔
eureka:
server:
enable-self-preservation: false # 关闭自我保护机制
eviction-interval-timer-in-ms: 3000 # 检查服务的时间间隔
开启保护机制
Renews threshold # 期望的心跳包数量,(n+1)*2*0.85 n表示实例数,只取整数
Renews (last min) # 实际收到的数量,根据lease-renewal-interval-in-seconds的设置
期望的比实际的大,就会开启保护机制。
保护机制的目的
什么是Eureka的自我保护机制?为什么要有这个机制?
Eureka中注册的应用,有超过15%的心跳没有被发送,他就进入自我保护状态。进入自我保护状态,不再剔除应用。
避免网络波动的时候,删除了大量的正常应用。一次性的大量的应用被删除。
疑问:
注册中心坏了,那么系统就无法使用了,所以要保证Eureka高可用,就是搭建Eureka集群。
分析:
疑问:
如何来搭建Eureka集群?
分析:
各个注册中心Eureka相互注册。
搭建步骤:
创建两个Eureka server应用
配置
server:
port: 8761
eureka:
instance:
hostname: eureka-server1 # 主机名
client:
service-url:
defaultZone: http://eureka-server2:8762/eureka
register-with-eureka: true # 是否将自己的路径 注册到eureka上。eureka server 不需要的,eureka provider client 需要
fetch-registry: true # 是否需要从eureka中抓取路径。eureka server 不需要的,eureka consumer client 需要
spring:
application:
name: eureka-server-ha
hostname主机名不能一致,需要使用hosts配置为不同。
defaultZone 为集群中其他Eureka server的地址,多个使用,逗号分隔。
application.name应用名称要一致
修改hosts文件。C:\Windows\System32\drivers\etc
127.0.0.1 eureka-server1
127.0.0.1 eureka-server2
启动测试
看看集群的效果
客户端需要配置集群中所有Eureka的地址,使用,逗号分隔。
client:
service-url:
defaultZone: http://eureka-server1:8761/eureka,http://eureka-server2:8762/eureka
疑问: spring could支持的其他注册中心软件?
分析:
consul有点类似zookeeper,需要我们自己运行服务。
解压consul_1.6.1_windows_amd64.zip
进入服务所在的目录,运行命令
.\consul agent -dev
控制台地址: http://localhost:8500/
疑问: consul作为注册中心,客户端如何配置并使用?
分析:
搭建 Provider 和 Consumer 服务。
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-consul-discoveryartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
使用 RestTemplate 完成远程调用。(省略)
将Provider服务注册到Consul中。consumer调用方也要配,只需要改应用名。
server:
port: 8000
spring:
cloud:
consul:
host: localhost # consul 服务端的 ip
port: 8500 # consul 服务端的端口 默认8500
discovery:
service-name: ${spring.application.name} # 当前应用注册到consul的名称
prefer-ip-address: true # 注册ip
application:
name: consul-provider # 应用名称
Consumer 服务 通过从 Consul 中抓取 Provider 地址 完成 远程调用
代码无需改动。注意设置实例的name不区分大小写.
discoveryClient.getInstances(“CONSUL-PROVIDER”);
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/goods/{id}")
public Goods findGoodsById(@PathVariable("id") int id){
//演示discoveryClient 使用
List<ServiceInstance> instances = discoveryClient.getInstances("CONSUL-PROVIDER");
//判断集合是否有数据
if(instances == null || instances.size() == 0){
//集合没有数据
return null;
}
ServiceInstance instance = instances.get(0);
String host = instance.getHost();//获取ip
int port = instance.getPort();//获取端口
System.out.println(host);
System.out.println(port);
String url = "http://"+host+":"+port+"/goods/findOne/"+id;
// 3. 调用方法
Goods goods = restTemplate.getForObject(url, Goods.class);
return goods;
}
国产注册中心
分析:
• Nacos(Dynamic Naming and Configuration Service) 是阿里巴巴2018年7月开源的项目。
• 它专注于服务发现和配置管理领域 致力于帮助您发现、配置和管理微服务。Nacos 支持几乎所有主流类型的“服
务”的发现、配置和管理。
• 一句话概括就是Nacos = Spring Cloud注册中心 + Spring Cloud配置中心。
• 官网:https://nacos.io/
• 下载地址: https://github.com/alibaba/nacos/releases
使用步骤:
解压nacos-server-1.1.3.zip
运行nacos\bin\startup.cmd
进入控制台:http://localhost:8848/nacos
账号,密码都是: nacos
使用步骤:
搭建 Provider 和 Consumer 服务。
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
<version>0.2.2.RELEASEversion>
dependency>
<dependency>
<groupId>com.alibaba.nacosgroupId>
<artifactId>nacos-clientartifactId>
<version>1.1.0version>
dependency>
使用 RestTemplate 完成远程调用。(省略)
将Provider服务注册到Consul中。consumer调用方也要配,只需要改应用名。
server:
port: 8000
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 # 配置nacos 服务端地址
application:
name: nacos-provider # 服务名称
Consumer 服务 通过从 Consul 中抓取 Provider 地址 完成 远程调用
代码无需改动。注意设置实例的name不区分大小写.
discoveryClient.getInstances(“nacos-provider”);
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/goods/{id}")
public Goods findGoodsById(@PathVariable("id") int id){
//演示discoveryClient 使用
List<ServiceInstance> instances = discoveryClient.getInstances("nacos-provider");
//判断集合是否有数据
if(instances == null || instances.size() == 0){
//集合没有数据
return null;
}
ServiceInstance instance = instances.get(0);
String host = instance.getHost();//获取ip
int port = instance.getPort();//获取端口
System.out.println(host);
System.out.println(port);
String url = "http://"+host+":"+port+"/goods/findOne/"+id;
// 3. 调用方法
Goods goods = restTemplate.getForObject(url, Goods.class);
return goods;
}
疑问: 如果服务的提供端是集群,每次都访问第一个是不科学的。
分析:
负载均衡是一个算法,可以通过该算法实现从地址列表中获取一个地址进行服务调用。
在Spring Cloud中提供了负载均衡器:Ribbon
Ribbon提供了轮询、随机等负载均衡算法(默认是轮询)可以实现从地址列表中使用负载均衡算法获取地址进行服务调用。
需求:
通过服务名称,使用RestTemplate访问 http://user-service/user/8 获取服务数据。
实现步骤:
启动多个eureka-provider 实例(8001,8002);
复制eureka-provider2
修改pom.xml中的模块名:
修改application.yml中的端口号:
注意:两个应用的name一定要一致,这样才是集群。
修改RestTemplate实例化方法,添加负载均衡注解;
@Configuration
public class RestTemplateConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
修改ConsumerController;
@GetMapping("/goods2/{id}")
public Goods findGoodsById2(@PathVariable("id") int id){
String url = "http://eureka-provider/goods/findOne/"+id;
Goods goods = restTemplate.getForObject(url, Goods.class);
return goods;
}
注意:服务器的地址就是应用服务的名称name.
测试
http://localhost:9000/order/goods2/1
修改负载均衡策略
@Bean
public IRule myRule(){
//return new RoundRobinRule();//轮询
return new RandomRule();//随机
}