springcloud组件

参考:https://www.cnblogs.com/bt2882/p/13304746.html?sharea_token=8deb2369-f8e3-4b7d-8cfa-47fea11f6e51

https://blog.csdn.net/mango5208/article/details/108996336

https://www.cnblogs.com/qdhxhz/p/9581440.html   熔断

https://www.cnblogs.com/qdhxhz/p/9581440.html

 

@EnableDiscoveryClient和@EnableEurekaClient共同点就是:都是能够让注册中心能够发现,扫描到该服务。

不同点:@EnableEurekaClient只适用于Eureka作为注册中心,@EnableDiscoveryClient 可以是其他注册中心。

 

eureka默认心跳为30秒,失效时间默认为90秒。

A服务第一次与B服务打交道,如果eureka宕机,如果交易在30秒前,则A还可以继续调用B,因采用的事本地缓存。如果是30秒后,则无法调用。

SpringCloud核心组件Eureka(类似于zookeeper)

  首先考虑一个问题,订单服务要调用库存服务、仓储服务、积分服务,如何调用呢?
答:订单服务根本不知道上述服务在哪台服务器上,所以没法调用,而Eureka的作用就是来告诉订单服务它想调用的服务在哪台服务器上,Eureka有客户端和服务端,每一个服务上面都有Eureka客户端,可以把本服务的相关信息注册到Eureka服务端上,那么我们的订单服务就可以就可以找到库存服务、仓储服务、积分服务了。

启动添加@EnableEurekaClient

 

 

 

五、SpringCloud核心组件:Feign(类似于dubbo)

启动添加  @EnableFeignClients

 

通过上面的Eureka,现在订单服务确实知道库存服务、积分服务、仓储服务在哪了,但是我们如何去调用这些服务呢,如果我们自己去写很多代码调用那就太麻烦了,而SpringCloud已经为我们准备好了一个核心组件:Feign,接下来看如何通过Feign让订单服务调用库存服务,注意Feign也是用在消费者端的;

@FeignClient

@RequestMapping

@PathVariable

  

没有底层的建立连接、构造请求、解析响应的代码,直接就是用注解定义一个 FeignClient接口,然后调用那个接口就可以了。人家Feign Client会在底层根据你的注解,跟你指定的服务建立连接、构造请求、发起靕求、获取响应、解析响应,等等。这一系列脏活累活,人家Feign全给你干了。

问题来了,Feign是如何做到的呢?其实Feign的一个机制就是使用了动态代理:

  • 首先,如果你对某个接口定义了@FeignClient注解,Feign就会针对这个接口创建一个动态代理
  • 接着你要是调用那个接口,本质就是会调用 Feign创建的动态代理,这是核心中的核心
  • Feign的动态代理会根据你在接口上的@RequestMapping等注解,来动态构造出你要请求的服务的地址
  • 最后针对这个地址,发起请求、解析响应

 

六、springCloud核心组件:Ribbon

 

上面可以通过Eureka可以找到服务,然后通过Feign去调用服务,但是如果有多台机器上面都部署了库存服务,我应该使用Feign去调用哪一台上面的服务呢,这个时候就需要Ribbon闪亮登场了,它在服务消费者端配置和使用,它的作用就是负载均衡,然后默认使用的负载均衡算法是轮询算法,Ribbon会从Eureka服务端中获取到对应的服务注册表,然后就知道相应服务的位置,然后Ribbon根据设计的负载均衡算法去选择一台机器,Feigin就会针对这些机器构造并发送请求,如下图所示:

启动类添加@EnableDiscoveryClient

首页添加:

@Bean
@LoadBalanced
public RestTemplate restTemplate(){
  return new RestTemplate();
}

 

或者

@Configuration
public class ConfigBean {
    //spring框架提供的RestTemplate类可用于在应用中调用rest服务,
    // 它简化了与http服务的通信方式,统一了RESTful的标准,
    // 封装了http链接, 我们只需要传入url及返回值类型即可
    @Bean
    @LoadBalanced  //配置负载均衡
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}
@RestController
public class UserConsumerController {
    /*
    * 使用restTemplate访问restful接口非常的简单粗暴无脑。
    * (url, requestMap, ResponseBean.class)这三个参数分别代表
    * 请求地址、请求参数、HTTP响应转换被转换成的对象类型。
     */
    @Autowired
    private RestTemplate restTemplate;//提供多种便捷访问远程http服务的方法,简单的restful服务模板

    //ribbon 我们这里的地址应该式一个变量,通过服务名来访问
   // private static final String REST_URL_PREFIX="http://localhost:8001";
    private static final String REST_URL_PREFIX="http://springcloud-provder-user";

    @RequestMapping("/consumer/user/get/{id}")
    public User get(@PathVariable("id")Long id){
     return restTemplate.getForObject(REST_URL_PREFIX+"/user/get/"+id, User.class);//注意get还是post
    }
    @RequestMapping("/consumer/user/add")
    public int addUser(User user){
        return restTemplate.postForObject(REST_URL_PREFIX+"/user/add",user,int.class);
    }
    @RequestMapping("/consumer/user/list")
    public List<User> list(){
        return restTemplate.getForObject(REST_URL_PREFIX+"/user/list",List.class);
    }
}

@PathVariable 映射 URL 绑定的占位符

通过 @PathVariable 可以将 URL 中占位符参数绑定到控制器处理方法的入参中:URL 中的 {xxx} 占位符可以通过

@PathVariable("xxx") 绑定到操作方法的入参中。

一般与@RequestMapping(method = RequestMethod.GET)一起使用

@RequestMapping("/getUserById/{name}")
    public User getUser(@PathVariable("name") String name){
        return userService.selectUser(name);
    }
若方法参数名称和需要绑定的uri中变量名称一致时,可以简写:
@RequestMapping("/getUser/{name}")
    public User getUser(@PathVariable String name){
        return userService.selectUser(name);
    }

七、SpringCloud的核心组件:Hystrix

在微服务架构里,一个系统会有多个服务,以本文的业务场景为例:订单服务在一个业务流程里需要调用三个服务,现在假设订单服务自己最多只有100个线程可以处理请求,如果积分服务出错,每次订单服务调用积分服务的时候,都会卡住几秒钟,然后抛出—个超时异常。

分析下这样会导致什么问题呢?如果系统在高并发的情况下,大量请求涌过来的时候,订单服务的100个线程会卡在积分服务这块,导致订单服务没有一个多余的线程可以处理请求,这种问题就是微服务架构中恐怖的服务器雪崩问题,这么多的服务互相调用要是不做任何保护的话,某一个服务挂掉会引起连锁反应,导致别的服务挂掉,上述描述如下图所示:

但是我们想一下,即使积分服务挂了,那订单服务也不应该挂掉啊,我们只要让存储服务和仓储服务正常工作就可以了,至于积分服务我们后期可以手动给用户加上积分,这个时候就轮到Hystrix闪亮登场了,Hystrix是隔离、熔断以及降级的一个框架,说白了就是Hystrix会搞很多小线程池然后让这些小线程池去请求服务,返回结果,Hystrix相当于是个中间过滤区,如果我们的积分服务挂了,那我们请求积分服务直接就返回了,不需要等待超时时间结束抛出异常,这就是所谓的熔断,但是也不能啥都不干就返回啊,不然我们之后手动加积分咋整啊,那我们每次调用积分服务就在数据库里记录一条消息,这就是所谓的降级,Hystrix隔离、熔断和降级的全流程如下:


//添加熔断降级注解 @EnableCircuitBreaker

 

circuitBreaker.requestVolumeThreshold    //滑动窗口的大小,默认为20 
circuitBreaker.sleepWindowInMilliseconds //过多长时间,熔断器再次检测是否开启,默认为5000,即5s钟 
circuitBreaker.errorThresholdPercentage  //错误率,默认50%

3个参数放在一起,所表达的意思就是:

    每当20个请求中,有50%失败时,熔断器就会打开,此时再调用此服务,将会直接返回失败,不再调远程服务。直到5s钟之后,重新检测该触发条件,判断是否把熔断器关闭,或者继续打开。

 

/**
 * 商品服务客户端
 * name = "product-service"是你调用服务端名称
 * fallback = ProductClientFallback.class,后面是你自定义的降级处理类,降级类一定要实现ProductClient
 */
@FeignClient(name = "product-service",fallback = ProductClientFallback.class)
public interface ProductClient {

    //这样组合就相当于http://product-service/api/v1/product/find
    @GetMapping("/api/v1/product/find")
    String findById(@RequestParam(value = "id") int id);

}
/**
 * 针对商品服务,错降级处理
 */
@Component
public class ProductClientFallback implements ProductClient {

    @Override
    public String findById(int id) {

        System.out.println("ProductClientFallback中的降级方法");

        //这对gai该接口进行一些逻辑降级处理........
        return null;
    }
}

feign.hystrix.enabled=true

 

@RestController
@RequestMapping("api/v1/order")
public class OrderController {

    @Autowired
    private ProductOrderService productOrderService;

    @RequestMapping("save")
    //当调用微服务出现异常会降级到saveOrderFail方法中
    @HystrixCommand(fallbackMethod = "saveOrderFail")
    public Object save(@RequestParam("user_id")int userId, @RequestParam("product_id") int productId){

        return productOrderService.save(userId, productId);
    }

    //注意,方法签名一定要要和api方法一致
    private Object saveOrderFail(int userId, int productId){

        System.out.println("controller中的降级方法");

        Map<String, Object> msg = new HashMap<>();
        msg.put("code", -1);
        msg.put("msg", "抢购人数太多,您被挤出来了,稍等重试");
        return msg;
    }
}

@FeignClient(name= "spring-

cloud-producer",fallback = HelloRemoteHystrix.class)
public interface HelloRemote {

    @RequestMapping(value = "/hello")
    public String hello(@RequestParam(value = "name") String name);

}


@Component
public class HelloRemoteHystrix implements HelloRemote{

    @Override
    public String hello(@RequestParam(value = "name") String name) {
        return "hello" +name+", this messge send failed ";
    }
}
 

 

八、SpringCloud核心组件:zull(类似于服务器端的nginx)

该组件是负责网络路由的,假设你后台部署了几百个服务,现在有个前端兄弟,人家请求是直接从浏览器那儿发过来的。打个比方:人家要请求一下库存服务,你难道还让人家记着这服务的名字叫做inventory-service,并且部署在5台机器上,就算人家肯记住这一个,那你后台可有几百个服务的名称和地址呢?难不成人家请求一个,就得记住一个?哈哈哈

上面这种情况,压根儿是不现实的。所以一般微服务架构中都必然会设计一个网关在里面,像android、ios、pc前端、微信小程序、H5等等,不用去关心后端有几百个服务,就知道有一个网关,所有请求都往网关走,网关会根据请求中的一些特征,将请求转发给后端的各个服务。

九、简单总结

Eureka:
服务启动的时候,服务上的Eureka客户端会把自身注册到Eureka服务端,并且可以通过Eureka服务端知道其他注册的服务
Ribbon:
服务间发起请求的时候,服务消费者方基于Ribbon服务做到负载均衡,从服务提供者存储的多台机器中选择一台,如果一个服务只在一台机器上面,那就用不到Ribbon选择机器了,如果有多台机器,那就需要使用Ribbon选择之后再去使用
Feign:
Feign使用的时候会集成Ribbon,Ribbon去Eureka服务端中找到服务提供者的所在的服务器信息,然后根据随机策略选择一个,拼接Url地址后发起请求
Hystrix:
发起的请求是通过Hystrix的线程池去访问服务,不同的服务通过不同的线程池,实现了不同的服务调度隔离,如果服务出现故障,通过服务熔断,避免服务雪崩的问题 ,并且通过服务降级,保证可以手动实现服务正常功能
Zuul:
如果前端调用后台系统,统一走zull网关进入,通过zull网关转发请求给对应的服务

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值