、
SpringCloud
Springcloud之负载均衡、熔断器
SpringCloud—Fegin、Gateway、分布式配置中心、Bus服务总线
1. 系统演变
单一应用–>垂直拆分–> 分布式服务–>SOA–>微服务
1.1. 单一应用
将所有的功能都部署在一起,以减少部署节点和成本。
优点:
-
系统开发速度快
-
维护成本低
-
适用于并发要求较低的系统
缺点:
-
代码耦合度高,后期维护困难
-
无法针对不同模块进行优化
-
无法水平扩展
-
单点容错率低,并发能力差
1.2. 垂直拆分
优点:
- 系统拆分实现了流量分担,解决了并发问题
- 可以针对不同模块进行优化
- 方便水平扩展,负载均衡,容错率提高
缺点:
- 系统间相互独立,会有很多重复开发工作,影响开发效率
1.3. 分布式服务
优点:
- 将基础服务进行了抽取,系统间相互调用,提高了代码复用和开发效率
缺点:
- 系统间耦合度变高,调用关系错综复杂,难以维护
1.4. SOA(服务治理)
SOA(Service Oriented Architecture)面向服务的架构:它是一种设计方法,其中包含多个服务, 服务之间通过 相互依赖最终提供一系列的功能。一个服务通常以独立的形式存在于操作系统进程中。各个服务之间通过网络调 用。
**SOA缺点:**每个供应商提供的ESB产品有偏差,自身实现较为复杂;应用服务粒度较大,ESB集成整合所有服务和 协议、数据转换使得运维、测试部署困难。所有服务都通过一个通路通信,直接降低了通信速度。
1.5. 微服务
微服务架构是使用一套小服务来开发单个应用的方式或途径,每个服务基于单一业务能力构建,运行在自己的进程中,并使用轻量级机制通信,通常是HTTP API,并能够通过自动化部署机制来独立部署。这些服务可以使用不同的编程语言实现,以及不同数据存储技术,并保持最低限度的集中式管理。 微服务结构图 :
特点:
-
单一职责:微服务中每一个服务都对应唯一的业务能力,做到单一职责
-
面向服务:面向服务是说每个服务都要对外暴露服务接口API。并不关心服务的技术实现,做到与平台和语言
-
无关,也不限定用什么技术实现,只要提供REST的接口即可。
-
自治:自治是说服务间互相独立,互不干扰
-
团队独立:每个服务都是一个独立的开发团队。
-
技术独立:因为是面向服务,提供REST接口,使用什么技术没有别人干涉
-
前后端分离:采用前后端分离开发,提供统一REST接口,后端不用再为PC、移动段开发不同接口
-
数据库分离:每个服务都使用自己的数
-
1.6. SpringCloud
配置管理,服务发现,智能路由,负载均衡,熔断器,控制总线,集群状态等等功能。其主要涉及的组件包括:
-
Eureka:注册中心
-
Zuul:服务网关
-
Ribbon:负载均衡
-
Feign:服务调用
-
Hystrix:熔断器
-
2.远程调用方式
**RPC:**Remote Procedure Call远程过程调用,类似的还有RMI。自定义数据格式,基于原生TCP通信,速度快,效率高。早期的Web Service,现在热门的Dubbo,都是RPC的典型。
**HTTP:**HTTP其实是一种网络传输协议,基于TCP,规定了数据传输的格式。现在客户端浏览器与服务端通信 基本都是采用HTTP协议。也可以用来进行远程服务调用。缺点是消息封装臃肿。现在热门的REST风格,就可以通过HTTP协议来实现。
3.微服务场景模拟
1、创建一个空的项目:
2、创建userservice 模块,然后写入代码
3、创建一个新的consumer模块调用userservice模块。
consumer和userservice的不同之处:
//controller
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/{id}")
public User queryById(@PathVariable Long id){
String url = "http://localhost:9091/user/" + id; // http://localhost:9091/user/ 是userservice的地址
return restTemplate.getForObject(url,User.class);
}
}
//Application
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
4. Eureka(服务注册中心)
-
Eureka:就是服务注册中心(可以是一个集群),对外暴露自己的地址
-
提供者:启动后向Eureka注册自己信息(地址,提供什么服务)
-
消费者:向Eureka订阅服务,Eureka会将对应服务的所有提供者地址列表发送给消费者,并且定期更新
-
心跳(续约):提供者定期通过HTTP方式向Eureka刷新自己的状态
4.1 原理
- 由服务提供者实例化服务
- 将服务注册到eureka中
- eureka注册中心记录服务
- 客户端定期从eureka中拉去服务列表
- 基于负载均衡算法从地址列表中选择一个地址提供调用服务
- 服务定期发送心跳给服务注册中心
- 检查没有定期发送心跳的服务将其在一定时间内从服务列表中剔除
4.2 入门案例
-
新建模块
-
生成application和配置文件
package com.java.eureka; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @SpringBootApplication @EnableEurekaServer public class EurekaApplication { public static void main(String[] args) { SpringApplication.run(EurekaApplication.class, args); } } //yml文件 server: port: 10086 spring: application: name: eureka-server eureka: client: service-url: #eureka服务的地址,如果做集群,需要制定其他eureka的地址 defaultZone: http://127.0.0.1:10086/eureka #不注册自己 register-with-eureka: false #不拉取服务 fetch-registry: false
-
导入eureka依赖
<?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>springcloud</artifactId> <groupId>com.java</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>eureka-server</artifactId> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> </dependencies> </project>
-
运行看效果:
5、服务注册:
-
首先注入eureka依赖
-
在application中加入EnableDiscoveryClient注解
-
- 添加配置信息
-
效果:
6.发现服务 -
在consumer-demo中导入依赖
-
在application中加入EnableDiscoveryClient注解
-
修改controller代码
-
修改yml配置文件
-
效果:
三大核心:
- 服务注册中心
Eureka的服务端应用,提供服务注册和发现功能,就是刚刚我们建立的eureka-server
- 服务提供者
提供服务的应用,可以是Spring Boot应用,也可以是其它任意技术实现,只要对外提供的是REST风格服务即
可。本例中就是我们实现的user-service
- 服务消费者
消费应用从注册中心获取服务列表,从而得知每个服务方的信息,知道去哪里调用服务方。本例中就是我们
实现的consumer-demo
配置不同的端口号并互相注册
4.4 客户端和服务端配置
Eureka客户端工程 :
user-service 服务提供 :
服务地址使用ip方式
续约
consumer-demo 服务消费 :
获取服务地址的频率
Eureka服务端工程 eureka-server:
失效剔除
自我保护
服务注册
服务提供者在启动时,会检测配置属性中的: eureka.client.register-with-erueka=true 参数是否为true,事实上 默认就是true。如果值确实为true,则会向EurekaServer发起一个Rest请求,并携带自己的元数据信息,EurekaServer会把这些信息保存到一个双层Map结构中 。 第一层Map的Key就是服务id,一般是配置中的 spring.application.name 属性,user-service 第二层Map的key是服务的实例id。一般host+ serviceId + port,例如: localhost:user-service:8081 值则是服务的实例对象,也就是说一个服务,这样可以同时启动多个不同实例,形成集群。
服务续约
在注册服务完成以后,服务提供者会维持一个心跳(定时向EurekaServer发起Rest请求),告诉 EurekaServer:“我还活着”。这个我们称为服务的续约(renew); 有两个重要参数可以修改服务续约的行为;可以在 user-service 中添加如下配置项:
#服务续约(renew)的间隔,默认为30秒
lease-renewal-interval-in-seconds: 5
# 服务失效时间,默认值90秒
lease-expiration-duration-in-seconds: 10
获取服务列表
服务下线
当服务进行正常关闭操作时,它会触发一个服务下线的REST请求给Eureka Server,告诉服务注册中心:“我要下线 了”。服务中心接受到请求之后,将该服务置为下线状态
失效剔除
有时我们的服务可能由于内存溢出或网络故障等原因使得服务不能正常的工作,而服务注册中心并未收到“服务下线”的请求。相对于服务提供者的“服务续约”操作,服务注册中心在启动时会创建一个定时任务,默认每隔一段时间 (默认为60秒)将当前清单中超时(默认为90秒)没有续约的服务剔除,这个操作被称为失效剔除。 可以通过eureka.server.eviction-interval-timer-in-ms 参数对其进行修改,单位是毫秒。
自我保护
我们关停一个服务,就会在Eureka面板看到一条警告:
案例地址