欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring Cloud調(diào)用Ribbon的步驟

 更新時(shí)間:2021年05月24日 11:52:42   作者:初入職場(chǎng)小碼農(nóng)  
Ribbon是Netflix發(fā)布的開源項(xiàng)目,主要功能是提供客戶端的軟件負(fù)載均衡算法和服務(wù)調(diào)用。本文將講述Spring Cloud調(diào)用Ribbon的方法

一、簡(jiǎn)介

1. 是什么

  • Spring Cloud Ribbon是基于Netflix Ribbon實(shí)現(xiàn)的一套客戶端負(fù)載均衡的工具。
  • 簡(jiǎn)單的說(shuō),Ribbon是Netflix發(fā)布的開源項(xiàng)目,主要功能是提供客戶端的軟件負(fù)載均衡算法和服務(wù)調(diào)用。
  • 官方文檔
  • 目前已進(jìn)入維護(hù)狀態(tài),以后可以通過(guò)Open Feign作為替代方案
  • 負(fù)載均衡+RestTemplate,實(shí)現(xiàn)負(fù)載均衡調(diào)用

2. 負(fù)載均衡

  • 負(fù)載均衡(Load Balance,LB),即將用戶的請(qǐng)求平攤到多個(gè)服務(wù)上,從而達(dá)到系統(tǒng)的高可用(HA)
  • 負(fù)載均衡分為兩種方案:集中式LB、進(jìn)程內(nèi)LB

2.1 集中式LB

  • 即服務(wù)方和消費(fèi)方之間使用獨(dú)立的LB設(shè)施,由該設(shè)備負(fù)責(zé)把訪問(wèn)請(qǐng)求通過(guò)某種策略轉(zhuǎn)發(fā)至服務(wù)提供方。
  • 比如說(shuō)Nginx、Gateway、zuul等

2.2 進(jìn)程內(nèi)LB

  • 負(fù)載均衡的算法集成到消費(fèi)方,消費(fèi)方在注冊(cè)中心中獲取可用地址,然后通過(guò)LB算法選擇出一個(gè)合適的服務(wù)器。
  • Ribbon就屬于進(jìn)程內(nèi)LB,它只是一個(gè)類庫(kù),集成于消費(fèi)方進(jìn)程,消費(fèi)方通過(guò)它來(lái)獲取到服務(wù)方提供的地址。

二、實(shí)驗(yàn)

Ribbon集成在spring-cloud-starter-netflix-eureka-client中,可以參考eureka的使用。在此基礎(chǔ)上簡(jiǎn)單修改一下,就可以完成服務(wù)調(diào)用及負(fù)載均衡

1. RestTemplate

  • 官網(wǎng)
  • 通過(guò)RestTemplate,可以實(shí)現(xiàn)HttpClient的功能,只需要給它提供一個(gè)url及返回類型,即可實(shí)現(xiàn)遠(yuǎn)程方法調(diào)用。

1.1 加入到IOC容器

首先,將其加入到IOC容器中。@LoadBalanced表示開啟負(fù)載均衡。

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

1.2 RestTemplate 遠(yuǎn)程調(diào)用

@Slf4j
@RestController
@RequestMapping("/order")
public class OrderController {
  @Autowired
  RestTemplate restTemplate;  // 在ioc容器中獲取
  @Value("${payment.url}")
  String paymentUrl;  // 遠(yuǎn)程調(diào)用的URL,保存在配置文件中,解耦

  @GetMapping("/payment/get/{id}")
  public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id) {
    CommonResult<Payment> result = restTemplate.getForObject(paymentUrl + "/payment/get/" + id, CommonResult.class);  // get方法調(diào)用,并且返回封裝成 CommonResult 類型
    log.info("Order 查詢 Payment,id:" + id);
    return result;
  }
}

也可以使用getForEntity()方法,獲取整個(gè)響應(yīng),自己在響應(yīng)中獲取想要的內(nèi)容。

  @GetMapping("/payment/getEntity/{id}")
  public CommonResult<Payment> getPaymentEntityById(@PathVariable("id") Long id) {
    ResponseEntity<CommonResult> entity = restTemplate.getForEntity(paymentUrl + "/payment/get/" + id, CommonResult.class);
    log.info("獲取到的信息是:" + entity.toString());
    log.info("獲取到的StatusCode是:" + entity.getStatusCode());
    log.info("獲取到的StatusCodeValue是:" + entity.getStatusCodeValue());
    log.info("獲取到的Headers是:" + entity.getHeaders());

    if (entity.getStatusCode().is2xxSuccessful()) {
      log.info("查詢成功:" + id);
      return entity.getBody();
    } else {
      log.info("查詢失?。? + id);
      return new CommonResult<>(CommonResult.FAIlURE, "查詢失敗");
    }
  }

如果使用post方法,就將get改成post就好了。

1.3 配置文件

url,可以寫具體的地址,表示直接調(diào)用該地址;也可以寫在eureka的服務(wù)名,首先在eureka中獲取該服務(wù)的所有地址,再通過(guò)LB選擇一個(gè)。

payment:
  url: "http://CLOUD-PAYMENT-SERVICE"

2. LoadBalancer

上面通過(guò)@LoadBalanced開啟了負(fù)載均衡。默認(rèn)使用輪詢算法,也可以修改成其他算法。

Class 算法
com.netflix.loadbalancer.RoundRobinRule 輪詢,默認(rèn)算法
com.netflix.loadbalancer.RandomRule 隨機(jī)算法,通過(guò)產(chǎn)生隨機(jī)數(shù)選擇服務(wù)器
com.netflix.loadbalancer.RetryRule 先按照RoundRobinRule的策略獲取服務(wù),如果獲取服務(wù)失敗則在指定時(shí)間內(nèi)會(huì)進(jìn)行重試,獲取可用的服務(wù)
WeightedResponseTimeRule 對(duì)RoundRobinRule的擴(kuò)展,響應(yīng)速度越快的實(shí)例選擇權(quán)重越大,越容易被選擇
BestAvailableRule 會(huì)先過(guò)濾掉由于多次訪問(wèn)故障而處于斷路器跳閘狀態(tài)的服務(wù),然后選擇一個(gè)并發(fā)量最小的服務(wù)
AvailabilityFilteringRule 先過(guò)濾掉故障實(shí)例,再選擇并發(fā)較小的實(shí)例
ZoneAvoidanceRule 默認(rèn)規(guī)則,復(fù)合判斷server所在區(qū)域的性能和server的可用性選擇服務(wù)器

2.1 修改負(fù)載均衡算法

如果想讓該算法只針對(duì)某個(gè)服務(wù),則不能將其放在ComponentScan夠得到的地方,否則會(huì)修改所有服務(wù)的負(fù)載均衡算法。因此,最好在外面再新建一個(gè)package,用來(lái)放這個(gè)LB

@Configuration
public class MyRule {
  @Bean
  public IRule rule() {
    return new RandomRule();
  }
}

在主啟動(dòng)類上,標(biāo)識(shí)一下服務(wù)與算法直接的映射關(guān)系

@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE", configuration = MyRule.class)
public class OrderApplication80 {
  public static void main(String[] args) {
    SpringApplication.run(OrderApplication80.class, args);
  }
}

如果嫌這種方法麻煩,也可以使用配置文件的方法

CLOUD-PAYMENT-SERVICE:  # 服務(wù)名稱
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule  # 算法選擇

3. 負(fù)載均衡算法源碼

以默認(rèn)的RoundRobinRule作為閱讀的源碼,其他的源碼基本上很類似,只是修改的選擇服務(wù)器的代碼。

  • RoundRobinRule父類為AbstractLoadBalancerRule,AbstractLoadBalancerRule實(shí)現(xiàn)了接口IRule

3.1 IRule

public interface IRule {
  Server choose(Object var1);  // 選擇服務(wù)器,最重要的方法

  void setLoadBalancer(ILoadBalancer var1);

  ILoadBalancer getLoadBalancer();
}

3.2 AbstractLoadBalancerRule

基本沒(méi)什么作用,只是將公共的部分提取了出來(lái)進(jìn)行實(shí)現(xiàn)。

public abstract class AbstractLoadBalancerRule implements IRule, IClientConfigAware {
  private ILoadBalancer lb;  // ILoadBalancer接口,主要的功能就是獲取當(dāng)前服務(wù)器的狀態(tài)、數(shù)量等,為負(fù)載均衡算法提供計(jì)算的參數(shù)

  public AbstractLoadBalancerRule() {
  }

  public void setLoadBalancer(ILoadBalancer lb) {
    this.lb = lb;
  }

  public ILoadBalancer getLoadBalancer() {
    return this.lb;
  }
}

3.3 RoundRobinRule

簡(jiǎn)單來(lái)說(shuō),就是通過(guò)一個(gè)計(jì)數(shù)器,實(shí)現(xiàn)了輪詢

public class RoundRobinRule extends AbstractLoadBalancerRule {
  private AtomicInteger nextServerCyclicCounter;  // 原子類,用來(lái)保存一個(gè)計(jì)數(shù),記錄現(xiàn)在輪詢到哪了
  private static final boolean AVAILABLE_ONLY_SERVERS = true;
  private static final boolean ALL_SERVERS = false;
  private static Logger log = LoggerFactory.getLogger(RoundRobinRule.class);

  public RoundRobinRule() {
    this.nextServerCyclicCounter = new AtomicInteger(0);  // 初始化
  }

  public RoundRobinRule(ILoadBalancer lb) {  // 設(shè)置LoadBalancer
    this();
    this.setLoadBalancer(lb);
  }

  public Server choose(ILoadBalancer lb, Object key) {  // 最重要的方法,選擇服務(wù)器并返回
  // 下面貼出來(lái)
  }
 
  private int incrementAndGetModulo(int modulo) {  // 對(duì)計(jì)數(shù)器進(jìn)行修改,并返回一個(gè)選擇值,是輪詢算法的實(shí)現(xiàn)
  // 下面貼出來(lái)
  }

  public Server choose(Object key) {   // 接口的方法,在該類中調(diào)用了另一個(gè)方法實(shí)現(xiàn)
    return this.choose(this.getLoadBalancer(), key);
  }

  public void initWithNiwsConfig(IClientConfig clientConfig) {}
}

簡(jiǎn)單來(lái)說(shuō),該方法就是根據(jù)目前的狀態(tài),選擇一個(gè)服務(wù)器返回。

public Server choose(ILoadBalancer lb, Object key) {
    if (lb == null) {  // 如果沒(méi)有LoadBalancer,那就不白費(fèi)功夫了
      log.warn("no load balancer");
      return null;
    } else {
      Server server = null;
      int count = 0;

      while(true) {  
        if (server == null && count++ < 10) {  // 嘗試十次,如果還找不到server就放棄了
          List<Server> reachableServers = lb.getReachableServers();  // 通過(guò)LB獲取目前所有可獲取的服務(wù)器
          List<Server> allServers = lb.getAllServers();  // 獲取實(shí)際上的所有服務(wù)器
          int upCount = reachableServers.size();  // 獲取目前可獲得的服務(wù)器數(shù)量
          int serverCount = allServers.size();  // 所有服務(wù)器的數(shù)量,這是取余的除數(shù)
          if (upCount != 0 && serverCount != 0) {  // 如果目前有服務(wù)器且服務(wù)器可用
            int nextServerIndex = this.incrementAndGetModulo(serverCount);  // 最關(guān)鍵的選擇算法,將目前的的服務(wù)器數(shù)量放進(jìn)去,返回一個(gè)選擇的號(hào)碼
            server = (Server)allServers.get(nextServerIndex);   // 根據(jù)下標(biāo)將服務(wù)器取出來(lái)
            if (server == null) {  // 如果取出來(lái)為空,表示目前不可用,則進(jìn)入下一個(gè)循環(huán)
              Thread.yield(); 
            } else {
              if (server.isAlive() && server.isReadyToServe()) {  // 如果該服務(wù)器活著且可以被使用,則直接將其返回
                return server;
              }

              server = null;
            }
            continue;
          }

          log.warn("No up servers available from load balancer: " + lb);
          return null;
        }

        if (count >= 10) {
          log.warn("No available alive servers after 10 tries from load balancer: " + lb);
        }

        return server;
      }
    }
  }

簡(jiǎn)單來(lái)說(shuō),就是將目前的計(jì)數(shù)器+1取余,獲取一個(gè)下標(biāo),并返回。為了避免高并發(fā)的危險(xiǎn),采用CAS的方法進(jìn)行設(shè)置。

  private int incrementAndGetModulo(int modulo) {
    int current;
    int next;
    do {
      current = this.nextServerCyclicCounter.get();  // 獲取當(dāng)前值
      next = (current + 1) % modulo;  // +1取余
    } while(!this.nextServerCyclicCounter.compareAndSet(current, next));  // CAS,如果成功就返回,失敗就再來(lái)

    return next;
  }

以上就是Spring Cloud調(diào)用Ribbon的步驟的詳細(xì)內(nèi)容,更多關(guān)于Spring Cloud調(diào)用Ribbon的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • java中的Object類的toSpring()方法

    java中的Object類的toSpring()方法

    這篇文章主要介紹了java中的Object類的toSpring()方法,Object是類層次結(jié)構(gòu)的根,每個(gè)類都可以將Object作為超類。所有類都直接或者間接的繼承自該類,下文相關(guān)資料,需要的朋友可以參考下
    2022-04-04
  • java金錢處理方法實(shí)例詳解

    java金錢處理方法實(shí)例詳解

    這篇文章主要介紹了java金錢處理方法實(shí)例詳解的相關(guān)資料,這里提供實(shí)現(xiàn)方法分轉(zhuǎn)化成元的實(shí)現(xiàn)方法,需要的朋友可以參考下
    2017-08-08
  • Arrays.asList方法總結(jié)

    Arrays.asList方法總結(jié)

    本文主要對(duì)Arrays.asList方法進(jìn)行總結(jié)。具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧
    2017-02-02
  • SpringBoot MockMvc單元測(cè)試的示例代碼

    SpringBoot MockMvc單元測(cè)試的示例代碼

    這篇文章主要介紹了SpringBoot MockMvc單元測(cè)試的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-11-11
  • idea運(yùn)行vue項(xiàng)目設(shè)置自定義瀏覽器方式

    idea運(yùn)行vue項(xiàng)目設(shè)置自定義瀏覽器方式

    這篇文章主要介紹了idea運(yùn)行vue項(xiàng)目設(shè)置自定義瀏覽器方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • 一文帶你搞懂Java8的LocalDateTime

    一文帶你搞懂Java8的LocalDateTime

    LocalDateTime?是Java8中新加入的日期時(shí)間類,現(xiàn)在都?Java20?了,不會(huì)還有人沒(méi)用過(guò)?LocalDateTime?吧?今天給大家演示一下?LocalDateTime?的常用方法
    2023-04-04
  • 史上最全的IDEA快捷鍵總結(jié)

    史上最全的IDEA快捷鍵總結(jié)

    這篇文章主要介紹了史上最全的IDEA快捷鍵總結(jié),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-01-01
  • Java Semaphore信號(hào)量使用分析講解

    Java Semaphore信號(hào)量使用分析講解

    Semaphore實(shí)際上是一種共享鎖,因?yàn)樗试S多個(gè)線程并發(fā)獲取共享的資源,在Semaphore對(duì)象創(chuàng)建時(shí)必須設(shè)置可用令牌的初始數(shù)量permits,用于控制并發(fā)時(shí)同時(shí)獲取資源權(quán)限的線程數(shù)量,這篇文章主要介紹了Java中的Semaphore如何使用,需要的朋友可以參考下
    2022-12-12
  • Java中new關(guān)鍵字和newInstance方法的區(qū)別分享

    Java中new關(guān)鍵字和newInstance方法的區(qū)別分享

    在初始化一個(gè)類,生成一個(gè)實(shí)例的時(shí)候,newInstance()方法和new關(guān)鍵字除了一個(gè)是方法一個(gè)是關(guān)鍵字外,最主要的區(qū)別是創(chuàng)建對(duì)象的方式不同
    2013-07-07
  • mybatis 插件: 打印 sql 及其執(zhí)行時(shí)間實(shí)現(xiàn)方法

    mybatis 插件: 打印 sql 及其執(zhí)行時(shí)間實(shí)現(xiàn)方法

    下面小編就為大家?guī)?lái)一篇mybatis 插件: 打印 sql 及其執(zhí)行時(shí)間實(shí)現(xiàn)方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-06-06

最新評(píng)論