springcloud总结:

1.服务架构的演变
  1>当我们的网站的并发量在100左右的时候,选择单体架构,直接采用表现层,服务层,数据层,(三层架构)就可以搞定!
  2>商城的1000并发量 ,根据Tomcat来计算,需要使用2到3台tomcat,平均一台Tomcat可以负载300并发量
   但是这些相同Tomcat来处理相同的项目,前面在使用一个负载均衡服务器来实现转发,但是这些tomcat
   之间可以使用tomcat集群的的session复制的方式,进行通信!
  3> 商城的10000并发量,上面的架构支撑不了,如果在使用第二种架构,性能可能会下降,因为session
    在通信的时候,内网带宽的原因。
    这个时候就需要分布式来支撑,分布式:把项目的每一个功能模块拆分成单个的系统,单独为每一个节点
    添加服务器,需要系统之间的配置来完成业务逻辑
 2.一旦把系统拆分成各个单独的服务的话,那么就会面临各个服务之间的调用问题?
   服务的调用方式:
   Rpc http 两种方式
   rpc:这种调用方式有常见的WebService 和 dubbo
   http:这种方式其实是一种网络协议,一般是方式Rest风格的调用采用这种方式

如果我们选择http方式进行服务之间的调用的话,那么就需要http的客户端工具,我们采用Spirng中的RestTemplate进行服务之间的调用

   RestTemplate的使用方式:
   1>.首先我们在项目中注册一个RestTemplate对象,可以在启动类中注册
   
    @Bean
    public RestTemplate restTemplate() {
   
        return new RestTemplate();
    }

   2>.在测试类中直接注入这个对象,然后测试使用

    @Test
    public void httpGet() {
        User user = this.restTemplate.getForObject("http://localhost/user/8", User.class);
        System.out.println(user);
    }

微服务

定义:SpringCloud也是一样,它将现在非常流行的一些技术整合到一起,实现了诸如:配置管理,服务发现,智能路由,负载均衡,熔断器,控制总线,集群状态等等功能

Eureka的实现步骤:
服务端:
1.首先是导入eureka的服务端的依赖
2.在启动类上加上一个注解表示这个是一个eureka的服务
3.在配置文件中的配置,配置主要是一个服务的地址(刚开始不然报错,地址就写自己,自己注册自己),还有一个是服务的名称,因为注册到
  eureka中的服务都是需要配置一个名称的,因为eureak注册中心是需要记录你服务的名称的,才可以给服务调用者方便的提供服务!
  还有一个是服务的端口号 一般是10086(呼叫中心)
服务消费方(客户端)
1.首先是导入依赖,导入eureka的客户端的依赖
2.在启动类上加一个注解EnabaleDiscoverClient依赖
3.配置服务名称
  spring:
    application:
       name: user-service  //配置名称,这个名称就是在服务注册中心的名称

  配置地址:
  
  eureka:
    client:
       service-url:
         defaultZone: http://127.0.0.1:10086/eureka      

服务提供方(客户端)
服务提供方和服务消费方一样的!!!!

ribbon负载均衡(负载均衡是基于erueka注册中心的!!!)

应用场景:举个例子当我们的服务提供方有多个的实例的时候,我们采用ribbon负载均衡的方式对服务进行调用
1.首先在服务的消费方引入负载均衡的依赖
2.在启动类的RestTemplate方法上添加一个@LoadBalance注解
3.把请求的路径修改成服务的id即可
  String url="http://user-service/user/"+id
  User user=restTemplate.getForObject(url,user.class);
  return user;

Hystrix 服务的熔断

  雪崩:就是服务的调用之间出现了级联的失败问题,加入一个请求到tomcat服务器以后,调用了一个服务,但是个服务依赖了另一个服务,但是这个服务已经挂了,但是用户是一直在访问,假如这个tomcat一共有1000个线程,但是就是因为这一个服务的出现了异常,把这1000个线程全部用完了,当有用户进来访问其他的服务的时候也是访问不了的,因为tomcat的线程已经满了,导致整个系统的崩溃,叫做雪崩效应,又叫做蝴蝶效应!
  解决的方式:
  1.线程的隔离+服务的降级

  线程的隔离:
  意思就是说,通过线程池把服务隔离起来,一个服务分配一个线程池,每一个线程池中假设分配10个线程,这个时候如果某一个服务出现了问题,那么只会占满该服务的线程池,不会影响到其他的线程池,所以就不影响到其他服务的调用!

  服务的降级:
  一旦一个请求进来以后,服务出现了异常 ,不会让用户处于一直等待状态,可以快速的结束这次请求,然后给予有好的提示!
  或者说把更多的服务器资源去帮助这个服务!


 触发服务的降级的原因:线程池已经满了,或者是请求超时了!

 注意:在服务的消费方进行服务的降级处理,因为消费方是用来调用别的服务的!
 使用步骤:

1. 首先在服务的消费方引入Hystrix的依赖
2. 在启动类中配置注解@EnableCircuitBreaker
3. 这个时候发现这个springcloud程序的客户端上有三个注解 @EnableCircuitBreaker @EnableDiscoveryClient @SpringbootApplication
   所以这个spring官方就把这三个注解合成@SpringCloutApplication注解 于是一个标准的springcloud客户端程序需要这个注解!
4.配置 使用默认的配置就可以了,超时时长都是使用默认的时长就可以了!
5.开启服务的降级 一般是使用@HystrixCommand(fallbackMethod=失败方法名称)  ,但是注意成功的方法和失败的方法的返回值类型和参数列表
  都是一样的!
  如下所示:
   
   @RestController("user")
  public class ConsumerController{
    @Autowired
    private RestTemplate restTemplate;

    //定义方法
    @GetMapping("{id}")
    @HystrixCommand(fallbackMethod= "queryUserByIdFallBack")
    public String queryUserById(@PathVariable("id") Long id){
       String url="http://user-service/user"+id;
       String user=restTemplate.getForObject(url,String.class);
       return user;
    }
   

    //定义失败的方法
    public String queryUserByIdFallBack(Long id){
        return "服务正忙!"
    }

  }   
Hystrix熔断器的原理:
 熔断器有三个状态,close open halfopen  请求正常的情况下是close状态,就是熔断器关闭状态,假设在20次请求内有百分之五十的请求是
 失败的,那么这个时候熔断器就是open状态,这个时候,在有请求进来的时候就是直接返回失败都是不会去尝试加载,过一段时间就会进入一个
 halfopen半开的状态,他会让一部分请求进来,如果这些请求是好的,没有问题的,那么熔断器就会进入关闭状态,否则还是开启状态!

Feign技术:

Feign就是来解决了远程调用的问题,因为开发者觉得使用
String url="http://user-service/user/"+id
这种方式不是特别的方便而且在路径中user路径都是写死的,所以觉得不够优雅
所以Feign就是来解决这个问题的!!
表现:实际上我们是实现了一次远程调用,但是在controller中看不出来,在controller看出的只是调用了本地的一个方法
      这样也就达到了Feign的单词的意思了 ,“欺骗” !
Feign 实现步骤:
实现调用的肯定是消费方,所以都是在消费方中操作!
1.首先在消费方中引入依赖 openFeign
2.在启动类中添加注解@EnableFeignClients 启用Feign的客户端
3.定义一个包叫做Client 定义了一个接口userClient,在接口中告诉了Feign的调用信息(服务的名称user-service,路径,参数,返回值)
  这些信息和使用RestTemplate调用的时候信息是一样的,一个都没有少,只是使用了Springmvc这套语法体现出了这些信息
  如下:
    @FeignClient("user-service")
    public interface userClient{
      @GetMapping("user/{id}")
      User queryById(ParthVariable("id") Long id);
    }

4. 然后再controller中直接注入这个userClient,然后直接调用定义好的接口就可以了
   如下:
   @Autowired
   private userClient client;
   @GetMapping("{id}")
   public User queryUserById(@PathVariable("id") Long id){
       return client.queryById(id);
   } 

原理:这个里面的原理就是和mybatis一样的,底层使用动态代理的方式,根据接口帮我们写好了远程调用的代码了!    

注意:1.OpenFeign的依赖中已经有了ribbon负载均衡的依赖和Hystrix的依赖,所以这两个依赖是不用再引入了!
     2. Feign中的熔断机制和spirngcloud中的熔断机制的配置有点区别,如果使用,可以百度!

zuul网关:

zuul网关就是起到一个boss的作用,就是起到了一个路由和过滤的作用
一切请求都是经过网关,都是由网关来实现鉴权,动态路由的操作,zuul就是
我们的统一的入口!
实现步骤:
1.首先引入依赖
2.在启动类中添加一个注解@EnableZuulProxy 开启网关的功能
3.在配置文件中编写配置文件 
  server:
     port: 10010
  spring:
     application:
       name: api-getway  #指定服务名


4.使用zuul来代理user-service服务
  编写代理规则:
  zuul:
    routes:
      user-service #这个是路由id,可以随便定义
        path: /user-service/** # 这个是映射路径
        url: http://127.0.0.1:8081 #映射路径对应的实际的url
面向服务的路由的配置:
在刚才的路由规则中,我们把路径对应的服务地址写死了,如果同一个服务有多个实例的话,显然就是不太合理了
,我们应该根据服务的名称,去eureka注册中心中查找服务对应的所有的实例列表,然后动态路由即可!!
实现步骤:

1.首先导入依赖,一个是网关的依赖,一个是eureka客户端的依赖
2.在启动类上添加@Enablezuulproxy 开启网关的功能,同时开启@EnableDiscoveryClient 开启eureka客户端发现功能
3.添加eureka配置,获取服务信息
  eureka:
   Client:
     service-url:
       defaultZone: http://127.0.0.1:10086/eureka
  instance:
    prefer-ip-address: true
    ip-address: 127.0.0.1

 4.修改映射配置,通过服务名称来获取,因为已经有了Eureka客户端,我们可以从Eureka中获取服务的地址信息
   因此映射的时候无需指定ip,而是通过服务名称来获取该服务的实例,而且zool网关中已经集成了Ribbon
   负载均衡的功能:
   zuul:
     routes:
       user-service: #这里是路由id,可以随便写
         path: /user-service/**  #这里是映射路径
         serviceId: user-service #指定服务名称
         

 注意:路由的简化配置
       zuul:
         routes:
           user-service: /user-service/** #这个是映射路径 前面的user-service是服务id
zuul网关的过滤器配置:

zuul网关的一个重要的共两个了就是实现请求鉴权,这个功能的实现技术就是过滤器

zuulFilter 是过滤器的顶级湖南卫视,在这里我们看下定义的四个方法

public abstract ZuulFilter implements IZuulFilter{
    abstract public String filterType(); //过滤器的类型
    abstract public int filterOrder(); //定义的是过滤器的顺序
    boolean shouldFilter(); //来自IZuulFilter 要不要过滤
    object run() throws zuulException; //定义的是过滤的逻辑

}

- shouldFilter:返回一个Boolean值,判断该过滤器是否需要执行。返回true执行,返回false不执行。
- run:过滤器的具体业务逻辑。
- filterType:返回字符串,代表过滤器的类型。包含以下4种:
  - pre:请求在被路由之前执行
  - routing:在路由请求时调用
  - post:在routing和errror过滤器之后调用
  - error:处理请求时发生错误调用
- filterOrder:通过返回的int值来定义过滤器的执行顺序,数字越小优先级越高。