中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

SpringCloud中Ribbon怎么調用

發布時間:2022-02-24 17:20:57 來源:億速云 閱讀:138 作者:iii 欄目:開發技術

這篇文章主要介紹“SpringCloud中Ribbon怎么調用”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“SpringCloud中Ribbon怎么調用”文章能幫助大家解決問題。

    一、簡介

    1. 是什么

    • Spring Cloud Ribbon是基于Netflix Ribbon實現的一套客戶端負載均衡的工具。

    • 簡單的說,Ribbon是Netflix發布的開源項目,主要功能是提供客戶端的軟件負載均衡算法和服務調用。

    • 官方文檔

    • 目前已進入維護狀態,以后可以通過Open Feign作為替代方案

    • 負載均衡+RestTemplate,實現負載均衡調用

    2. 負載均衡

    • 負載均衡(Load Balance,LB),即將用戶的請求平攤到多個服務上,從而達到系統的高可用(HA)

    • 負載均衡分為兩種方案:集中式LB、進程內LB

    2.1 集中式LB
    • 即服務方和消費方之間使用獨立的LB設施,由該設備負責把訪問請求通過某種策略轉發至服務提供方。

    • 比如說Nginx、Gateway、zuul等

    2.2 進程內LB
    • 負載均衡的算法集成到消費方,消費方在注冊中心中獲取可用地址,然后通過LB算法選擇出一個合適的服務器

    • Ribbon就屬于進程內LB,它只是一個類庫,集成于消費方進程,消費方通過它來獲取到服務方提供的地址。

    二、實驗

    Ribbon集成在spring-cloud-starter-netflix-eureka-client中,可以參考eureka的使用。在此基礎上簡單修改一下,就可以完成服務調用及負載均衡

    1. RestTemplate

    • 官網

    • 通過RestTemplate,可以實現HttpClient的功能,只需要給它提供一個url及返回類型,即可實現遠程方法調用。

    1.1 加入到IOC容器

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

    @Configuration
    public class ApplicationContextConfig {
      @Bean
      @LoadBalanced
      public RestTemplate restTemplate() {
        return new RestTemplate();
      }
    }
    1.2 RestTemplate 遠程調用
    @Slf4j
    @RestController
    @RequestMapping("/order")
    public class OrderController {
      @Autowired
      RestTemplate restTemplate;  // 在ioc容器中獲取
      @Value("${payment.url}")
      String paymentUrl;  // 遠程調用的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方法調用,并且返回封裝成 CommonResult 類型
        log.info("Order 查詢 Payment,id:" + id);
        return result;
      }
    }

    也可以使用getForEntity()方法,獲取整個響應,自己在響應中獲取想要的內容。

      @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,可以寫具體的地址,表示直接調用該地址;也可以寫在eureka的服務名,首先在eureka中獲取該服務的所有地址,再通過LB選擇一個。

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

    2. LoadBalancer

    上面通過@LoadBalanced開啟了負載均衡。默認使用輪詢算法,也可以修改成其他算法。

    Class算法
    com.netflix.loadbalancer.RoundRobinRule輪詢,默認算法
    com.netflix.loadbalancer.RandomRule隨機算法,通過產生隨機數選擇服務器
    com.netflix.loadbalancer.RetryRule先按照RoundRobinRule的策略獲取服務,如果獲取服務失敗則在指定時間內會進行重試,獲取可用的服務
    WeightedResponseTimeRule對RoundRobinRule的擴展,響應速度越快的實例選擇權重越大,越容易被選擇
    BestAvailableRule會先過濾掉由于多次訪問故障而處于斷路器跳閘狀態的服務,然后選擇一個并發量最小的服務
    AvailabilityFilteringRule先過濾掉故障實例,再選擇并發較小的實例
    ZoneAvoidanceRule默認規則,復合判斷server所在區域的性能和server的可用性選擇服務器
    2.1 修改負載均衡算法

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

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

    在主啟動類上,標識一下服務與算法直接的映射關系

    @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:  # 服務名稱
      ribbon:
        NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule  # 算法選擇

    3. 負載均衡算法源碼

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

    • RoundRobinRule父類為AbstractLoadBalancerRule,AbstractLoadBalancerRule實現了接口IRule

    3.1 IRule
    public interface IRule {
      Server choose(Object var1);  // 選擇服務器,最重要的方法
    
      void setLoadBalancer(ILoadBalancer var1);
    
      ILoadBalancer getLoadBalancer();
    }
    3.2 AbstractLoadBalancerRule

    基本沒什么作用,只是將公共的部分提取了出來進行實現。

    public abstract class AbstractLoadBalancerRule implements IRule, IClientConfigAware {
      private ILoadBalancer lb;  // ILoadBalancer接口,主要的功能就是獲取當前服務器的狀態、數量等,為負載均衡算法提供計算的參數
    
      public AbstractLoadBalancerRule() {
      }
    
      public void setLoadBalancer(ILoadBalancer lb) {
        this.lb = lb;
      }
    
      public ILoadBalancer getLoadBalancer() {
        return this.lb;
      }
    }
    3.3 RoundRobinRule

    簡單來說,就是通過一個計數器,實現了輪詢

    public class RoundRobinRule extends AbstractLoadBalancerRule {
      private AtomicInteger nextServerCyclicCounter;  // 原子類,用來保存一個計數,記錄現在輪詢到哪了
      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) {  // 設置LoadBalancer
        this();
        this.setLoadBalancer(lb);
      }
    
      public Server choose(ILoadBalancer lb, Object key) {  // 最重要的方法,選擇服務器并返回
      // 下面貼出來
      }
     
      private int incrementAndGetModulo(int modulo) {  // 對計數器進行修改,并返回一個選擇值,是輪詢算法的實現
      // 下面貼出來
      }
    
      public Server choose(Object key) {   // 接口的方法,在該類中調用了另一個方法實現
        return this.choose(this.getLoadBalancer(), key);
      }
    
      public void initWithNiwsConfig(IClientConfig clientConfig) {}
    }

    簡單來說,該方法就是根據目前的狀態,選擇一個服務器返回。

    public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {  // 如果沒有LoadBalancer,那就不白費功夫了
          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();  // 通過LB獲取目前所有可獲取的服務器
              List<Server> allServers = lb.getAllServers();  // 獲取實際上的所有服務器
              int upCount = reachableServers.size();  // 獲取目前可獲得的服務器數量
              int serverCount = allServers.size();  // 所有服務器的數量,這是取余的除數
              if (upCount != 0 && serverCount != 0) {  // 如果目前有服務器且服務器可用
                int nextServerIndex = this.incrementAndGetModulo(serverCount);  // 最關鍵的選擇算法,將目前的的服務器數量放進去,返回一個選擇的號碼
                server = (Server)allServers.get(nextServerIndex);   // 根據下標將服務器取出來
                if (server == null) {  // 如果取出來為空,表示目前不可用,則進入下一個循環
                  Thread.yield(); 
                } else {
                  if (server.isAlive() && server.isReadyToServe()) {  // 如果該服務器活著且可以被使用,則直接將其返回
                    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;
          }
        }
      }

    簡單來說,就是將目前的計數器+1取余,獲取一個下標,并返回。為了避免高并發的危險,采用CAS的方法進行設置。

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

    關于“SpringCloud中Ribbon怎么調用”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    随州市| 大港区| 湾仔区| 苍梧县| 磐安县| 长子县| 万荣县| 福海县| 两当县| 盈江县| 墨竹工卡县| 仁布县| 上高县| 保定市| 贺州市| 饶河县| 微博| 固安县| 长顺县| 金平| 逊克县| 上饶县| 麻城市| 疏附县| 台湾省| 青铜峡市| 通化市| 平陆县| 锡林浩特市| 望奎县| 明水县| 咸阳市| 灵宝市| 崇明县| 行唐县| 安康市| 宁波市| 昭苏县| 共和县| 沂源县| 嫩江县|