国产成人精品18p,天天干成人网,无码专区狠狠躁天天躁,美女脱精光隐私扒开免费观看

Spring Cloud調用Ribbon的步驟

發(fā)布時(shí)間:2021-07-05 18:40 來(lái)源:腳本之家 閱讀:0 作者:初入職場(chǎng)小碼農 欄目: 開(kāi)發(fā)技術(shù)

目錄

      一、簡(jiǎn)介

      1. 是什么

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

      2. 負載均衡

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

      2.1 集中式LB

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

      2.2 進(jìn)程內LB

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

      二、實(shí)驗

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

      1. RestTemplate

      • 通過(guò)RestTemplate,可以實(shí)現HttpClient的功能,只需要給它提供一個(gè)url及返回類(lèi)型,即可實(shí)現遠程方法調用。

      1.1 加入到IOC容器

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

      @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 類(lèi)型
          log.info("Order 查詢(xún) Payment,id:" + id);
          return result;
        }
      }
      

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

        @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("查詢(xún)成功:" + id);
            return entity.getBody();
          } else {
            log.info("查詢(xún)失?。? + id);
            return new CommonResult<>(CommonResult.FAIlURE, "查詢(xún)失敗");
          }
        }
      

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

      1.3 配置文件

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

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

      2. LoadBalancer

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

      2.1 修改負載均衡算法

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

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

      在主啟動(dòng)類(lèi)上,標識一下服務(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ù)名稱(chēng)
        ribbon:
          NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule  # 算法選擇
      

      3. 負載均衡算法源碼

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

      • RoundRobinRule父類(lèi)為AbstractLoadBalancerRule,AbstractLoadBalancerRule實(shí)現了接口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í)現。

      public abstract class AbstractLoadBalancerRule implements IRule, IClientConfigAware {
        private ILoadBalancer lb;  // ILoadBalancer接口,主要的功能就是獲取當前服務(wù)器的狀態(tài)、數量等,為負載均衡算法提供計算的參數
      
        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è)計數器,實(shí)現了輪詢(xún)

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

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

      public Server choose(ILoadBalancer lb, Object key) {
          if (lb == null) {  // 如果沒(méi)有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();  // 通過(guò)LB獲取目前所有可獲取的服務(wù)器
                List<Server> allServers = lb.getAllServers();  // 獲取實(shí)際上的所有服務(wù)器
                int upCount = reachableServers.size();  // 獲取目前可獲得的服務(wù)器數量
                int serverCount = allServers.size();  // 所有服務(wù)器的數量,這是取余的除數
                if (upCount != 0 && serverCount != 0) {  // 如果目前有服務(wù)器且服務(wù)器可用
                  int nextServerIndex = this.incrementAndGetModulo(serverCount);  // 最關(guān)鍵的選擇算法,將目前的的服務(wù)器數量放進(jìn)去,返回一個(gè)選擇的號碼
                  server = (Server)allServers.get(nextServerIndex);   // 根據下標將服務(wù)器取出來(lái)
                  if (server == null) {  // 如果取出來(lái)為空,表示目前不可用,則進(jìn)入下一個(gè)循環(huán)
                    Thread.yield(); 
                  } else {
                    if (server.isAlive() && server.isReadyToServe()) {  // 如果該服務(wù)器活著(zhù)且可以被使用,則直接將其返回
                      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ō),就是將目前的計數器+1取余,獲取一個(gè)下標,并返回。為了避免高并發(fā)的危險,采用CAS的方法進(jìn)行設置。

        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,如果成功就返回,失敗就再來(lái)
      
          return next;
        }
      

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

      免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自互聯(lián)網(wǎng)轉載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權請聯(lián)系QQ:712375056 進(jìn)行舉報,并提供相關(guān)證據,一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容。

      专干老肥熟女视频网站300部| 亚洲AVAV天堂AV在线网毛片| 丰满岳乱妇在线观看中字无码| 色狠狠色婷婷丁香五月| 老师办公室被吃奶好爽在线观看| 国产精品XXXX国产喷水|