微服务入门:Ribbon与Nacos

微服务入门:Ribbon与Nacos

一、Ribbon概论

微服务入门:服务拆分与Eureka有提到过Eurka具有负载均衡的作用

负载均衡其实是用一个名为Ribbon的组件实现的

那么Ribbon是什么?

先给Ribbon来个简单的自我介绍,Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法和服务调用。也就是说Ribbon会自动帮我们基于某种规则去选择某种服务


二、Ribbon实现原理

我们使用RestTemplate对象只需要访问一个带有对象名称的路径,也就是http://userservice/user/XX,就可以访问到相对应的接口,这其中离不开LoadBalancerInterceptor的帮助,它会去RestTemplate的请求进行拦截,然后从Eureka中获取服务id与端口号,随后利用负载均衡算法得到真实的服务地址信息,替换服务id。

在LoadBalancerInterceptor这个类中,会有一个intercept方法,其拦截了用户的HttpRequest请求,通过调用以下api

  • request.getURI():获取请求uri,也就是 http://user-service/user/8
  • originalUri.getHost():获取uri路径的主机名,其实就是服务id,user-service
  • this.loadBalancer.execute():处理服务id,和用户请求。

获取到了url、主机名、和服务的id,再将这些信息作为参数传到LoadBalancerClient(this.loadBalancer)的execute的方法中

在这里插入图片描述

而在LoadBalancerClient的execute方法中可以通过服务id获取到服务列表,并获取合适的服务的端口号,其实现的主要api如下

  • getLoadBalancer(serviceId):根据服务id获取ILoadBalancer,而ILoadBalancer会拿着服务id去eureka中获取服务列表并保存起来。
  • getServer(loadBalancer):利用内置的负载均衡算法,从服务列表中选择一个。也就是127.0.0.1:8080

在这里插入图片描述

从这里可以知道,负载均衡的实现是在getServer方法中实现的

在这里插入图片描述

继续跟进

可以发现这里返回一个rule,那我们就再跟进看看这个rule到底是什么

在这里插入图片描述

可以发现,前面传过来的default对应的是RoundRobinRule对象

在这里插入图片描述

查询相关资料可以知道,RoundRobinRule对应的是一个轮询的规则,所以这里采用的默认负载均衡规则是轮询

Ribbon的主要流程如下

在这里插入图片描述


三、常用的Ribbon负载均衡策略

内置负载均衡规则类规则描述
RoundRobinRule简单轮询服务列表来选择服务器。它是Ribbon默认的负载均衡规则。
AvailabilityFilteringRule对以下两种服务器进行忽略: (1)在默认情况下,这台服务器如果3次连接失败,这台服务器就会被设置为“短路”状态。短路状态将持续30秒,如果再次连接失败,短路的持续时间就会几何级地增加。 (2)并发数过高的服务器。如果一个服务器的并发连接数过高,配置了AvailabilityFilteringRule规则的客户端也会将其忽略。并发连接数的上限,可以由客户端的..ActiveConnectionsLimit属性进行配置。
WeightedResponseTimeRule为每一个服务器赋予一个权重值。服务器响应时间越长,这个服务器的权重就越小。这个规则会随机选择服务器,这个权重值会影响服务器的选择。
ZoneAvoidanceRule以区域可用的服务器为基础进行服务器的选择。使用Zone对服务器进行分类,这个Zone可以理解为一个机房、一个机架等。而后再对Zone内的多个服务做轮询。
BestAvailableRule忽略那些短路的服务器,并选择并发数较低的服务器。
RandomRule随机选择一个可用的服务器。
RetryRule重试机制的选择逻辑

既然有那么多负载均衡策略,那就说明我们可以自己自定义指定某个负载均衡策略

首先,先在OrderApplication类中,定义一个IRule

@Bean
public IRule randomRule(){
	return new RandomRule();
}

然后再yml文件进行配置

userservice:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡规则 

四、饥饿加载

Ribbon默认是采用懒加载,即第一次访问时才会去创建LoadBalanceClient,请求时间会很长。

而饥饿加载则会在项目启动时创建,降低第一次访问的耗时,通过下面配置开启饥饿加载:

ribbon:
  eager-load:
    enabled: true
    clients: userservice

五、Nacos注册中心

1、Nacos简介

Nacos与Eureka一样,都是一个注册中心,但是Nacos是阿里巴巴的产品,也是SpringCloud的一个组件。与Eureka相比,Nacos的功能更加丰富,同时在国内也更受欢迎


2、将服务注册到nacos

  • 父工程引入依赖

    <dependency>
    	<groupId>com.alibaba.cloud</groupId>
    	<artifactId>spring-cloud-alibaba-dependencies</artifactId>
    	<version>2.2.6.RELEASE</version>
    	<type>pom</type>
    	<scope>import</scope>
    </dependency>
    
  • 在子工程引入nacos客服端依赖包

    <!--nacos客户端依赖包-->
    <dependency>
    	<groupId>com.alibaba.cloud</groupId>
    	<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    
  • 在对应工程的yml文件配置nacos地址

    spring:
      application:
        name: orderservice  #orderservice的服务名称
      cloud:
        nacos:
          server-addr: localhost:8848 #nacos地址
    

通过cmd指令打开nacos,先定位到nacos的bin目录,输入以下指令(window指令)打开启动nacos

startup.cmd -m standalone

启动之后登录地址http://127.0.0.1:8848/nacos即可

登录账号和密码默认为nacos

在这就能看到我们已经成功将服务注册了

在这里插入图片描述


3、服务分级存储模型

上面的示例都是将服务布置在一个集群(机房),但是如果当机房出现天灾人祸的话,这个服务的实例就会都全军覆没,因此为了解决这个问题,可以将一个服务的实例布置在多个集群,以防万一

在这里插入图片描述

但是这里需要注意的是,服务的调用一般应该尽可能选择本地的服务,一般不跨集群调用,因为这样的话延迟会比较高

只有当本地集群不可以访问的时候,再访问其他集群

在这里插入图片描述


(1)、配置集群

在需要配置集群的服务的yml文件配置以下属性

spring:
  application:
    name: orderservice  #orderservice的服务名称
  cloud:
    nacos:
      server-addr: localhost:8848
      discovery:
        cluster-name: HZ

这当中的cluster-name为集群名称,可以自己自定义

注意:如果是自己本机测试的话,不可以修改集群之后一次性打开一个服务的所有实例,应当先打开一个实例,再改变集群名称,再运行另外一个实例


(2)、配置集群的负载均衡策略

首先安装上面那样配置集群,接着修改使用该集群的服务的yml配置文件

这里order-service服务使用了user-service服务,所以再order-service服务设置

userservice:
  ribbon:
    NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule # 负载均衡规则

这里的默认情况下NacosRule是同集群内随机挑选,不会考虑机器的性能问题

但是有些机器比较旧,有些比较新,因此我们一般都是希望服务多调用机器新的服务,小频率调用机器旧的集群。

在nacos中,其为我们提供了权重配置来控制访问频率,权重越大则访问频率越高

在nacos控制台中,打开服务服务列表——》点击详情,就可以看到某个服务的所有实例

在这里插入图片描述

点击编辑即可修改权重,权重大小为0-1,支持小数

在这里插入图片描述

注意:当权重修改为0的时候,该服务实例不再被调用


4、环境隔离

环境隔离是基于环境隔离的,也就是说,在开发中我们会遇到很多不同的环境,对于这些不同的环境,不同的服务之间是不能访问的,因此我们需要对其进行隔离

Nacos提供了namespace来实现环境隔离功能。

  • nacos中可以有多个namespace
  • namespace下可以有group、service等
  • 不同namespace之间相互隔离,例如不同namespace的服务互相不可见

在这里插入图片描述


(1)、创建namespace

在nacos控制台的命名管理,里面新建一个命名空间

在这里插入图片描述

下面两个是必填的,第一项不用填,会自动生成

在这里插入图片描述

新建完毕之后,就可以得到这样的一串命名空间ID

在这里插入图片描述


(2)、配置namespace

使用上述的命名空间id在需要配置的文件的yml配置namespace

这里是在order-service的yml文件配置

spring:
  cloud:
    nacos:
      server-addr: localhost:8848
      discovery:
        cluster-name: HZ
        namespace: 86be35cb-2a01-451f-9978-b6c45e72fb76 # 命名空间,填ID

重启服务,即可得到两个环境中有不同的服务

在这里插入图片描述


六、Nacos与Eureka的不同

Nacos的服务实例分为两种l类型:

  • 临时实例:如果实例宕机超过一定时间,会从服务列表剔除,默认的类型。

  • 非临时实例:如果实例宕机,不会从服务列表剔除,也可以叫永久实例。

配置一个服务实例为永久实例:

spring:
  cloud:
    nacos:
      discovery:
        ephemeral: false # 设置为非临时实例

Nacos和Eureka整体结构类似,服务注册、服务拉取、心跳等待,但是也存在一些差异:

在这里插入图片描述

  • Nacos与eureka的共同点

    • 都支持服务注册和服务拉取
    • 都支持服务提供者心跳方式做健康检测
  • Nacos与Eureka的区别

    • Nacos支持服务端主动检测提供者状态:临时实例采用心跳模式,非临时实例采用主动检测模式
    • 临时实例心跳不正常会被剔除,非临时实例则不会被剔除
    • Nacos支持服务列表变更的消息推送模式,服务列表更新更及时
    • Nacos集群默认采用AP方式,当集群中存在非临时实例时,采用CP模式;Eureka采用AP方式

七、Nacos配置管理

Nacos与Eureka不同,Nacos既可以用来做注册中心,也可以用来做配置管理来使用


1、统一配置管理

在实际开发中,我们也许需要部署很多微服务,但是如果当我们需要修改微服务的某个配置文件的时候,就会需要修改很多,这是极其不方便的,因此nacos为我们提供了一个统一的配置管理

也就是当配置发生改变的时候,nacos会通知微服务告诉它配置改变了,应该从nacos将新的配置拉取下来,实现了配置的热更新

在这里插入图片描述


2、在nacos添加配置文件

首先,先在nacos控制中心的配置管理中添加配置

在这里插入图片描述

这里的Date ID的命名规则是服务名称+开发环境+后缀(userservice-dev.yaml)

Group的话默认分组即可

配置格式一定要勾选YAML

然后配置内容就可以像在本地的yml文件那样配置,到时候微服务拉取配置下来就和本地的yml合并

在这里插入图片描述

注意:项目的核心配置,需要热更新的配置才有放到nacos管理的必要。基本不会变更的一些配置还是保存在微服务本地比较好。


3、从nacos中拉取配置

在这里插入图片描述

服务从nacos中拉取配置,需要借助一个spring引入的新配置文件——bootstrap.yaml

这个文件的作用就是会在application.yml先读取bootstrap.yml文件,然后读取里面的nacos配置信息,从nacos的地址拉取特定的配置下来

具体实现过程如下:

首先先引入nacos-config依赖

<!--nacos配置管理依赖-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

然后新建一个bootstrap.yml文件,在里面配置相关信息

这里再user-service中添加bootstrap.yml文件

spring:
  application:
    name: userservice # 服务名称
  profiles:
    active: dev #开发环境,这里是dev 
  cloud:
    nacos:
      server-addr: localhost:8848 # Nacos地址
      config:
        file-extension: yaml # 文件后缀名

这里会根据spring.cloud.nacos.server-addr获取nacos地址,再根据

${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}作为文件id,来读取配置。

在这里插入图片描述

这样从nacos中拉取配置下来


4、实现配置的热更新

实现配置的热更新有两种方式

  1. 通过@RefreshScope实现热更新
  2. 通过@ConfigurationProperties解决

(1)方式1

在controller中加入@RefreshScope如下所示

@Slf4j
@RestController
@RequestMapping("/user")
@RefreshScope
public class UserController {

    @Autowired
    private UserService userService;

    // @Value("${pattern.dateformat}")
    // private String dataformat;

    @GetMapping("prop")
    public PatternProperties properties(){
        return patternProperties;
    }

    @GetMapping("now")
    public String now(){
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dataformat));
    }

    /**
     * 路径: /user/110
     *
     * @param id 用户id
     * @return 用户
     */
    @GetMapping("/{id}")
    public User queryById(@PathVariable("id") Long id) {
        return userService.queryById(id);
    }
}

但是这种方法不常用,一般用另外一种方法


(2)方式2

使用@ConfigurationProperties注解代替@Value注解。

@Data
@Component
@ConfigurationProperties(prefix = "pattern")
public class PatternProperties {
    private String dateformat;
    private String envShareValue;
}
@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    @Autowired
    private PatternProperties patternProperties;

    @GetMapping("prop")
    public PatternProperties properties(){
        return patternProperties;
    }

    @GetMapping("now")
    public String now(){
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(patternProperties.getDateformat()));
    }

    /**
     * 路径: /user/110
     *
     * @param id 用户id
     * @return 用户
     */
    @GetMapping("/{id}")
    public User queryById(@PathVariable("id") Long id) {
        return userService.queryById(id);
    }
}

这样当我们在nacos修改配置文件的时候,即可实现热更新


5、配置共享

配置共享的实现也很简单,在nacos配置一个服务名+后缀的配置,也就是[spring.application.name].yaml,这个不包含任何环境,所以可以用来做环境共享
在这里插入图片描述

不管是dev环境还是test环境,都可以读取其中的配置


6、配置共享的优先级

当nacos、服务本地同时出现相同属性时,优先级有高低之分:

在这里插入图片描述


  • 8
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
斐波那契查找算法是一种基于二分查找算法的查找算法,它利用了斐波那契数列的特性来确定查找的位置。下面是斐波那契查找算法的设计步骤: 1. 首先,需要确定斐波那契数列的长度,使得它大于等于待查找数组的长度。假设斐波那契数列的长度为n,那么有:F(n) = F(n-1) + F(n-2),其中F(0) = 0,F(1) = 1。 2. 然后,需要将待查找数组扩展到长度为n,扩展的部分用原数组的最后一个元素填充。 3. 接着,需要定义两个指针:low和high。初始时,low指向待查找数组的第一个元素,high指向斐波那契数列中第一个大于等于n的元素的下标减1。 4. 然后,需要计算mid的值,mid的值为low加上斐波那契数列中第k-1个元素的值,其中k为满足F(k)-1 >= n的最小值。 5. 然后,比较待查找数组中第mid个元素和要查找的元素的大小。如果待查找数组中第mid个元素小于要查找的元素,则将low指向mid+1;如果待查找数组中第mid个元素大于要查找的元素,则将high指向mid-1;否则,找到了要查找的元素,返回mid。 6. 重复步骤4和步骤5,直到low大于high为止。 下面是一个Python实现的斐波那契查找算法的例子: ```python def fibonacci_search(arr, x): n = len(arr) fib_k2 = 0 # F(k-2) fib_k1 = 1 # F(k-1) fib_k = fib_k1 + fib_k2 # F(k) while fib_k < n: fib_k2 = fib_k1 fib_k1 = fib_k fib_k = fib_k1 + fib_k2 offset = -1 while fib_k > 1: i = min(offset+fib_k2, n-1) if arr[i] < x: fib_k = fib_k1 fib_k1 = fib_k2 fib_k2 = fib_k - fib_k1 offset = i elif arr[i] > x: fib_k = fib_k2 fib_k1 = fib_k1 - fib_k2 fib_k2 = fib_k - fib_k1 else: return i if fib_k1 and arr[offset+1] == x: return offset+1 return -1 ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

起名方面没有灵感

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值