springcloud入门+组件使用

代码gitee地址:https://gitee.com/bing520/springcloud

集群 cluster:
同一中软件服务的多个服务节点共同为系统提供服务过程,称之为软件服务集群。

分布式 distribute:
不同软件集群共同为一个系统提供服务,这个系统称之为分布式系统。

比如:一组tomcat叫tomcat集群,一组MySQL叫MySQL集群,一组redis叫redis集群。
这些集群要共同为一个系统提供服务,这个系统就叫分布式系统。分布式系统一定是集群,但是集群不一定是分布式系统。

微服务:
微服务是一种架构,这种架构是将单个的整体应用程序分割成更小的项目关联的独立服务。一个服务通常实现一组独立的特性或功能,包含自己的业务逻辑和适配器。各个微服务之前的关联是通过暴漏的rest api来实现。这些独立的微服务不需要部署在同一个虚拟机,同一个系统和同一个应用服务器中。

单体应用架构:
优点:项目初期很小的时候开发方便,测试方便,部署方便,运行良好
缺点:随着时间推进,加入的功能越来越多,最终会变的巨大,开发效率低,代码维护困,任意的模块漏洞或者错误都会导致整个项目无法运行,降低系统的可靠性。

微服务架构:
优点:将服务拆分成多个单一职责的小服务,进行单独部署,服务之前通过网络进行通讯。避免因为一个模块的问题导致服务崩溃
缺点:部署成本增加,拆分的服务都要部署。服务治理和服务监控。

服务治理:考虑负载均衡,服务雪崩->由于在某一时刻因为某一个服务长时间不可用,导致上一个调用的服务也不可用,最终导致都不可用,解决需要考虑在某个节点业务时间过长要立即中断,
配置文件的管理,每个集群有很多配置文件,不需要一个一个去改
服务监控:
spring cloud用来解决以上的问题。快速构建一站式微服务架构。叫一个工具,有各种各样的组件,来解决以上问题。

什么是springcloud?
能帮我们快速的去构建微服务架构,他是一个工具集,工具集提供了各种各样的组件,帮助我们去解决微服务架构中所遇到的问题,如服务的注册发现,路由转发,负载均衡,配置管理。

服务注册中心组件
服务注册中心就是在整个微服务架构单独抽取一个服务,这个服务不完成项目中任何业务功能,仅仅用来在微服务中记录微服务以及对整个微服务系统进行健康状态检查,以及服务元数据信息存储
a、可以对所有的微服务的信息进行存储,如服务的ip,名称,端口
b、可以在进行服务调用时通过服务发现查询可用的微服务列表及网络地址进行服务调用
c、对所有服务进行心跳检测,如发现某实例长时间无法访问,就会从服务注册表移除该实例

eureak(netflix)、zookeeper(java)、consul(Go)、nacos(java阿里巴巴)
eureak:
	简化:Eureka是Netflix开发的服务发现框架 springcloud-netflix-eureka服务注册中心
	Eureka包含两个组件: Eureka Server和Eureka client.

eureak(netflix)
作用:微服务架构充当服务注册中心
不推荐使用,eureka1.0版本稳定、eureka2.0版本已经停止更新。每次必须手动通过代码形式开发服务注册中心

consul 服务注册中心
基于go语言开发,轻量级服务注册中心。谷歌公司。不需要手动开发。

开发eureka server服务注册中心

1、创建spring boot项目,代码:01eureka_server服务
2、引入eureka server依赖

		<!-- 引人eureka server依赖 -->
		<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>        

3、编写配置文件,指定eureka server端口,服务地址

#eureka server端口号
server.port=8761
#指定服务名称,不可以是下划线
spring.application.name=EUREKASERVER
#eureka sercer服务注册中心地址 暴露的服务地址
eureka.client.service-url.defaultZone= http://localhost:8761/eureka

4、在入口类加入注解

//开启当前应用是一个服务注册中心
@EnableEurekaServer

springcloud入门+组件使用_第1张图片
springcloud入门+组件使用_第2张图片
springcloud入门+组件使用_第3张图片
启动服务:访问 http://localhost:8761/

在这里插入图片描述
启动过程中报错,是因为:eureka有两个组件eureka server和eureka client组件,当项目中引入eureka server组件时,这个组件同时将eureka client引入到项目中,因此启动时就会将自己作为一个服务中心启动,同时会将自己作为服务客户端进行注册,默认启动时立即注册,注册时服务还没有启动完成因此会出现这个错误。

如何关闭eureka server自己注册自己

#关闭eureka client立即注册,等启动之后在进行注册
eureka.client.fetch-registry=false

#让当前的应用仅仅是服务注册中心,不进行自己注册自己
eureka.client.register-with-eureka=false

开发eureka client服务注册中心

1、创建spring boot项目,代码:02eureka_client
2、引入eureka client依赖

		<!--引入eurekaclient依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>        

3、编写配置文件,指定eureka client端口,服务地址

#指定服务端口
server.port=8888
#指定服务名称,不可以是下划线
spring.application.name=eurekaclient01

#指定服务注册中心地址
eureka.client.service-url.defaultZone=http://localhost:8761/eureka

4、在入口类加入注解

//让当前服务作为一个eureka server客户端 进行服务注册
@EnableEurekaClient

eureka server的自我保护机制
默认情况下,如果eureka server在一默认时间内(90秒)没有接收到某个微服务的实例的心跳,eureka server将会移除该实例。有一定的时间是因为怕因为网络故障,有一定的缓冲,不会立即移除这个实例

eureka 不推荐使用,官方已经停更了。

eureka server集群搭建
复制几份eureka server。
springcloud入门+组件使用_第4张图片
可以修改端口。
VM options: -Dserver.port=8762 可以覆盖端口号
springcloud入门+组件使用_第5张图片
需要8761端口的eureka server注册到8762和8763
需要8762端口的eureka server注册到8761和8763
需要8763端口的eureka server注册到8761和8762
然后都启动即可。
客户端client需要连接的地址:

#指定服务注册中心地址
eureka.client.service-url.defaultZone=http://localhost:8761/eureka,http://localhost:8762/eureka,http://localhost:8763/eureka

consul 服务注册中心

基于go语言开发,轻量级服务注册中心。谷歌公司。不需要手动开发。
consul服务注册中心安装

a、官网下载:https://www.consul.io/downloads
b、在指定目录解压,不要中文目录,
   E:\wbing\consul
c、启动服务注册中心,在安装目录打开cmd
   consul agent -dev
d、访问consul管理界面
   地址:http://localhost:8500/
e:界面内容:
  dc1:数据中心名称。指定数据中心启动 consul agent -dev -datacenter=aa
  services:当前服务中心注册服务列表,默认consul server同时启动时会自己注册自己,会有一个consul服务
  nodes:用来查看consul的集群节点

consul client 服务客户端(微服务,一个一个服务)

1、创建一个spring boot,引入依赖,代码:03consul_client服务

		<!--引入consul依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>

2、编写配置文件application.properties

#指定服务端口
server.port=9999
spring.application.name=CONSULCLIENT

#向consul server进行注册
spring.cloud.consul.host=localhost
spring.cloud.consul.port=8500
#执行注册的当前服务的服务名称,默认引用 ${spring.application.name}
spring.cloud.consul.discovery.service-name=${spring.application.name}

3、在入口类上加入注解

@SpringBootApplication
//是一个通用的服务注册客户端注解,有:consul client、zk client、nacos client
@EnableDiscoveryClient
public class ConsulClientApplication {...}

4、直接启动会发现consul client有如下问题
springcloud入门+组件使用_第6张图片

原因:consul client检车所有客户端心跳,但是发送心跳时client必须回应才能说明该服务可以正常使用。在现有客户端中没有引入健康依赖检查,导致健康检查始终不通。
所以需要引入健康心跳检查的依赖

 		<!--健康依赖检查,这个包是用来做consul的健康监控的-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

如何解决微服务的服务间通讯的问题

RestTemplate restTemplate = new RestTemplate();
        String forObject = restTemplate.getForObject("http://localhost:8082/order/getOrder", String.class);

存在问题:
a、访问的主机和端口是写死的,当调用的服务是一个集群时候,无法实现请求服务的负载均衡。始终调用这个一个端口。
b、请求路径写死,不利于后期维护。需要改很多地方

解决负载均衡:
a、自定义负载均衡,

	//自定义随机策略
    public static String randomHost() {
        //将服务集群的地址放入list里边,
        List<String> hosts = new ArrayList<String>();
        hosts.add("http://localhost:8082");
        hosts.add("http://localhost:8072");
        //随机获取一个地址
        int i = new Random().nextInt(hosts.size());
        return hosts.get(i);
    }

如果服务宕机则无办法,无法进行健康检查。太单一。

b、使用spring cloud组件 ribbon解决负载均衡调用。推荐
Ribbon:springcloud-netflix-ribbon
作用:负载均衡客户端组件,用来实现请求调用时负载均衡。
原理:是一个客户端的组件,根据调用服务id去服务注册中心获取对应服务id的服务列表,并将服务列表缓存到本地,然后在本地通过默认的轮询负载均衡策略在现有列表中选择一个可用的节点提供服务

使用Ribbon+RestTemplate实现请求负裁均衡

代码:04users服务、05orders服务

a、在服务调用方引入依赖
注意:consul client的依赖中已经存在ribbon相关依赖,所以无需在引入。
b、直接使用ribbon组件根据服务id实现负载均衡
DiscoveryClient
作用:服务发现客户端对象,根据服务id去服务注册中心获取对应服务列表到本地。返回一个请求地址list。通过@Autowired进行注入。
缺点没有负载均衡 需要自己实现负载均衡

//服务注册与发现的客户端对象
@Autowired
private DiscoveryClient discoveryClient;
//使用ribbon组件+restTemplate实现复制均衡调用   1、DiscoveryClient  2.LoadBalanceClient  3、@LoadBalance
List<ServiceInstance> instances = discoveryClient.getInstances("ORDERS");
for (ServiceInstance instance : instances) {
   System.out.println(instance.getUri());
   System.out.println(instance.getHost());
   System.out.println(instance.getPort());
}
//调用order服务
RestTemplate restTemplate = new RestTemplate();
String forObject = restTemplate.getForObject(instances.get(0).getUri() + "/order/getOrder", String.class);

LoadBalancerClient
作用:负载均衡客户端对象,根据服务id去服务注册中心获取对应列表,根据默认的负载均衡策略返回列表中的一个请求地址进行返回。通过@Autowired进行注入。
缺点使用时需要每次先根据服务id获取一个负裁均衡机器之后再通过restTemplate调用服务

//负载均衡客户端对象
@Autowired
private LoadBalancerClient loadBalancerClient;
//使用LoadBalanceClient进行服务调用,默认轮询策略
ServiceInstance orders = loadBalancerClient.choose("ORDERS");

//调用order服务
RestTemplate restTemplate = new RestTemplate();
String forObject = restTemplate.getForObject(orders.getUri() + "/order/getOrder", String.class);

@LoadBalance:推荐使用!!!
作用:负载均衡客户端注解,用在方法上,让当前对象具有ribbon负债均衡特性

//代表这是一个springboot 配置类 工厂创建对象 bean id class=n"
@Configuration
public class BeanConfig {
    //工厂中创建RestTemplate
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}
//3、使用@LoadBalance注解,可以让对象具有ribbon负载均衡特性
//http://+ 服务注册名称 + 请求地址
String forObject = restTemplate.getForObject("http://ORDERS/order/getOrder", String.class);

ribbon有哪些负载均衡策略
springcloud入门+组件使用_第7张图片
RoundRobbinRule:轮询策略,按照顺序循环选择。默认
RandomRule:随机策略,随机选择
AvailabilityFilteringRule:可用过滤策略,会先过滤由于多次访问故障而处于断路器跳闸状态的服务,还有开发的连接数量超过阈值的服务,然后对剩余的服务进行轮询策略进行访问
WeightedResponseTimeRule:相应时间加权策略,相应时间最快,服务权重越大,被选中的概率越高。
RetryRule:重试策略,如果获取失败则在定制的时间内进行重试,获取可用的服务
BestAviabTeRule:最低并发策略,会选择一个并发量最小的服务

修改ribbon负载均衡策略,不再使用随机策略

服务id.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
com.netflix.loadbalancer.RandomRule 要写全限定名

openFeign

为什么使用openFeign?
可以使的Java HTTP客户端变得更容易。Feign集成了Ribbon、rest template实现了负载均衡的执行http请求,对原有的方式进行了封装,不必手动调用,只需要定义一个接口,在这个接口中标注一个注解即可完成服务调用。还支持springmvc的注解。调用服务代码更加简单,自动完成数据传递过程中对象转换

使用open Feign
a、创建两个spring boot项目,06category服务和07product服务
并注册到服务中心 consul 。引入服务注册中心依赖

		<!--引入consul依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>

        <!--健康依赖检查,这个包是用来做consul的健康监控的-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

b、修改配置文件,入口类加注解

server.port=6661
spring.application.name=CATEGORY

#配置服务注册地址
spring.cloud.consul.host=localhost
spring.cloud.consul.port=8500
@SpringBootApplication
@EnableDiscoveryClient //开启服务注册

c、使用open Feign进行调用,引入feign依赖。哪里需要调用写道哪里

		<!--引入openfeign依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

d、入口类加注解,启动geign调用

@EnableFeignClients //开启openfeign客户端调用

e、加注解,写接口。单独建立一个包,写接口

/**
 * 调用商品服务的接口
 */
@FeignClient("PRODUCT") //调用服务的服务id
public interface ProductClient {

    //调用商品服务接口
    @GetMapping("product")
    public String product();

}

f、进行调用

@RestController
public class CategoryController {

    @Autowired
    private ProductClient productClient;

    @GetMapping("category")
    public String category() {
        String product = productClient.product();
        return "category调用ok!!!! 返回:" + product;
    }
}

然后请求接口:http://localhost:6661/category。就会实现调用product服务接口。也有负载均衡。

服务间通讯之参数传递和相应处理

a、传递零散类型参数 url?name=张三&age=22
在openFeign接口声明中必须在接口参数中加入注解 @RequestParam

//调用商品服务,带参数,调用方。必须要写注解
@FeignClient("PRODUCT") //调用服务的服务id
public interface ProductClient {
    //调用商品服务,带参数
    @GetMapping("param")
    public String param(@RequestParam("name") String name, @RequestParam("age") Integer age);
}

b、路径传递参数 url/zhangsan/22
在openFeign接口声明中必须在接口参数中加入注解 @RequestParam

@FeignClient("PRODUCT") //调用服务的服务id
public interface ProductClient {
  @GetMapping("param1/{name}/{age}")
  public String param1(@PathVariable("name") String name, @PathVariable("age") int age);
}

c、对象类型参数
application/json方式参数

//对象类型参数
@PostMapping("param2")
String param2(@RequestBody Product product);

d、数组参数传递

//传递一个数组类型 url/param3?ids=21&ids=22
@GetMapping("param3")
String param3(@RequestParam("ids") String[] ids);

e、集合类型的参数接收
服务提供者

@GetMapping("param4")
public String param4(CollectionVo collectionVo) {
	return " product 欧克,提供当前服务端口:" + collectionVo.toString();
}
public class CollectionVo {
   private List<String> ids;
}

在openFeign中调用

//集合类型参数
    @GetMapping("param4")
    String param4(@RequestParam("ids") List<String> ids);

openFeign实现服务间通讯的响应

服务提供者

   @GetMapping("param7")
    public Map<String, Object> param7(String id) {
        Product product = new Product("张三", 18, new Date());
        Product product1 = new Product("李四", 19, new Date());
        List<Product> products = new ArrayList<Product>();
        products.add(product);
        products.add(product1);

        Map<String, Object> map = new HashMap<String, Object>();
        map.put("total", 110);
        map.put("list", products);
        return map;
    }
    
    @GetMapping("param6")
    public List<Product> param6(String id) {
        Product product = new Product("张三", 18, new Date());
        Product product1 = new Product("李四", 19, new Date());
        List<Product> products = new ArrayList<Product>();
        products.add(product);
        products.add(product1);
        return products;
    }

    @GetMapping("param5")
    public Product param5(String id) {
        Product product = new Product("张三", 18, new Date());
        return product;
    }

open Feign中调用

	//返回多个map类型
    @GetMapping("param7")
    String param7(@RequestParam("id") String id);
 
    //相应对象集合类型
    @GetMapping("param6")
    List<Product> param6(@RequestParam("id")String id);

    //相应对象类型
    @GetMapping("param5")
    Product param5(@RequestParam("id") String id);

调用者代码,使用fastjson转换

    @GetMapping("param7")
    public List<Product> param7() {
        String param7 = productClient.param7("1");
        JSONObject jsonObject = JSONObject.parseObject(param7);
        String total = jsonObject.get("total").toString();
        System.out.println(total);

        String list = jsonObject.get("list").toString();
        List<Product> products = JSONObject.parseArray(list, Product.class);
        return products;
    }

openFeign默认超时处理

默认的超时:在使用open feign组件在进行服务器间通讯,要求被调用的服务必须在1s内给予回应,一旦服务执行时间超过1s,就会报错。
Read timed out executing GET http://PRODUCT/product

修改openFeign调用某个服务的超时时间

#修改调用服务时 openFeign默认时间是1s。PRODUCT是服务注册名称
#指定服务修改某个服务调用超时时间

#配置指定服务连接超时
feign.client.config.PRODUCT.connect-timeout=5000
#配置指定服务等待超时
feign.client.config.PRODUCT.read-timeout=5000

修改openFeign调用所有服务的超时时间

#修改调用所有服务的open Feign 超时时间。毫秒。服务名称改为default

feign.client.config.default.read-timeout=5000
feign.client.config.default.connect-timeout=5000

open Feign日志展示
open Feign 伪 http client对象,用来帮助我们完成服务间通讯,底层用http协议完成服务间调用
日志:为了方便开发和调试,默认日志功能是关闭的。
使用:feign日志的打印只会DEBUG级别做出响应。

#展示open Feign日志。com.wbing.category.feignclient 包名
logging.level.com.wbing.category.feignclient=debug

#开启open Feign调用商品服务日志展示级别。PRODUCT服务名称
feign.client.config.PRODUCT.logger-level=FULL

NONE:不记录任何日志
BASIC:仅仅记录请求方法,url,相应状态码和执行时间
HEADERS:记录basic级别基础之上,记录请求和相应的headers
FULL:记录请求和相应的header,body和元数据。展示全部协议状态

服务中的重要概念,服务雪崩、服务熔断、服务降级

服务雪崩:在某一个时刻,微服务系统中所有的服务均不可用的这种现象,称之为服务雪崩。

引发:在微服务之间进行服务调用由于一个服务故障,导致级联服务故障的现象,称之为雪崩效应,是由于服务提供方不可用,导致消费方不可用,并将不可用逐渐放大的过程。

原因:在调用链路中某一个服务因为执行业务时间过长,或者大规模出现异常导致自身服务不可用,并把这种现象逐渐放大。

如何解决微服务系统服务雪崩问题?

服务熔断:Hystrix,
作用:监控器,监控服务链路。就是用来在微服务系统中防止服务雪崩现象出现的。

熔断机制:所有微服务必须引入Hystrix组件。一旦引入就具有服务熔断功能。类似于家里的保险丝,或者电闸。超过一定的功率会跳闸。

流程
1、当满足一定的阈值的时候( 默认10秒内超过20个请求次数)
2、当失败率达到一定的时候(默认10秒内超过50%的请求失败)
3、到达以上任一阈值,断路器就会开启
4、当开启的时候,所有的请求都不会转发
5、一段时间以后(默认是5秒),这个时候断路器改为半开状态,会让其中一个请求进行转,如果成功,断路器关闭。如果失败,再次打开断路器。重复4和5

注意:一旦断路器打开之后所有到这个服务请求均不可用,只有在熔断关闭之后才行。

阐述流程:当Hystrix监控到对该服务接口调用出发两个阈值时候,会在系统中自动触发熔断器,在熔断器打开期间内,任何到该接口的请求都不可用,同时在断路器打开5s后,断路器会处于一个半开的状态,此时断路器会允许放行一个请求到该服务接口,如果该请求执行成功,断路器关闭;如果请求执行失败断路器重新打开。

什么是服务降级?
定义:在服务压力剧增的时候根据当前的业务情况及流量对一些服务和页面有策略的降级,以此缓解服务器的压力,以保证核心业务的进行。同时保证大部分客户都能得到正确的响应。也就是当前的请求处理不了或者出错了,给一个默认的返回。返回服务繁忙请稍后再试,或者返回一个服务可用时间。

通俗定义:当网站或者服务流量突然增加时,为了保证系统核心服务正常运行,有策略关闭系统中边缘服务,以保证核心服务的正常运行。比如双十一,关闭确认收货,评价,物流通知等一些功能,来保证能够正常下单,付款等服务。

总结 熔断和降级
共同点:
1、都是为了防止系统缓慢、系统崩溃才有的技术手段。
2、最终表现形式,都是让用户体验到的是某一些功能的短暂不可用。
3、熔断是系统基于服务策略的自动触发,降级是需要手动干预。
不同点:
1、熔断一般是某个服务下游故障引起的,降级是从服务整体负荷考虑
2、熔断是一个框架的处理,每个微服务都需要引入监控,而降级是需要对业务有层级之分(一般从最外围服务边缘开始)

总结:熔断必会出发降级,所以熔断也是降级的一种,区别在于熔断是对链路的保护,降级是对系统过载的一种保护处理

Hystrix组件

作用:防雪崩利器,已停止更新,进入维护阶段。Sentinel是它的替换品

如何使用Hystrix组件?

服务提供方,被调用方服务:当服务正常运行的时候。
1、在所有的微服务中引入依赖

<!--引入Hystrix熔断-->
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

2、开启Hystrix服务熔断。在入口类加入注解

@EnableCircuitBreaker //开启Hystrix服务熔断
public class HystrixApplication {
}

3、在控制器中加入备选处理

 	@GetMapping("demo")
 	//熔断之后的处理,fallbackMethod 书写快速失败的方法名
    @HystrixCommand(fallbackMethod = "demoFallback")//熔断之后默认执行哪个方法
    public String demo(int id) {

        System.out.println("demo方法");
        if (id <= 0) {
            throw new RuntimeException("无效的id");
            //只要抛出异常就会进入fallbackMethod的备选方法
        }
        return "demo调用成功!!!";
    }

    //熔断之后要执行的方法
    public String demoFallback(int id) {
        return "当前活动过于火爆,服务已经被熔断了,请稍后再试试";
    }

抛出异常用来模拟服务异常现象,一直请求失败就会打开熔断。 id<0一直请求就会失败打开熔断,打开熔断之后再输入正确的id>0,也会进入熔断方法。
发现:只要调用失败就会进入fallbackMethod方法,无论熔断是否打开。

open Feign调用服务时集成Hystrix:消费方,调用方服务。可能会有调用的服务不可用宕机的情况
1、引入Hystrix依赖

<!--引入Hystrix熔断-->
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

2、开启openFeign对 hystrix 的支持,配置文件加入

#开启openFeign在调用服务过程中 开启Hystrix熔断支持。默认是关闭
feign.hystrix.enabled=true

3、开发openFeign调用失败的默认处理
在openFeign客户端接口中的Feignclients(value=“服务id”,fallBack-默认处理lass)

//fallback:当服务调用不可用时候, 默认的备选处理
@FeignClient(value = "HTSTRIX", fallback = HystrixClientFallback.class)
public interface HystrixClient {

    @GetMapping("demo")
    public String demo(@RequestParam("id") int id);
}
/**
 * 自定义的HystrixClient失败的默认备选方法
 */
@Configuration
public class HystrixClientFallback implements HystrixClient {

    @Override
    public String demo(int id) {
        return "当前服务不可用,请稍后再试!";
    }
}

4、当服务宕机不可用时,直接会执行自定义的fallback的方法

Hystrix DashBoard 仪表盘
作用:监控每一个@HystrixCommond注解创建一组度量,构建一组信息,然后通过图形化方式展示当前方法@HystrixCommond的状态信息。可以看到方法是否打开了断路器。

最后:Hystrix不再处于积极开发中,目前处于维护模式。但是.Hystrix(版本1.5.18)足够稳定,可以满足Netflix对我们现有应用程序的需求

可以代替她的组件。sentinel 流量卫兵。流量控制,降级策略。推荐使用

Gateway 网关组件

作用:路由转发+请求过滤
1、网关统一所有的微服务入口;
2、网关可以实现请求路由转发,以及请求过程的负载均衡;根据前端请求的不同路径,转发到不同服务
3、访问服务的身份认证、防报文重放与防数据算改、功能调用的业务鉴权响应数据的脱敏、流与并发控 制,甚至基于APT调用的计量或者计费等等

Gateway网关使用

1、建立一个独立的spring boot项目
2、引入Gateway依赖

<!--gateway依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

3、编写配置
a、配置文件形式 推荐使用

server:
  port: 8880
spring:
  application:
    name: GATEWAY
  cloud:
    consul:
      port: 8500
      host: localhost
    gateway:
      routes:
        - id: category_router #路由对象唯一表示
          uri: http://localhost:6661 #用来调用类别服务地址
          predicates: #断言 用来配置路由规则
            - Path=/category/**,/list #路由里边携带/category,都会转发到上边的url。只会替换IP和端口。path逗号分割可以写多个

        - id: product_router #路由对象唯一表示
          uri: http://localhost:7777 #用来调用商品服务地址
          predicates: #断言 用来配置路由规则
            - Path=/product/**,/list #路由里边携带/product,都会转发到上边的url。只会替换IP和端口。path逗号分割可以写多个
         

http://localhost:8880/category的时候,会先去path里边比较,然后将请求地址转发到uri的路径在拼接上请求的方法,实际请求就是 http://localhost:6661/category

b、java代码形式

@Configuration
public class GatewayConfig {
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("category_router", r -> r.path("/category/**").uri("http://localhost:6661"))
                .route("product_router", r -> r.path("/product/**").uri("http://localhost:7777"))
                .build();
    }
}

网关在路由转发时如何实现请求负载均衡?
Ribbon组件 负均衡客户端组件。

# 将Gateway配置的uri修改为如下
uri: lb://PRODUCT   #lb: load balance 负载均衡 /服务id

网关细节
网关 gateway = 断言 predicate + 过滤 (后置 filter)

断言:当请求到达网关时,网关前置处理。满足断言放行请求,不满足断言立即返回
过滤:当请求满足断言的所有条件时,在向后端服务转发之前会经过一些过滤

网关断言使用:
满足放行,不满足报404

- Path=/category/  路径断言
- After=2017-01-20T17:42:47.789-07:00[America/Denver]   代表该路由规则必须在指定时间之后才能使用,
- Before=2017-01-20T17:42:47.789-07:00[America/Denver]  代表该路由规则必须在指定时间之前才能使用,
- Between=2017-01-20T17:42:47.789-07:00[America/Denver],2017-01-21T17:42:47.789-07:00[America/Denver]  在某个时间段内生效。比如双十二的活动时间
- Cookie=username,wbing #携带指定的cookie才能访问
- Cookie=username,[A-Za-z0-9]+ #携带指定cookie,满足正则表达式
- Header=X-Request-Id,\d+  #X-Request-Id指定请求头name。\d代表数字
- Method=GET,POST  #基于请求方式的断言

过滤 (后置 filter):

- AddRequestHeader=X-username, wbing #添加指定的请求头,用来给路由对象的所有请求
- AddRequestParameter=red, blue  #添加指定的参数,用来给路由对象的所有请求
- AddResponseHeader=X-Response-Red, Blue #给响应对象加入指定的头信息,用来给路由对象的所有请求
- 
#用来给路由对象的所有转发请求的url加入指定的前缀信息。
#如访问网关地址为 /list 前缀路径为/mypath 转发到后端服务地址为 uri+前缀路径+地址栏路径 就是 uri+/mypath/list
- PrefixPath=/mypath

#给所有转发请求的url去掉指定的n个前缀,
#浏览器访问网关地址:/product/list   - stripPefix=1  请求就为 /list
- StripPrefix=2

自定义全局的filter,所有请求都要经过全局filter之后,再走配置yml,再转发到后端服务。

@Configuration
public class CustomerGlobalFilter implements GlobalFilter, Ordered {
    /**
     * 类似javaweb doFilter
     * exchange:交换 封装了request、response
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //HttpRequest
        ServerHttpRequest request = exchange.getRequest();
        //HttpResponse
        ServerHttpResponse response = exchange.getResponse();
        System.out.println("经过全局的filter处理。。。。。优先于配置执行");
        Mono<Void> filter = chain.filter(exchange);//放行filter继续向后执行
        System.out.println("响应回来filter处理、、、、、、、");
        return filter;
    }

    /**
     * order 排序。用来指定filter指定的顺序,按照自然数字进行排序。
     * -1 表示在所有filter执行之前执行
     */
    @Override
    public int getOrder() {
        return 1;
    }
}

通过网关提供的web路径查看路由详细规则

路径:http://localhost:8880/actuator/gateway/routes

查看网关路由规则详细路径必须在网关配置文件中暴露当前路径

#加入这个配置可以查看所有的路由规则。 访问 http://localhost:8880/actuator/gateway/routes 
management:
  endpoints:
    web:
      exposure:
        include: "*"

config组件

config:组件。统一配置中心。
作用:用来实现微服务系统中服务配置统一管理组件
组件:统一配置中心服务端(集中管理配置文件)、统一配置中心客户端(client,就是每个分割出去的服务)
原题:用来统一配置中心,会先去远程仓库拉取一份放到本地仓库,然后把本地仓库的配置交给各个服务。

config server组件的使用

1、选择一个远端的gitee仓库使用

仓库地址:
https://gitee.com/bing520/cloud-configs.git

2、创建config server 统一配置中心服务,引入依赖

<!--config server-->
 <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-config-server</artifactId>
 </dependency>

3、配置application配置文件,如果是私有库需要配置用户名和密码

#配置远程仓库的地址
spring.cloud.config.server.git.uri=https://gitee.com/bing520/cloud-configs.git
spring.cloud.config.server.git.default-label=master

4、开启统一配置中心,入口类加入注解

@SpringBootApplication
@EnableDiscoveryClient
@EnableConfigServer //代表我是一个统一配置中心服务
public class ConfigServerApplication {
.......
}

config client 使用,

1、创建一个单独的应用,引入依赖

<!--config client相关依赖-->
 <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-config</artifactId>
 </dependency>

2、将自身的配置交给远端的gie仓库管理,命名使用服务名+环境.properties
springcloud入门+组件使用_第8张图片
里边写配置
springcloud入门+组件使用_第9张图片
3、编写配置文件告诉config server地址,并且也要注册到服务中心

#告诉当前configclient统一配置中心在 配置中心的服务id
spring.cloud.config.discovery.service-id=CONFIGSERVER

#开启当前configclient 根据服务id去注册中心获取,config服务,并做负载均衡
spring.cloud.config.discovery.enabled=true

#配置注册中心
spring.cloud.consul.port=8500
spring.cloud.consul.host=localhost


#获取哪个配置文件  1、分支  2、文件明  3、环境
spring.cloud.config.label=master
spring.cloud.config.name=configclient
spring.cloud.config.profile=dev

这个配置文件名称必须修改为bootstrap.properties
springcloud入门+组件使用_第10张图片

config client 微服务的手动配置刷新

当远端的git仓库地址的配置文件发生变化时,不需要重启微服务就可以直接读取远端修改过后的配置信息

1、加入注解 @RefreshScope

@RestController
@RefreshScope //用来在不需要重启微服务情况下,将当前scope域中信息刷新为最新配置信息
public class controller {

    @Value("${name}")
    private String name;

    @RequestMapping("demo")
    public String demo() {
        return "demo ok! name = " + name;
    }

}

2、必须在微服务配置文件中暴漏远端配置刷新端点 endpoints


#开启所有web 端点暴漏
management.endpoints.web.exposure.include=* 

3、修改完远端的git仓库配置文件之后,向微服务发生一个post方式的请求就行。/actuator/refresh
在这里插入图片描述
缺点:每一个微服务节点如果要加载最新配置信息,必须向每一个服务手动发送请求,麻烦

Bus: 实现配置刷新原理
spring cloud bus利用轻量级消息中间件将分布式系统中所有服务连接到一起。
作用:利用bus广播特性当某一个状态(配置文件)发送改变时通知到bus中所有服务节点更新当前状态(更新自身配置)
原理:
只需要向config server发送一个post方式请求,actuator/bus-refresh。server接受到请求之后,会把这个消息发送到rabbitmq。mq接收到消息之后,他会通知到他下边每一个消费者。 消费者接受到这个bus的消息之后,就会自动从configserver拉去一遍配置进行改变。
springcloud入门+组件使用_第11张图片
会用到RabbitMQ,RabbitMQ安装在docker里边
//只需执行以下命令,docker容器便会自动从Docker Hub中拉取RabbitMQ的镜像,并创建容器(注意:docker会自动帮我们部署Erlang环境)。


docker run -d --name rabbit -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=admin -p 15672:15672 -p 5672:5672 -p 25672:25672 -p 61613:61613 -p 1883:1883 rabbitmq:management

利用spring cloud bus实现远端配置修改 自动刷新

1、启动mq服务,docker start rabbit
2、配置统一配置中心通过bus 连接到mq服务,在confug server服务中引入bus依赖

 <!--引入bus依赖-->
 <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-bus-amqp</artifactId>
 </dependency>

3、配置configserver配置文件

#通过bus组件连接到mq服务
spring.rabbitmq.host=192.168.1.29
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=admin
spring.rabbitmq.virtual-host=/

4、把其他的服务配置加入mq配置。放入远端的git仓库里。复制3、到远端仓库
引入bus依赖启动立即根据配置文件bus配置连接mg服务器,但是此时mg配置信息都在远端,因此bus连接不到mg直接报错,为了避免在启动的时候报错,加入以下配置,允许项目启动时bus组件立即连接mq这个失败,因为获取远端配置之后可以再以远端配置初始化bus组件

#代表在启动时 还没有拉去远端配置完成的 失败报错都是允许的
spring.cloud.config.fail-fast=true

5、开启所有web 端点暴漏,cmd向config server 统一配置发送POST方式请求实现自动配置刷新。actuator/bus-refresh。

#开启所有web 端点暴漏
management.endpoints.web.exposure.include=*

在这里插入图片描述
发现配置已经更新。
刷新所有服务 POST http://localhost:8848(confiqserver地址) /actuator/bus-refresh
指定服务刷新 POST http://localhost:8848(confiqserver地址) /actuator/bus-refresh / 服务id

利用gitee webhooks 实现自动刷新远端配置文件修改

webhooks:根据远端仓库触发事件发送一个web post请求。不需要再手动发送请求
1、远端仓库配置webhooks
springcloud入门+组件使用_第12张图片

2、需要填写一个本地的 内网穿透 地址。借助工具 natapp 免费使用一个隧道。localhost:8848 内网地址

   1、访问natapp官方 https://natapp.cn/
   2、注册,实名认证,购买免费隧道
   3、配卫隧道 ====>本地端口为config server 端口 8848
   4、下载客户端 natapp.exe 。地址:https://natapp.cn/#download
   5、在cmd打开 启动 natapp --authtoken= 我的隧道生成的authtoken

springcloud入门+组件使用_第13张图片
cmd执行:natapp --authtoken= XXXXXXXXX。如下就成功了
springcloud入门+组件使用_第14张图片
注意:webhooks首次配置完成之后config server 发送post方式出现400错误。需要加一个过滤器。启动类加一个注解。可以去gitee上拉取代码。UrlFilter。启动类加入注解 @ServletComponentScan(basePackages = “com/wbing/configserver/filter”)
webhooks就可以启动成功。
springcloud入门+组件使用_第15张图片
最后每次修改完配置文件,webhooks都会自动向configserver发送请求。更新配置。

代码gitee地址:https://gitee.com/bing520/springcloud

你可能感兴趣的:(springcloud,java,微服务)