首页 > 作文

聊聊SpringCloud中的Ribbon进行服务调用的问题

更新时间:2023-04-04 13:31:46 阅读: 评论:0

目录
1、robbon1.1、ribbon概述1.2、ribbon负载均衡演示1.3、ribbon核心组件irule1.4、ribbon负载均衡算法1.4.1、轮询算法原理 负载均衡算法:1.4.2、roundrobinrule 源码1.4.3、手写轮询算法

前置内容
(1)、微服务理论入门和手把手带你进行微服务环境搭建及支付、订单业刘丽娜务编写
(2)、springcloud之eureka服务注册与发现
(3)、springcloud之zookeeper进行服务注册与发现
(4)、springcloud之consul进行服务注册与发现

1、robbon

1.1、ribbon概述

(1)、ribbon是什么?

springcloud-ribbon是基于netflix ribbon实现的一套客户端负载均衡的工具。简单来说,ribbonnetflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法和服务调用。ribbon客户给水排水工程师端组件提供一系列完善的配置如连接超时、重拾等。简单的说,就是在配置文件中列出load balancer(简称lb)后面的所有机器,ribbon会自动的帮助你基于某种规则(如简单轮询,随即连接等)去连接这些机器。我们很容易使用ribbon实现自定义的负载均衡算法。一句话就是 负载均衡+resttemplate调用。

(2)、ribbon的官网

官网地址

且目前也进入了维护模式

(3)、负载均衡(lb)

负载均衡就是将用户的请求平摊的分配到多个服务上,从而达到系统的ha(高可用)。常见的负载均衡由软件nginxlvsf5

1.集中式lb:就是在服务的消费方和提供方之间使用独立的lb设施(可以是硬件,如f5,也可以是软件,如nginx),由该设施负责把访问请求通过某种策略转发至服务的提供方。

2.进程内lb:将lb逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选择出一个合适的服务器。ribbon就属于进程内lb,它只是一个类库,集成于消费方进程,消费方通过它来获取服务提供方的地址。

(4)、ribbon本地负载均衡客户端和nginx服务端负载均衡的区别

nginx是服务器负载均衡,客户端所有请求都会交给nginx实现转发请求。即负载均衡是由服务端实现的。ribbon本地负载均衡,在调用微服务接口的时候,会在注册中心获取注册信息列表之后缓存到jvm本地,从而在本地实现rpc远程服务调用技术。

1.2、ribbon负载均衡演示

(1)、架构说明

ribbon其实就是一个软负载均衡的客户端组件,他可以和其他所需请求的客户端结合使用,和eureka结合只是其中的一个实例。

ribbon在工作时分为两步

第一步先选择eurekarver,他优先选择在同一个区域内负载较少的rver。第二步再根据用户指定的策略,在从rver取到的服务注册列表中选择一个地址。其中ribbon提供了多种策略:比如轮询、随机和根据响应时间加权。

(2)、pom文件

所以在引入eureka的整合包中就包含了整合ribbonjar包。

所以我们前面实现的8001和8002交替访问的方式就是所谓的负载均衡。

(3)、resttemplate的说明

getforobject:返回对象为响应体中数据转化成的对象,基本上可以理解为json。getforentity:返回对象为responentity对象,包含了响应中的一些重要信息,比如响应头、响应状态码、响应体等。postforobjectpostforentity

1.3、ribbon核心组件irule

1. 主要的负载规则

roundrobinrule:轮询randomrule:随机retryrule:先按照roundrobinrule的策略获取服务,如果获取服务失败则在指定时间内会进行重试weightedrespontimerule:对roundrobinrule的扩展,响应速度越快的实例选择权重越大,越容易被选择bestavailablerule:会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务availabilityfilteringrule:先过滤掉故障实例,再选择并发较小的实例zoneavoidancerule:默认规则,复合判断rver所在区域的性能和rver的可用性选择服务器

2. 如何替换负载规则

cloud-consumer-order80包下的配置进行修改。我们自己自定义的配置类不能放在@componentscan所扫描的当前包以及子包下,否则我们自定义的这个配置类就会被所有的ribbon客户端所共享,达不到特殊化定制的目的了。在com.xiao的包下新建一个myrule的子包。

myrule的包下新建一个mylfrule配置类

​​​​​​​import com.netflix.loadbalancer.irule;import com.netflix.loadbalancer.randomrule;import org.springframework.context.annotation.bean;import org.springframework.context.annotation.configuration;@configurationpublic class mylfrule {    @bean    public irule getrandomrule(){        return new randomrule(); // 新建随机访问负载规则    }}
对主启动类进行修改,修改为如下:
import com.xiao.myrule.mylfrule;import org.springframework.boot.springapplication;import org.springframework.boot.autoconfigure.springbootapplication;import org.springframework.cloud.netflix.eureka.enableeurekaclient;import org.springframework.cloud.netflix.ribbon.ribbonclient;@springbootapplication@enableeurekaclient@ribbonclient(name = "cloud-payment-rvice",configuration = mylfrule.class)public class ordermain80 {    public static void main(string[] args) {        springapplication.run(ordermain80.class,args);    }}

6.测试结果 结果就是以我们最新配置的随机方式进行访问的。

1.4、ribbon负载均衡算法

1.4.1、轮询算法原理 负载均衡算法:

rest接口第几次请求数 % 服务器集群总数量 = 实际调用服务器位置下标,每次服务重新启动后rest接口计数从1开始。

1.4.2、roundrobinrule 源码

import com.netflix.client.config.iclientconfig;import java.util.list;import java.util.concurrent.atomic.atomicinteger;import org.slf4j.logger;import org.slf4j.loggerfactory;public class roundrobinrule extends abstractloadbalancerrule {    private atomicinteger nextrvercycliccounter;    private static final boolean available_only_rvers = true;    private static final boolean all_rvers = fal;    private static logger log = loggerfactory.getlogger(roundrobinrule.class);    public roundrobinrule() {        this.nextrvercycliccounter = new atomicinteger(0);    }    public roundrobinrule(iloadbalancer lb) {        this();        this.tloadbalancer(lb);    }    public rver choo(iloadbalancer lb, object key) {   主持人开场白     if (lb == null) {            log.warn("no load balancer");            return null;        } el {            rver rver = null;            int count = 0;            while(true) {                if (rver == null && count++ < 10) {                // 获取状态为up的服务提供者                    list<rver> reachablervers = lb.getreachablervers();                    // 获取所有的服务提供者                    list<rver> allrvers = lb.getallrvers();                    int upcount = reachablervers.size();                    int rvercount = allrvers.size();                                        if (upcount != 0 && rvercount != 0) {                    // 对取模获得的下标进行获取相关的服务提供者                        int nextrverindex = this.incrementandgetmodulo(rvercount);                        rver = (rver)allrvers.get(nextrverindex);                        if (rver == null) {                            thread.yield();                        } el {                            if (rver.isalive() && rver.isreadytorve()) {                                return rver;                            }                            rver = null;                        continue;                    }                    log.warn("no up rvers available from load balancer: " + lb);                    return null;                }                if (count >= 10) {                    log.warn("no available alive rvers after 10 tries from load balancer: " + lb);                }                return rver;            }        }    }    private int incrementandgetmodulo(int modulo) {        int current;        int next;        do {        // 先加一再取模            current = this.nextrvercycliccounter.get();            next = (current + 1) % modulo;            // cas判断,如果判断成功就返回true,否则就一直自旋        } while(!this.nextrvercycliccounter.compareandt(current, next));        return next;    }}

1.4.3、手写轮询算法

1. 修改支付模块的controller

添加以下内容

@getmapping(value = "/payment/lb")public string getpaymentlb(){      return rverport;}

2. applicationcontextconfig去掉@loadbalanced注解

3. loadbalancer接口

import org.springframework.cloud.client.rviceinstance;import java.util.list;public interface loadbalancer {    //收集服务器总共有多少台能够提供服务的机器,并放到list里面    rviceinstance instances(list<rviceinstance> rviceinstances);}

4. 编写mylb类

import org.sprin大连三日游gframework.cloud.client.rviceinstance;import org.springframework.stereotype.component;import java.util.list;import java.util.concurrent.atomic.atomicinteger;@componentpublic class mylb implements loadbalancer {    private atomicinteger atomicinteger = new atomicinteger(0);    //坐标    private final int getandincrement(){        int current;        int next;        do {            current = this.atomicinteger.get();            next = current >= 2147483647 ? 0 : current + 1;        }while (!this.atomicinteger.compareandt(current,next));  //第一个参数是期望值,第二个参数是修改值是        system.out.println("*******第几次访问,次数next: "+next);        return next;    }    @override    public rviceinstance instances(list<rviceinstance> rviceinstances) {  //得到机器的列表        int index = getandincrement() % rviceinstances.size(); //得到服务器的下标位置        return rviceinstances.get(index);    }}

5. 修改ordercontroller类

import com.xiao.cloud.entities.commonresult;import com.xiao.cloud.entities.pay广州美术学院分数线ment;import com.xiao.cloud.lb.loadbalancer;import lombok.extern.slf4j.slf4j;import org.springframework.beans.factory.annotation.autowired;import org.springframework.cloud.client.rviceinstance;import org.springframework.cloud.client.discovery.discoveryclient;import org.springframework.http.responentity;import org.springframework.web.bind.annotation.getmapping;import org.springframework.web.bind.annotation.pathvariable;import org.springframework.web.bind.annotation.restcontroller;import org.springframework.web.client.resttemplate;import javax.annotation.resource;import java.net.uri;import java.util.list;@restcontroller@slf4jpublic class ordercontroller {    // public static final string payment_url = "http://localhost:8001";    public static final string payment_url = "http://cloud-payment-rvice";    @resource    private resttemplate resttemplate;    @resource    private loadbalancer loadbalancer;    @resource    private discoveryclient discoveryclient;    @getmapping("/consumer/payment/create")    public commonresult<payment>   create( payment payment){        return resttemplate.postforobject(payment_url+"/payment/create",payment,commonresult.class);  //写操作    }    @getmapping("/consumer/payment/get/{id}")    public commonresult<payment> getpayment(@pathvariable("id") long id){        return resttemplate.getforobject(payment_url+"/payment/get/"+id,commonresult.class);    }    @getmapping("/consumer/payment/getforentity/{id}")    public commonresult<payment> getpayment2(@pathvariable("id") long id){        responentity<commonresult> entity = resttemplate.getforentity(payment_url+"/payment/get/"+id,commonresult.class);        if (entity.getstatuscode().is2xxsuccessful()){            //  log.info(entity.getstatuscode()+"\t"+entity.getheaders());            return entity.getbody();        }el {            return new commonresult<>(444,"操作失败");        }    }    @getmapping(value = "/consumer/payment/lb")    public string getpaymentlb(){        list<rviceinstance> instances = discoveryclient.getinstances("cloud-payment-rvice");        if (instances == null || instances.size() <= 0){            return null;        }        rviceinstance rviceinstance = loadbalancer.instances(instances);        uri uri = rviceinstance.geturi();        return resttemplate.getforobject(uri+"/payment/lb",string.class);    }}

6. 测试结果

最后是在80018002两个之间进行轮询访问。控制台输出如下

7. 包结构示意图

到此这篇关于springcloud中的ribbon进行服务调用的文章就介绍到这了,更多相关springcloud ribbon服务调用内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!

本文发布于:2023-04-04 13:31:44,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/zuowen/a580079e3f94de02e3d14f948c634c6a.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

本文word下载地址:聊聊SpringCloud中的Ribbon进行服务调用的问题.doc

本文 PDF 下载地址:聊聊SpringCloud中的Ribbon进行服务调用的问题.pdf

相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图