微服务加强负载均衡

重点:服务负载均衡设计及实现

一,LoadBalancerClient的应用

第一步:修改ConsumerController类,注入LoadBalancerClient对象,并添加doRestEcho2方法,然后进行服务访问.
使用LoadBalancerClient的实例对象,使用getHost方法以及getPort方法获取服务端的IP地址以及端口号
@GetMapping("/consumer/doRestEcho2")
    public String doRestEcho2(){
        ServiceInstance instance =
                loadBalancerClient.choose("sca-provider");
        String ip = instance.getHost();
        int port = instance.getPort();
        //String url = "http://"+ip+":"+ port +"/provider/echo/{msg}";
        String url = String.format("http://%s:%s/provider/echo/%s", ip, port, appName);
        return restTemplate.getForObject(url,String.class);
    }

二,修改sca-provider的配置文件端口,分别以8081,8082端口方式进行启动。
三,启动成功以后,访问nacos的服务列表,检测服务是否成功注册
结论:通过不断刷新检测我发现,通过LoadBalancerClient实例对象方式启动时,访问方式采用的是负载均衡方式
原因:里的负载均衡实现默认是因为Nacos集成了Ribbon来实现的,Ribbon配合RestTemplate,可以非常容易的实现服务之间的访问。Ribbon是Spring Cloud核心组件之一,它提供的最重要的功能就是客户端的负载均衡(客户端可以采用一定算法,例如轮询访问,访问服务端实例信息),这个功能可以让我们轻松地将面向服务的REST模版请求自动转换成客户端负载均衡方式的服务调用。

二,@LoadBalanced的应用

在启动类中与@bean一起使用

 /*
    * 当我们使用@LoadBalanced 注解描述RestTemplate进行远程服务调动时,会被一个
    * 拦截器拦截,然后进行功能增强。
    * 这里的功能增强是指,基于 loadBalancerClient对象进行服务实例获取
    * 而这个服务实例获取的过程,底层会采用负载均衡
    * */
    @Bean
    @LoadBalanced
    public RestTemplate loadBalancedRestTemplate(){
        return new RestTemplate();
    }
 @Autowired
    private RestTemplate loadBalancedRestTemplate;
    @GetMapping("/consumer/doRestEcho3")
    public String doRestEcho3(){
        //定义远程调用的url
        String url = String.format("http://sca-provider/provider/echo/%s",appName);
        return loadBalancedRestTemplate.getForObject(url,String.class);
    }

@LoadBalanced注解是属于Spring,而不是Ribbon的,Spring在初始化容器的时候,如果检测到Bean被@LoadBalanced注解,Spring会为其设置LoadBalancerInterceptor的拦截器。

三,Ribbon负载均衡策略(了解)

基于Ribbon方式的负载均衡,Netflix默认提供了七种负载均衡策略,对于SpringCloud Alibaba解决方案中又提供了NacosRule策略,默认的负载均衡策略是轮训策略
在这里插入图片描述
系统提供的负载均衡策略不能满足我们需求时,我们还可以基于IRule接口自己定义策略.

小节面试分析

@Bean注解的作用?(一般用于配置类内部,描述相关方法,用于告诉spring此方法的返回值要交给spring管理,bean的名字默认为方法名,假如需要指定名字可以@Bean(“bean的名字”),最多的应用场景是整合第三方的资源-对象)
@Autowired注解的作用?(此注解用于描述属性,构造方法,set方法等,用于告诉spring框架,按找一定的规则为属性进行DI操作,默认按属性,方法参数类型查找对应的对象,假如只找到一个,则直接注入,类型多个时还会按照属性名或方法参数名进行值的注入,假如名字也不同,就出报错.)
Nacos中的负责均衡底层是如何实现的?(通过Ribbon实现,Ribbon中定义了一些负载均衡算法,然后基于这些算法从服务实例中获取一个实例为消费方法提供服务)
Ribbon 是什么?(Netflix公司提供的负载均衡客户端,一般应用于服务的消费方法)
Ribbon 可以解决什么问题? (基于负载均衡策略进行服务调用, 所有策略都会实现IRule接口)
Ribbon 内置的负载策略都有哪些?(8种,可以通过查看IRule接口的实现类进行分析)
@LoadBalanced的作用是什么?(描述RestTemplate对象,用于告诉Spring框架,在使用RestTempalte进行服务调用时,这个调用过程会被一个拦截器进行拦截,然后在拦截器内部,启动负载均衡策略。)
我们可以自己定义负载均衡策略吗?(可以,基于IRule接口进行策略定义,也可以参考NacosRule进行实现)

负载均衡的方法

一,注解方式
 /*
     * 指定默认的负载均衡策略,但是这种配置方式不够灵活,
     * 将来项目上线后,我们所有的类都会打包成一个jar包
     * 假如项目在运行过程中,我们想调整负载均衡,就不太方便了
     * 我们可以将这些配置写到配置文件,最后更新到配置中心
     * */
    @Bean
    public IRule rule(){
        return  new BestAvailableRule();
    }

    //底层默认逻辑实现 @ConditionalOnMissingBean注解配合@Bean注解一起使用时
    //会在没有指定Bean时 才会创建这个Bean对象
    @Bean
    @ConditionalOnMissingBean
    public IRule rule(){
        return  new BestAvailableRule();
    }
二,在配置类中定义轮询策略
sca-provider:
 ribbon: #ribbon是一个负载均衡组件。是Ribbon组件提供了IRule接口及相关实现
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

基于Feign的远程服务调用(重点)

作用:避免每次服务调用都需要url的拼接,简便代码的编写,通过Feign可以简化服务消费方对远程服务提供方法的调用实现

第一步:在服务消费方,添加项目依赖

dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

第二步:在启动类上添加@EnableFeignClients注解

@EnableFeignClients
@SpringBootApplication
public class ConsumerApplication {}

第三步:定义Http请求API,基于此API借助OpenFeign访问远端服务

/*
* @FeignClient 注解用于描述远程服务调用接口,其value属性值有两个层面的含义:
* 第一个就是要你要的远程服务名,第二个含义就是当前bean的名字,假如不使用
* 这个名字还可以使用contextId指定bean的名字。
* */
@FeignClient(value = "sca-provider",
             contextId ="RemoteProviderService")
public interface RemoteProviderService {
    @GetMapping("/provider/echo/{string}")
    String echoMessage(@PathVariable("string") String string);
}

其中,@FeignClient描述的接口底层会为其创建实现类。

第四步:创建FeignConsumerController中并添加feign访问

package com.jt.consumer.controller;
@RestController
@RequestMapping("/consumer ")
public class FeignConsumerController {
    @Autowired
    private RemoteProviderService remoteProviderService;
    /**基于feign方式的服务调用*/
    @GetMapping("/echo/{msg}")
    public String doFeignEcho(@PathVariable  String msg){
        //基于feign方式进行远端服务调用(前提是服务必须存在)
        return remoteProviderService.echoMessage(msg);
    }
}

第五步:启动消费者服务,在浏览器中直接通过feign客户端进行访问
说明,feign方式的远程服务调用,底层会自动基于ribbon组件实现负载均衡。

Feign配置进阶实践

一个服务提供方通常会提供很多资源服务,服务消费方基于同一个服务提供方写了很多服务调用接口,此时假如没有指定contextId,服务
启动就会失败,例如,假如在服务消费方再添加一个如下接口,消费方启动时就会启动失败,例如:

@FeignClient(name="sca-provider")
 public interface RemoteOtherService {
     @GetMapping("/doSomeThing")
     public String doSomeThing();
}

其启动异常如下:

The bean 'optimization-user.FeignClientSpecification', defined in null, could not be registered. A bean with that name has already been defined in null and overriding is disabled.

此时我们需要为远程调用服务接口指定一个contextId,作为远程调用服务的唯一标识(这个标识是Bean对象的名字)即可,例如:

@FeignClient(name="sca-provider",contextId="remoteProviderService")//sca-provider为服务提供者名称
interface RemoteProviderService{
    @GetMapping("/provider/echo/{string}")//前提是远端需要有这个服务
    public String echoMessage(@PathVariable("string") String string);
}

还有,当我们在进行远程服务调用时,假如调用的服务突然不可用了或者调用过程超时了,怎么办呢?一般服务消费端会给出具体的容错方案,例如,在Feign应用中通过FallbackFactory接口的实现类进行默认的相关处理,例如:

第一步:定义FallbackFactory接口的实现,代码如下:

package com.cy.service.factory;
/**
 * 基于此对象处理RemoteProviderService接口调用时出现的服务中断,超时等问题
 */
@Component
public class ProviderFallbackFactory implements FallbackFactory<RemoteProviderService> {
    /**
     * 此方法会在RemoteProviderService接口服务调用时,出现了异常后执行.
     * @param throwable 用于接收异常
     */
    @Override
    public RemoteProviderService create(Throwable throwable) {
        return (msg)->{
                return "服务维护中,稍等片刻再访问";
        };
    }
}

第二步:在Feign访问接口中应用FallbackFactory对象,例如:

@FeignClient(name = "sca-provider", contextId = "remoteProviderService",
             fallbackFactory = ProviderFallbackFactory.class)//sca-provider为nacos中的服务名
public interface RemoteProviderService {
    @GetMapping("/provider/echo/{msg}")
    public String echoMsg(@PathVariable String msg);
}

第三步:在配置文件application.yml中添加如下配置,启动feign方式调用时的服务中断处理机制.

feign:  
  hystrix:
    enabled: true #默认值为false

第四步:在服务提供方对应的调用方法中添加Thread.sleep(5000)模拟耗时操作,然后启动服务进行访问测试.

Feign 调用过程分析(了解)
Feign应用过程分析(底层逻辑先了解):
1)通过 @EnableFeignCleints 注解告诉springcloud,启动 Feign Starter 组件。
2) Feign Starter 会在项目启动过程中注册全局配置,扫描包下所由@FeignClient注解描述的接口,然后由系统底层创建接口实现类(JDK代理类),并构建类的对象,然后交给spring管理(注册 IOC 容器)。
3) Feign接口被调用时,底层代理对象会将接口中的请求信息通过编码器创建 Request对象,基于此对象进行远程过程调用。
4) Feign客户端请求对象会经Ribbon进行负载均衡,挑选出一个健康的 Server 实例(instance)。
5) Feign客户端会携带 Request 调用远端服务并返回一个响应。
6) Feign客户端对象对Response信息进行解析然后返回客户端。

小节面试分析
为什么使用feign?(基于Feign可以更加友好的实现服务调用,简化服务消费方对服务提供方方法的调用)。
@FeignClient注解的作用是什么?(告诉Feign Starter,在项目启动时,为此注解描述的接口创建实现类-代理类)
Feign方式的调用,底层负载均衡是如何实现的?(Ribbon)
@EnableFeignCleints 注解的作用是什么?(描述配置类,例如启动类)
总结(Summary)
重难点分析
何为注册中心?(用于记录服务信息的一个web服务,例如淘宝平台,滴滴平台,美团外卖平台,……)
注册中心的核心对象?(服务提供方,服务消费方,注册中心-Registry)
市面上常用注册中心?(Google-Consul,Alibaba-Nacos,…)
Nacos安装、启动、服务的注册、发现机制以及实现过程
服务调用时RestTemplate对象的应用。
基于Feign方式的服务调用及基本原理?
FAQ分析
Nacos是什么,提供了什么特性(服务的注册、发现、配置)?
你为什么会选择Nacos?(活跃度、稳定、性能、学习成本)
Nacos的官网?(nacos.io)
Nacos在github的源码?(github.com/alibaba/nacos)
Nacos在windows环境下安装?(解压即可使用)
Nacos在windows中的的初步配置?(application.properties访问数据库的数据源)
Nacos服务注册的基本过程?(服务启动时发送web请求)
Nacos服务消费的基本过程?(服务启动时获取服务实例,然后调用服务)
Nacos服务负载均衡逻辑及设计实现?(Ribbon)
注册中心的核心数据是什么?(服务的名字和它对应的网络地址)
注册中心中心核心数据的存取为什么会采用读写锁?(底层安全和性能)
Nacos健康检查的方式?(基于心跳包机制进行实现)
Nacos是如何保证高可用的?(重试,本地缓存、集群)
RestTemplate的基本作用是什么?
Feign是什么,它的应用是怎样的,feign应用过程中的代理对象是如何创建的(JDK)?
Feign方式的调用过程,其负载均衡是如何实现?(Ribbon)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值