java6.2 springCloud
前言
- 什么是微服务架构
是一种架构风格,它提倡将单一的应用程序划分成一组小的服务,每个服务运行在其独立的线程中。服务之间相互配合,采用轻量级的通信机制相互沟通。(避免统一的、集中的服务管理机制)
优点:
职责单一、开发简单、耦合度低、易于集成第三方、只有业务逻辑
缺点:
分布式系统复杂、运维难度大、通信成本高、数据一致、性能监控
- 微服务要解决的问题
(springCloud解决方案)
- 客户如何访问:服务网关(Netflix Zuul)
- 服务如何通信:HTTP/RPC
- 服务如何治理:注册与发现(Netflix Eureka)
- 风险如何处理:熔断机制(Netflix Hystrix)
五大组件
- 服务网关(Netflix Zuul)
- 负载均衡
- 客户端—Ribbon
- 服务端—Feign
- 注册与发现(Netflix Eureka)
- 熔断器(Netflix Hystrix)
- 分布式配置(spring cloud config)
-
springCloud
springBoot能够快速独立开发一个单体微服务,而springCloud是关注全局的微服务协调治理框架。为各服务之间提供了:配置管理,服务发现,熔断器,路由,微代理,事件总线,全局锁,决策竞选,分布式会话等等的集成服务。
一. Eureka
- Netflix 在设计Eureka 时,遵循的是AP原则
- Eureka 是 Netflix 的核心模块之一。它是基于 Rest 的服务,用于 == 服务注册与发现 == 。
1.1 Eureka Server
Eureka服务器没有后端存储,但注册表中的服务实例都必须发送心跳以保持其注册更新(因此可以在内存中完成)。客户端还具有eureka注册的内存缓存(因此,他们不必为注册表提供每个服务请求)。
- 导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
- 配置
server:
port: 8010
#Eureka配置
eureka:
instance:
hostname: localhost # Eureka服务器实例名称
client:
register-with-eureka: false # 是否向注册中心注册自己
fetch-registry: false # 是否获得注册表
service-url: # 注册中心地址(既自己的地址)
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
server:
# 开启自我保护机制,默认开启
enable-self-preservation: true
- 还需要在启动类添加注解
@EnableEurekaServer
。同时,服务器具有一个带有UI的主页。
1.2 Eureka Client(服务提供)
- 导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
- 客户端需要配置才能找到Eureka服务器
spring:
application:
name: springCloud-pro-dept # 当前服务名(多个相同服务的生产者,服务名必须相同)
# 注册到注册中心
eureka:
instance:
# 修改描述(可选)
instance-id: ${spring.application.name}:${server.port}
# 配置使用主机名注册服务
hostname: localhost
# 将主机名替换为ip地址
prefer-ip-address: true
client:
service-url:
# 注册中心地址
defaultZone: http://localhost:8010/eureka/
-
还需要在启动类添加注解
@EnableEurekaClient
使应用程序成为Eureka“实例”(即注册自身)------------------- 扩展 --------------------
-
获得服务列表清单
- 在启动类添加注解
@EnableDiscoveryClient
从Eureka服务器发现服务实例。 - 编码
@RestController public class DiscoveryController { @Autowired private DiscoveryClient discoveryClient; @GetMapping("/discoveryClient") public Object discovery(){ // 获得微服务列表清单 List<String> services = discoveryClient.getServices(); System.out.println("discoveryClient=>services"); System.out.println(services); // 根据id,得到某一个服务 List<ServiceInstance> instances = discoveryClient.getInstances("SPRINGCLOUD-PRO-DEPT"); for (ServiceInstance instance : instances) { System.out.println( "Host: "+instance.getHost()+"\t"+ "Port: "+instance.getPort()+"\t"+ "Uri: "+instance.getUri()+"\t"+ "ServiceId: "+instance.getServiceId() ); } return this.discoveryClient; } }
- 在启动类添加注解
1.3 Eureka集群
Eureka可以通过运行多个实例并要求他们相互注册而变得更有弹性。(host必须不一样)
# 注册中心8010配置
---
server:
port: 8010
#Eureka配置
eureka:
instance:
hostname: peer1.com # Eureka服务器实例名称
client:
service-url: # 指向备份主机,使用','分隔多个主机
defaultZone: http://peer2.com:8011/eureka/
# 注册中心8011配置
---
server:
port: 8011
#Eureka配置
eureka:
instance:
hostname: peer2.com # Eureka服务器实例名称
client:
service-url:
defaultZone: http://peer1.com:8010/eureka/
更改host配置
C:\Windows\System32\drivers\etc\hosts
127.0.0.1 peer1.com
127.0.0.1 peer2.com
最后,相应的生产者程序也需要讲地址指向多个配置中心地址,使用’,'分隔多个主机地址
【 小结 】
- Eureka 的自我保护机制
eureka 各节点平等,当某几个服务挂了,不会影响其他正常节点的工作。eureka 有一种自我保护机制,如果15分钟内超过85%的节点没有正常心跳,就会出现网络故障而保留节点,并不会立刻清理(宁可保留所有的服务,也不盲目注销任何可能健康的服务)。
因此当Eureka部分节点失联时,注册中心仍然能继续工作,不会像zookeeper那样使得整个注册服务瘫痪。
- CAP原则
C:强一致性 A:可用性 P:容错性
Eureka: AP原则
zookeeper: CP原则
二. Ribbon
- ribbon 是基于 Netflix Ribbon 实现的一套 客户端负载均衡的工具 。
- 它主要功能是提供客户端的软件负载均衡算法(轮询、随机),将用户的请求平摊的分配到多个服务上,从而达到系统的高可用。
- 负载均衡分类
- 集中式:在服务是消费者和生产者之间使用独立的 LB,由这个代理把服务转发给生产者。
- 进程式:把LB 集成到消费方,消费方中注册中心获知可用地址,然后自己选择生产者。(Ribbon属于进程内LB)
Ribbon+Rest(服务调用)
经过以上 Eurelka 的搭建,已经完成了注册中心到服务生产者的实现。而服务生产者也只需要像以往一样将在controller中配置接口,并将服务暴露出去即可。有了生产者,接下来将是消费者如何去远程调用服务。
- 导入依赖
<!-- ribbon依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!-- 为了从注册中心获取服务,还需要调入Eureka依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
- 编写配置
server:
port: 80
#Eureka配置
eureka:
client:
register-with-eureka: false # 是否向注册中心注册自己
fetch-registry: true # 是否获得注册表(默认true)
service-url: # 注册中心地址
defaultZone: http://peer1.com:8010/eureka/,http://peer2.com:8011/eureka/
- 还需要在启动类添加注解
@EnableEurekaClient
使应用程序成为Eureka“实例”。(感觉应该可以不用) - 将 RestTemplate 注入 Bean ,并添加
@LoadBalanced
注解
@Configuration
public class ConfigBean {
@Bean
@LoadBalanced //负载均衡
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
- 使用 RestTemplate 调用服务
@RestController
public class DeptController {
@Autowired
RestTemplate rest;
//private static final String REST_URL_PRE = "http://localhost:8001";
//通过服务名来访问,等价于http://localhost:8001
private static final String REST_URL_PRE = "http://SPRINGCLOUD-PRO-DEPT";
@RequestMapping("/con/getDepts")
public List<Dept> getDepts(){
List forObject = rest.getForObject(REST_URL_PRE + "/dept/all", List.class);
return forObject;
}
}
------------------- 扩展 --------------------
- 自定义负载均衡算法
自定义一个负载均衡算法规则的配置了,并且该类不能在主应用程序上下文中
package com.ribbonRule; //不在主应用程序上下文中
import ...;
@Configuration
public class MyRule {
@Bean
public IRule diyRule(){
//调用随机规则
return new RandomRule();
//可使用自定义的规则类
//该类必须继承AbstractLoadBalancerRule抽象类
//自定义规则类可参考例如RandomRule的任意一个规则类
//return new MyRobinRule();
}
}
在启动类中添加注解
@RibbonClient(name = "SPRINGCLOUD-PRO-DEPT",configuration = MyRule.class)
三. Feign
- springCloud 集成了Ribbon 和 Eureka,可在 使用 Feign 时提供负载均衡 的 http 客户端。
- 使用接口和注解调用微服务,在使编写java Http客户端变得更容易
- Feign 以 Ribbon+RestTemplate 为基础进一步封装,我们只需要创建一个接口并使用注解方式配置即可完成服务提供方的接口绑定。
- Feign 集成了 Ribbon
Feign(服务调用)
- 导入依赖,由于集成了Ribbon,所以不用导入Ribbon
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!-- 为了从注册中心获取服务,还需要调入Eureka依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
- 配置,与使用Ribbon配置相同
server:
port: 80
#Eureka配置
eureka:
client:
register-with-eureka: false # 是否向注册中心注册自己
fetch-registry: true # 是否获得注册表(默认true)
service-url: # 注册中心地址
defaultZone: http://peer1.com:8010/eureka/,http://peer2.com:8011/eureka/
- 定义一个服务接口,用于接收客户端数据
@Service
//客户端名称,可以使用url属性(绝对值或只是主机名)指定URL
@FeignClient("SPRINGCLOUD-PRO-DEPT")
public interface DeptClientService {
//客户端提供数据的接口
@GetMapping("/dept/all")
List<Dept> getList();
}
- 还需要在启动类添加注解
@EnableFeignClients(basePackages={"com.zheng"})
- 在 controller 中导入该接口,调用接口服务即可。
四. Hystrix
- 名词解析
服务雪崩
一个服务失败导致某个点开始阻塞,进而导致整条链路的服务都失败的情形,我们称之为服务雪崩。
服务熔断
当下游的服务因为某种原因突然变得不可用或响应过慢,上游服务为了保证自己整体服务的可用性,不再继续调用目标服务,直接返回,快速释放资源。如果目标服务情况好转则恢复调用。
例如:每当20个请求中,有50%失败时,熔断器就会打开,此时再调用此服务,将会直接返回失败,不再调远程服务。直到5s钟之后,重新检测该触发条件,判断是否把熔断器关闭,或者继续打开。
服务降级
- 两个场景
- 当下游的服务因为某种原因响应过慢,下游服务主动停掉一些不太重要的业务,释放出服务器资源,增加响应速度!
- 当下游的服务因为某种原因不可用,上游主动调用本地的一些降级逻辑,避免卡顿,迅速返回给用户!
- 服务降级有很多种降级方式!如开关降级、限流降级、熔断降级!
4.1 Hystrix(服务提供-熔断)
注:前提是先将Eureka Client搭建、配置完成。
- 导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
- 使用注解连接备用方法
@GetMapping("/dept/all")
@HystrixCommand(fallbackMethod = "queryAlls")
public List<Dept> queryAll(){
int err = 10/0; //程序出错,调用备用方法
return null;
}
// 备份方法
public List<Dept> queryAlls(){
List<Dept> list = new ArrayList<>();
list.add(new Dept(500,"备份方法hystrix","no db"));
return list;
}
- 还需要在启动类添加注解
@EnableCircuitBreaker
开启断路器
4.2 Hystrix+Feign(服务调用-降级)
- 当目标服务器由于降级down了,调用服务端应做降级的提示。(正常情况目标服务器down了,调用端服务器应报错)
- 本身就是Feign的功能 ,必须基于Feign,而不需要导入 Hystrix 依赖
- 配置
#开启服务降级
feign:
hystrix:
enabled: true
- 编码,定义一个服务降级实现类
/**
* 服务降级实现类
* 当DeptClientService中某一条服务调用报错时,将应急使用当前服务
*/
@Component
public class DeptClientFallback implements FallbackFactory {
@Override
public DeptClientService create(Throwable throwable) {
return new DeptClientService() {
@Override
public List<Dept> getList() {
List<Dept> list = new ArrayList<>();
list.add(new Dept("服务降级,当前服务不可用!"));
return list;
}
};
}
}
- 在 Feign 调用服务的接口中通过
fallbackFactory
属性定义应急类
@FeignClient(value = "SPRINGCLOUD-PRO-DEPT",fallbackFactory = DeptClientFallback.class)
4.3 Dashboard 流监控
【监控面板】
- 导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
- 还需要在启动类添加注解
@EnableHystrixDashboard
- 访问
/hystrix
,并将仪表板指向Hystrix客户端应用程序中的单个实例/hystrix.stream
端点
【被监控程序】
- 只有有注册断路器的请求才能被监控
导入依赖
<!--需要导入hystrix-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>2.7.3</version>
</dependency>
注入类
@Bean
public ServletRegistrationBean hystrixMetricsStreamServlet(){
ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
//监控面板加入当前 http://ip地址/actuator/hystrix.stream 即可监控
registrationBean.addUrlMappings("/actuator/hystrix.stream");
return registrationBean;
}
图示实心圆
- 健康程度:绿>黄>橙>红
- 流量越大,圆越大
五.Zuul
- Zuul 是路由网关,包含了对请求的代理、路由和过滤两个主要的功能。
- Zuul 也需要注册为 Eureka 服务治理下的应用,同时从 Eureka 中获取其他微服务的消息
- 导入依赖
<!--需要导入eureka-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
- 配置
server:
port: 8055
spring:
application:
name: springCloud-zull # 当前服务名(多个相同服务的生产者,服务名必须相同)
eureka:
instance:
instance-id: zuul8055.com
prefer-ip-address: true
client:
service-url:
defaultZone: http://peer1.com:8010/eureka/,http://peer2.com:8011/eureka/
zuul:
routes:
# http://localhost:8055/mydept/ 将代替该服务集群的主机路径
mydept: {serviceId: SPRINGCLOUD-PRO-DEPT, path: /mydept/**}
# 不能使用所有的原来的访问路径
ignored-services: "*"
- 还需要在启动类添加注解
@EnableZuulProxy