目录
微服务概述
微服务强调的是服务的大小,是具体解决某一个问题的一个服务应用;微服务架构将单一的应用程序划分成一组小的服务,每个服务运行在其独立的自己的进程内,服务之间互相协调,互相配置,服务之间采用轻量级的HTTP通信机制互相沟通,每个服务都围绕着具体的业务进行构建,被独立的部署到生产环境中,每个微服务可以有自己的数据库,也可以有统一的数据库
区别SpringCloud
SpringCloud和Springboot
SpringBoot专注开发单个个体微服务;SpringCloud是关注全局的微服务协调整理,它将SpringBoot开发的单体微服务,整合并管理起来,为各个微服务之间提供:配置管理、服务发现、断路器、路由、为代理、事件总栈、全局锁、决策竞选、分布式会话等等集成服务
SpringCloud和RPC
SpringCloud 抛弃了Dubbo的RPC通信,采用的是基于HTTP的REST方式
RestTemplate
服务提供者
package com.rainhey.springcloud.controller;
import com.rainhey.springcloud.pojo.Dept;
import com.rainhey.springcloud.service.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
public class DeptController {
@Autowired
private DeptService deptService;
@PostMapping("/dept/add")
public boolean addDept(Dept dept){
return deptService.addDept(dept);
}
@GetMapping("/dept/get/{id}")
public Dept get(@PathVariable long id){
return deptService.queryById(id);
}
@GetMapping("/dept/list")
public List<Dept> queryAll(){
return deptService.queryAll();
}
}
服务消费者
package com.rainhey.springcloud.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class ConfigBean {
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
package com.rainhey.springcloud.controller;
import com.rainhey.springcloud.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@RestController
public class DeptConsumerController {
//消费者不应该有service层
//RestTemplate供我们直接调用,注册到spring中
//RestTemplate 常用参数格式
/** 1. (url,Class<T> responseType)
* 2. (url,实体:map,Class<T> responseType*/
@Autowired
private RestTemplate restTemplate; //提供多种边界访问http服务的方法,简单的restful模板
public static final String prefixurl="http://localhost:8001";
@RequestMapping("/consumer/dept/add")
public boolean add(Dept dept){
return restTemplate.postForObject(prefixurl+"/dept/add", dept, boolean.class);
}
@RequestMapping("/consumer/dept/get/{id}")
public Dept get(@PathVariable long id){
return restTemplate.getForObject(prefixurl+"/dept/get/"+id, Dept.class);
}
@RequestMapping("/consumer/dept/list")
public List<Dept> list(){
return restTemplate.getForObject(prefixurl+"/dept/list", List.class);
}
}
Eureka
Eureka Server
- 导入依赖
<!--导入Eureka Server依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--热部署工具-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
- 编写配置文件
server:
port: 7001
#Eureka 配置
eureka:
instance:
hostname: localhost #Eureka服务端的实例名称
client:
register-with-eureka: false # 是否向Eureka服务中心注册自己
fetch-registry: false #如果为false,表示自己是注册中心
service-url: # 监控页面
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
- 添加注解@EnableEurekaServer,开启功能
package com.rainhey.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
// EurekaServer 服务端启动类,注册中心
@EnableEurekaServer
public class EurekaServer_7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaServer_7001.class, args);
}
}
- 访问 http://localhost:7001/
服务注册
- 服务提供者添加依赖
<!--accator 监控信息-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--eureka-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
- 编写Eureka配置
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka/
instance:
instance-id: springcloud-provider-dept8001 //修改Eureka默认描述信息Status
info: #autuator监控信息
app.name: rainhey-springcloud
company.name: www.rainhey.com
- 添加注解@EnableEurekaClient,开启功能
package com.rainhey.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient //在服务启动后自动注册到Eureka
public class DeptProvider_8001 {
public static void main(String[] args) {
SpringApplication.run(DeptProvider_8001.class, args);
}
}
- 访问 http://localhost:7001/
Eureka 自我保护机制
默认情况下,当Eureka server在一定时间内没有收到实例的心跳,便会把该实例从注册表中删除(默认是90秒),但是如果当一分钟内收到的心跳数大量减少时,会触发保护机制:Eureka认为虽然收不到实例的心跳,但不会把它们从注册表中删掉
保护机制的目的是避免网络连接故障,因为只有在微服务启动的时候才会发起注册请求,如果Eureka因网络故障而把微服务误删了,那即使网络恢复了,该微服务也不会重新注册到Eureka server了
本地搭建Eureka 集群
- 修改HOSTS,添加
- 创建三个Eureka Server,配置文件如图
server:
port: 7001
#Eureka 配置
eureka:
instance:
hostname: eureka7001.com #Eureka服务端的实例名称
client:
register-with-eureka: false # 是否向Eureka服务中心注册自己
fetch-registry: false #如果为false,表示自己是注册中心
service-url:
defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
server:
port: 7002
#Eureka 配置
eureka:
instance:
hostname: eureka7002.com #Eureka服务端的实例名称
client:
register-with-eureka: false # 是否向Eureka服务中心注册自己
fetch-registry: false #如果为false,表示自己是注册中心
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7003.com:7003/eureka/
server:
port: 7003
#Eureka 配置
eureka:
instance:
hostname: eureka7003.com #Eureka服务端的实例名称
client:
register-with-eureka: false # 是否向Eureka服务中心注册自己
fetch-registry: false #如果为false,表示自己是注册中心
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
- provider 服务提供者配置文件修改
server:
port: 8001
mybatis:
type-aliases-package: com.rainhey.springcloud.pojo
config-location: classpath:mybatis/mybatis-config.xml
mapper-locations: classpath:mybatis/mapper/*.xml
spring:
application:
name: springcloud-provider-dept
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: org.gjt.mm.mysql.Driver
url: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
username: root
password: 123456
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
instance:
instance-id: springcloud-provider-dept8001 #修改Eureka默认描述信息Status
info: #autuator
app.name: rainhey-springcloud
company.name: www.rainhey.com
- 访问 http://localhost:7001/,http://localhost:7002/,http://localhost:7003/
服务消费者
调用微服务有两种方法,即通过微服务名字(Ribbon)或者接口和注解(Feign)
Ribbon
客户端负载均衡的工具
- 主要功能是提供客户端软件负载均衡算法
- 负载均衡简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的高可用。
- SpringCloud 的负载均衡算法可以自定义
- 常见的负载均衡软件有 Nginx、Lvs 等等。
- 负载均衡简单分类:
集中式LB:即在服务的提供方和消费方之间使用独立的LB设施,如Nginx(反向代理服务器),由该设施负责把访问请求通过某种策略转发至服务的提供方
进程式 LB:将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选出一个合适的服务器 - Ribbon 就属于进程内LB,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址
服务消费者基于Ribbon调用服务
- 导入依赖
<!--ribbon负载均衡 轮询默认-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
<!--eureka-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
- 编写配置文件
server:
port: 8000
# eureka 配置
eureka:
client:
register-with-eureka: false #不向eureka注册自己
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
- 添加注解@EnableEurekaClient,开启功能
package com.rainhey.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class DeptConsumer_8000 {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer_8000.class, args);
}
}
- 配置类
package com.rainhey.springcloud.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class ConfigBean {
//配置负载均衡实现RestTemplate
@LoadBalanced //ribbon
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
- 服务消费者Controller
package com.rainhey.springcloud.controller;
import com.rainhey.springcloud.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@RestController
public class DeptConsumerController {
//消费者不应该有service层
//RestTemplate供我们直接调用,注册到spring中
//RestTemplate 常用参数格式
/** 1. (url,Class<T> responseType)
* 2. (url,实体:map,Class<T> responseType*/
@Autowired
private RestTemplate restTemplate; //提供多种边界访问http服务的方法,简单的restful模板
//public static final String prefixurl="http://localhost:8001";
//基于Ribbon负载均衡,通过服务名访问
public static final String prefixurl="http://SPRINGCLOUD-PROVIDER-DEPT";
@RequestMapping("/consumer/dept/add")
public boolean add(Dept dept){
return restTemplate.postForObject(prefixurl+"/dept/add", dept, boolean.class);
}
@RequestMapping("/consumer/dept/get/{id}")
public Dept get(@PathVariable long id){
return restTemplate.getForObject(prefixurl+"/dept/get/"+id, Dept.class);
}
@RequestMapping("/consumer/dept/list")
public List<Dept> list(){
return restTemplate.getForObject(prefixurl+"/dept/list", List.class);
}
}
- 另外创建服务提供者8002和服务提供者8003,配置相同的spring.application.name(即配置相同的服务名)
- 若从Eureka Server中查找的服务SPRINGCLOUD-PROVIDER-DEPT对应多台机器时(即多个服务提供者时),Ribbon默认采用轮询算法依次调用每台机器的服务,Ribbon主要啊做两件事:从Eureka集群中查找服务列表、通过某种算法实现负载均衡
Ribbon负载均衡策略
- 使用Ribbon自带负载均衡策略
@Configuration
public class ConfigBean {
//配置负载均衡实现RestTemplate
@LoadBalanced //ribbon
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
/*负载均衡策略主要是实现IRule这个接口,Ribbon自带一些负载均衡策略
* RoundRobinRule 轮询策略
* RandomRule 随机策略
* AvailabilityFilteringRule : 会先过滤掉,跳闸,访问故障的服务~,对剩下的进行轮询~
* RetryRule : 会先按照轮询获取服务~,如果服务获取失败,则会在指定的时间内进行,重试*/
//要想使用自带的某种负载均衡策略,只需将其注入容器
//比如想要使用随机策略
@Bean
public IRule myIRule(){
return new RandomRule();
}
}
- 自定义负载均衡策略
在主启动类上一级建包myRule,在其中自定义负载均衡策略,注意自定义组件包不要和主启动类同级,否则会被直接扫描到,影响程序的灵活性
配置类
@Configuration
public class MyRule {
@Bean
public IRule myRule(){
return new MyRandomRule();//默认是轮询RandomRule,现在自定义为自己的
}
}
参照RandomRule继承类AbstractLoadBalancerRule,写自己的负载均衡策略
public class MyRandomRule extends AbstractLoadBalancerRule {
/**
* 每个服务访问5次则换下一个服务(总共3个服务)
* <p>
* total=0,默认=0,如果=5,指向下一个服务节点
* index=0,默认=0,如果total=5,index+1
*/
private int total = 0;//被调用的次数
private int currentIndex = 0;//当前是谁在提供服务
//@edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE")
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
return null;
}
Server server = null;
while (server == null) {
if (Thread.interrupted()) {
return null;
}
List<Server> upList = lb.getReachableServers();//获得当前活着的服务
List<Server> allList = lb.getAllServers();//获取所有的服务
int serverCount = allList.size();
if (serverCount == 0) {
/*
* No servers. End regardless of pass, because subsequent passes
* only get more restrictive.
*/
return null;
}
//int index = chooseRandomInt(serverCount);//生成区间随机数
//server = upList.get(index);//从或活着的服务中,随机获取一个
//=====================自定义代码=========================
if (total < 5) {
server = upList.get(currentIndex);
total++;
} else {
total = 0;
currentIndex++;
if (currentIndex > upList.size()) {
currentIndex = 0;
}
server = upList.get(currentIndex);//从活着的服务中,获取指定的服务来进行操作
}
//======================================================
if (server == null) {
/*
* The only time this should happen is if the server list were
* somehow trimmed. This is a transient condition. Retry after
* yielding.
*/
Thread.yield();
continue;
}
if (server.isAlive()) {
return (server);
}
// Shouldn't actually happen.. but must be transient or a bug.
server = null;
Thread.yield();
}
return server;
}
protected int chooseRandomInt(int serverCount) {
return ThreadLocalRandom.current().nextInt(serverCount);
}
@Override
public Server choose(Object key) {
return choose(getLoadBalancer(), key);
}
@Override
public void initWithNiwsConfig(IClientConfig clientConfig) {
// TODO Auto-generated method stub
}
}
在主启动类添加@RibbonClient(name = “SPRINGCLOUD-PROVIDER-DEPT”,configuration = MyRule.class)注解,指定服务名和负载均衡的配置文件
@SpringBootApplication
@EnableEurekaClient
//在微服务启动的时候就能加载自定义的Ribbon类(自定义的规则会覆盖原有默认的规则)
@RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT",configuration = MyRule.class)//开启负载均衡,并指定自定义的规则
public class DeptConsumer_80 {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer_80.class, args);
}
}
Feign
- Feign在Ribbon+RestTemplate的基础上做了进一步的封装,由它帮助我们定义和实现依赖服务接口的定义。在Feign的实现下,我们只需要创建一个接口并使用注解的方式来配置它,即可完成对服务提供方的接口绑定,简化了使用Spring Cloud Ribbon 时,自动封装服务调用客户端的开发量
- Feign默认集成了Ribbon,Feign 本质上也是实现了 Ribbon,只不过在调用方式上,满足一些开发者习惯的接口调用习惯!
Feign相当于在中间加了一层接口,使得客户端的调用更加方便!
- 客户端导入以下主要依赖,API模块导入feign依赖
<!--Feign的依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--ribbon负载均衡 轮询默认-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
<!--eureka-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
- 客户端层编写配置,同以上Ribbon实例
server:
port: 8010
# eureka 配置
eureka:
client:
register-with-eureka: false #不向eureka注册自己
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
- API层编写接口
@Component
//@FeignClient:微服务客户端注解,value指定微服务的名字
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT")
public interface DeptClientService {
@GetMapping("/dept/get/{id}")
public Dept get(@PathVariable("id") long id);
@GetMapping("/dept/list")
public List<Dept> queryAll();
@PostMapping("/dept/add")
public boolean addDept(Dept dept);
}
- 客户端测试controller
@RestController
public class DeptConsumerController {
@Autowired
private DeptClientService deptClientService;
@PostMapping("/consumer/dept/add")
public boolean add(Dept dept) {
return deptClientService.addDept(dept);
}
@GetMapping("/consumer/dept/get/{id}")
public Dept get(@PathVariable("id") Long id) {
return deptClientService.get(id);
}
@GetMapping("/consumer/dept/list")
public List<Dept> list() {
return deptClientService.queryAll();
}
}
- 测试结果
Hystrix
Hystrix是一个应用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时,异常等,Hystrix 能够保证在一个依赖出问题的情况下,不会导致整个体系服务失败,避免级联故障,以提高分布式系统的弹性
“断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控,向调用方返回一个服务预期的,可处理的备选响应 (FallBack) ,而不是长时间的等待或者抛出调用方法无法处理的异常,这样就可以保证了服务调用方的线程不会被长时间,不必要的占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。
服务熔断(服务端)
当扇出链路的某个微服务不可用或者响应时间太长时,会熔断该节点微服务的调用,快速返回错误的响应信息。检测到该节点微服务调用响应正常后恢复调用链路。在SpringCloud框架里熔断机制通过Hystrix实现。Hystrix会监控微服务间调用的状况,当失败的调用到一定阀值缺省是5秒内20次调用失败,就会启动熔断机制。熔断机制的注解是:@HystrixCommand
服务熔断解决如下问题:
- 当所依赖的对象不稳定时,能够起到快速失败的目的;
- 快速失败后,能够根据一定的算法动态试探所依赖对象是否恢复。
- 添加依赖,复制一份服务提供者代码,添加Hystrix依赖
<!--Hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
- 编写配置
同springcloud-provider-dept-8001 的配置,无需添加额外配置 - 服务提供方为方法提供备选方案
@HystrixCommand(fallbackMethod = "hystrixGet")
@GetMapping("/dept/get/{id}")
public Dept get(@PathVariable long id){
Dept dept = deptService.queryById(id);
if(dept==null){
throw new RuntimeException("id="+id+"不存在该用户");
}
return dept;
}
// 备选方案
public Dept hystrixGet(@PathVariable long id){
return new Dept().setDeptno(id)
.setDname("id="+id+"没有对应信息,null @hystrix")
.setDb_source("no this db in database");
}
- 主启动类添加熔断支持
@SpringBootApplication
@EnableEurekaClient //在服务启动后自动注册到Eureka
//添加对熔断的支持
@EnableCircuitBreaker
public class DeptProviderHystrix_8001 {
public static void main(String[] args) {
SpringApplication.run(DeptProviderHystrix_8001.class, args);
}
}
- 测试:当服务消费方查询一个数据库不存在的ID
服务降级(客户端)
服务降级是指当服务器压力剧增的情况下,根据实际业务情况及流量,对一些服务和页面有策略的不处理,或换种简单的方式处理,从而释放服务器资源以保证核心业务正常运作或高效运作。自我理解就是当为了把系统资源分配给优先级高的服务,而关闭某些优先级低的服务,而在客户端暂时为这些优先级低的服务提供一种回调
- 在API模块创建DeptClientServiceFallbackFactory类实现FallbackFactory接口,重写create方法
@Component
public class DeptClientServiceFallbackFactory implements FallbackFactory {
@Override
public DeptClientService create(Throwable throwable) {
return new DeptClientService() {
@Override
public Dept get(long id) {
return new Dept().setDeptno(id)
.setDname("id="+id+"当前服务降级,已经被关闭")
.setDb_source("没有数据");
}
@Override
public List<Dept> queryAll() {
return null;
}
@Override
public boolean addDept(Dept dept) {
return false;
}
};
}
}
- 在feign的接口上指定服务降级的回调fallbackFactory
@Component
//@FeignClient:微服务客户端注解,value指定微服务的名字
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT",fallbackFactory = DeptClientServiceFallbackFactory.class)
public interface DeptClientService {
@GetMapping("/dept/get/{id}")
public Dept get(@PathVariable("id") long id);
@GetMapping("/dept/list")
public List<Dept> queryAll();
@PostMapping("/dept/add")
public boolean addDept(Dept dept);
}
- feign客户端配置文件开启降级
server:
port: 8010
# eureka 配置
eureka:
client:
register-with-eureka: false #不向eureka注册自己
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
# 开启降级
feign:
hystrix:
enabled: true
-
测试,可以正常访问;
当关闭服务提供者后,再次访问如图
当再次开启服务提供者后,再次访问如图
总结
服务熔断:服务端–某个服务超时或异常,引起熔断
服务降级:客户端–从整体网站请求负载考虑,当某个服务关闭之后,服务将不再被调用,此时在客户端我们可以准备一个FallbackFactory ,返回一个默认值
Dashboard监控
创建Dashboard模块-监控页面
- 添加依赖
<!--Hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
<!--hystrix-dashboard-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
- 编写配置
server:
port: 9000
- 编写主启动类,添加注解@EnableHystrixDashboard开启功能
@SpringBootApplication
@EnableHystrixDashboard
public class DeptConsumerDashboard {
public static void main(String[] args) {
SpringApplication.run(DeptConsumerDashboard.class, args);
}
}
- 启动主启动类,访问 http://localhost:9000/hystrix
监控服务-在hystrix-8001模块的主启动类中添加一个 servlet,配置URL
@SpringBootApplication
@EnableEurekaClient //在服务启动后自动注册到Eureka
//添加对熔断的支持
@EnableCircuitBreaker
public class DeptProviderHystrix_8001 {
public static void main(String[] args) {
SpringApplication.run(DeptProviderHystrix_8001.class, args);
}
//增加一个servlet dashboard 监控
@Bean
public ServletRegistrationBean hystrixMetricsStreamServlet(){
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
servletRegistrationBean.addUrlMappings("/actuator/hystrix.stream");
return servletRegistrationBean;
}
}
访问 http://localhost:9000/hystrix,监控信息填写如下
点击Monitor Stream
监控说明
Zuul
Zuul包含了对请求的路由和过滤两个最主要功能
路由功能负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础,而过滤器功能则负责对请求的处理过程进行干预,是实现请求校验,服务聚合等功能的基础。Zuul和Eureka进行整合,将Zuul自身注册为Eureka服务治理下的应用,同时从Eureka中获得其他服务的消息,也即以后的访问微服务都是通过Zuul跳转后获得
- 导入依赖,复制hystrix dashboard的依赖,加入zuul的依赖
<!--zuul-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
- 编写配置
server:
port: 9527
spring:
application:
name: springcloud-zuul
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/,http://localhost:7003/eureka/
instance:
instance-id: zuul9527.com #修改Eureka默认描述信息Status
prefer-ip-address: true #隐藏真实IP
info: #autuator
app.name: rainhey-springcloud
company.name: www.rainhey.com
- 编写主启动类,添加注解 @EnableZuulProxy
@SpringBootApplication
@EnableZuulProxy
public class ZuulApplication_9527 {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication_9527.class, args);
}
}
- HOSTS文件中添加 127.0.0.1和 www.rainhey.com 的映射
- 测试
直接访问
通过Zuul访问微服务
隐藏服务名,修改配置只能通过http://www.rainhey.com:9527/mydept/dept/get/1
访问,不能再通过http://www.rainhey.com:9527/springcloud-provider-dept/dept/get/1
访问
zuul:
routes:
mydept.serviceId: springcloud-provider-dept #隐藏服务名
mydept.path: /mydept/**
ignored-services: springcloud-provider-dept # 使通过原来的服务名访问无效 ; 可以使用通配符 "*" 来隐藏所有的服务名
通过服务名无法访问
通过 /mydept/** 访问
添加统一的访问前缀 /rainhey
zuul:
routes:
mydept.serviceId: springcloud-provider-dept #隐藏服务名
mydept.path: /mydept/**
ignored-services: springcloud-provider-dept # 使通过原来的服务名访问无效 ; 可以使用通配符 "*" 来隐藏所有的服务名
prefix: /rainhey # 设置统一的访问前缀
Config
config简介
spring cloud config 为微服务架构中的微服务提供集中化的外部支持,配置服务器为各个不同微服务应用的所有环节提供了一个中心化的外部配置
spring cloud config 分为服务端和客户端两部分。
服务端也称为分布式配置中心,它是一个独立的微服务应用,用来连接配置服务器并为客户端提供获取配置信息,加密,解密信息等访问接口
客户端则是通过指定的配置中心来管理应用资源,以及与业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息,即微服务应用;配置服务器默认采用git来存储配置信息
git环境搭建
- 码云创建springcloud-config仓库,复制链接
- 在桌面创建Git文件夹,在文件夹里面打开git bash,执行
git clone ****
- 在克隆文件springcloud-config中编写创建编写yml文件
spring:
profiles:
active: dev
---
spring:
profiles: dev
application:
name: springcloud-config-dev
---
spring:
profiles: test
application:
name: springcloud-config-test
- 依次执行
git add . # 将被修改的文件加入到暂存区
git commit -m "first commit" #本地提交
git push origin master #push到远程仓库,origin用户,master分支
- 创建config-client.yml
spring:
profiles:
active: dev
---
spring:
profiles: dev
application:
name: springcloud-provider-dept
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka/
server:
port: 8202
---
spring:
profiles: test
application:
name: springcloud-provider-dept
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka/
server:
port: 8201
- 上传到码云
config-server
通过config-server可以连接到git,读取其中的资源和配置
- 导入依赖
<dependencies>
<!--springcloud-config-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--actuator-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
- 编写配置
server:
port: 3344
spring:
application:
name: springcloud-config-server
# 连接远程仓库
cloud:
config:
server:
git:
uri: https://gitee.com/Rainhey/springcloud-config.git
- 编写主启动类,添加注解 @EnableConfigServer
@SpringBootApplication
@EnableConfigServer
public class config_server3344 {
public static void main(String[] args) {
SpringApplication.run(config_server3344.class, args);
}
}
- 测试,读取配置
config-client
- 导入依赖
<dependencies>
<!--springcloud config -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
<!--actuator-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
- 创建系统级别配置bootstrap.yml,优先级高于application.yml
spring:
cloud:
config:
uri: http://localhost:3344
name: config-client #需要从git上读取的资源名称,不需要后缀
profile: dev #环境
label: master # 分支
创建用户级别配置application.yml
spring:
application:
name: springcloud-config-client-3355
- 编写主启动类和controller
@RestController
public class ConfigClientController {
@Value("${spring.application.name}") //从远程取值
private String applicationName;
@Value("${eureka.client.service-url.defaultZone}")
private String eurekaServer;
@Value("${server.port}")
private String port;
@RequestMapping("/config")
public String getConfig(){
return "application="+applicationName
+" eurekaServer="+eurekaServer
+" port="+port;
}
}
- 开启config-server和config-client测试,结果如图拿到远程配置的端口8202,以及拿到其他远程配置