<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【送10本書】深入理解Spring Cloud與實戰(zhàn)

          共 9221字,需瀏覽 19分鐘

           ·

          2021-03-09 16:30

          無論是Dubbo,還是Spring Cloud,大家可能都不會感到陌生。
          那什么是Dubbo Spring Cloud呢?使用Dubbo Spring Cloud可以實現(xiàn)什么目的?基于其實現(xiàn)的路由和負載均衡又是怎樣的呢?
          本文就帶大家來一探究竟!
          以下節(jié)選自深入理解Spring Cloud與實戰(zhàn)》一書。
          01
          什么是Dubbo Spring Cloud
          Dubbo Spring Cloud是Spring Cloud Alibaba項目內(nèi)部提供的一個可以使用Spring Cloud客戶端RestTemplate或OpenFeign調用Dubbo服務的模塊。
          Apache Dubbo和Spring Cloud是兩套架構完全不同的開發(fā)框架。
          在講解Dubbo Spring Cloud之前,我們先來看這個問題:Apache Dubbo暴露的服務都是接口級別的,而Spring Cloud暴露的服務是應用級別的,RestTemplate或OpenFeign發(fā)起調用服務都會有對應的URL Path、Query Parameter、Header等內(nèi)容(這是HTTP協(xié)議調用),如何讓這些內(nèi)容關聯(lián)Dubbo服務呢?
          針對上述問題,Dubbo Spring Cloud實現(xiàn)了以應用為粒度的注冊機制,每個Dubbo應用注冊到注冊中心后有且僅有一個服務。那么原先以接口為維度的那些接口信息去哪里了?
          Dubbo Spring Cloud 定義了 DubboMetadataService 元數(shù)據(jù)服務的概念。這是一個專門用于存儲 Dubbo 服務的元數(shù)據(jù)接口。DubboMetadataService 接口定義如下:
          public interface DubboMetadataService {
          // 最核心的接口,用于獲取 Dubbo 服務的 Rest 元數(shù)據(jù) String getServiceRestMetadata();
          // 返回所有 Dubbo 服務的 ServiceKey 集合 Set<String> getAllServiceKeys();
          // 返回所有對外暴露的Dubbo服務。key為ServiceKey,value為URL的json格式 Map<String, String> getAllExportedURLs();
          // 基于接口名分組及版本獲取到 URL 的 json 格式 String getExportedURLs(String serviceInterface, String group, String version);
          }
          核心方法 getServiceRestMetadata 獲取 Dubbo 服務的 Rest 元數(shù)據(jù)是指:當一個 Dubbo 服務同時也被 SpringMVC 相關注解修飾時,SpringMVC 相關注解修飾的內(nèi)容就是這些 Rest 元數(shù)據(jù)。這些 Rest 元數(shù)據(jù)由 RestMethodMetadata 類修飾,比如,這個 Dubbo 服務 RestService 接口,其定義如下:
          @Service@RestControllerpublic class SpringRestService implements RestService {
              @Override    @GetMapping("/param")    public String param(@RequestParam String param) {        return param;    }
          }
          RestService服務對應的Rest元數(shù)據(jù)內(nèi)容如下:
          RestMethodMetadata{method=MethodMetadata{name='param'returnType='java.lang.String'params=[MethodParameterMetadata{index=0name='param', type='java.lang.String'}], method=public java.lang.String com.alibaba.cloud.dubbo.service.SpringRestService.param(java.lang.String)}, request=RequestMetadata{method='GET', path='/param'params={param=[{param}]}, headers=[], consumes=[], produces=[]}, urlIndex=null, bodyIndex=nullheaderMapIndex=null, queryMapIndex=null, queryMapEncoded=falsereturnType='java.lang.String', bodyType='null', indexToName={0=[param]}, formParams=[], indexToEncoded={}}
          除了SpringMVC相關注解,當Dubbo服務自身也暴露Rest協(xié)議的時候,這些JAX-RS相關注解修飾的內(nèi)容也會被解析成Rest元數(shù)據(jù)。比如,這個Dubbo服務RestService接口的代碼如下:
          @Service(protocol = { "dubbo""rest" })@Path("/")public class StandardRestService implements RestService {
              @Override    @Path("param")    @GET    public String param(@QueryParam("param") String param) {        return param;    }
          }
          RestService服務對應的Rest元數(shù)據(jù)內(nèi)容如下:
          RestMethodMetadata{method=MethodMetadata{name='param', returnType='java.lang.String', params=[MethodParameterMetadata{index=0, name='param', type='java.lang.String'}], method=public java.lang.String com.alibaba.cloud.dubbo.service.SpringRestService.param(java.lang.String)}, request=RequestMetadata{method='GET', path='/param', params={param=[{param}]}, headers=[], consumes=[], produces=[]}, urlIndex=null, bodyIndex=null, headerMapIndex=null, queryMapIndex=null, queryMapEncoded=false, returnType='java.lang.String', bodyType='null', indexToName={0=[param]}, formParams=[], indexToEncoded={}}
          從這兩個例子的RestMethodMetadata內(nèi)容可看出,SpringMVC和JAX-RS的Rest元數(shù)據(jù)是一致的。
          Rest元數(shù)據(jù)出現(xiàn)的意義是為了匹配RestTemplate或OpenFeign的HTTP協(xié)議內(nèi)容,匹配HTTP協(xié)議內(nèi)容的目的是為了讓HTTP協(xié)議內(nèi)容關聯(lián)上Dubbo服務。
          使用RestTemplate或OpenFeign調用Dubbo服務會經(jīng)歷以下過程:
          (1)根據(jù)服務名得到注冊中心的Dubbo服務DubboMetadataService。
          (2)使用DubboMetadataService里提供的getServiceRestMetadata方法獲取要使用的Dubbo服務和對應的Rest元數(shù)據(jù)。
          (3)基于Dubbo服務和Rest元數(shù)據(jù)構造GenericService。
          (4)服務調用過程中使用GenericService發(fā)起泛化調用。
          02
          調用Dubbo服務的步驟
          下面是使用Dubbo Spring Cloud調用Dubbo服務的開發(fā)步驟
          (1)引入spring-cloud-starter-dubbo依賴。
          <dependency>    <groupId>com.alibaba.cloud</groupId>    <artifactId>spring-cloud-starter-dubbo</artifactId></dependency>
          加上依賴后,將注冊中心改成 spring-cloud 注冊中心:
          dubbo.registry.address=spring-cloud://localhost
          (2)Provider 端接口加上 SpringMVC 相關注解或使用JAX-RS暴露Rest協(xié)議。
          ① 加上 SpringMVC 相關注解。
          @Service(version = "1.0.0")@RestControllerpublic class SpringRestService implements RestService {    @Override    @GetMapping("/param")    public String param(@RequestParam String param) {        log("/param", param);        return param;    }    @Override    @PostMapping("/params")    public String params(@RequestParam int a, @RequestParam String b) {        log("/params", a + b);        return a + b;    }}
          ② 使用 JAX-RS 暴露 Rest 協(xié)議。
          配置文件暴露 rest 協(xié)議:
          dubbo.protocols.rest.name=restdubbo.protocols.rest.port=9090dubbo.protocols.rest.server=netty
          接口使用 JAX-RS 注解修飾:
          @Service(version = "1.0.0", protocol = { "dubbo""rest" })@Path("/")public class StandardRestService implements RestService {    @Override    @Path("param")    @GET    public String param(@QueryParam("param") String param) {        log("/param", param);        return param;    }    @Override    @Path("params")    @POST    public String params(@QueryParam("a") int a, @QueryParam("b") String b) {        log("/params", a + b);        return a + b;    }}
          (3)Consumer 客戶端加上 @DubboTransported 注解。
          RestTemplate 和 OpenFeign 客戶端都支持 @DubboTransported 注解。
          RestTemplate 的使用方式如下:
          @Bean@LoadBalanced@DubboTransportedpublic RestTemplate restTemplate() {    return new RestTemplate();}
          OpenFeign 的使用方式如下:
          @FeignClient("nacos-provider-lb")@DubboTransported(protocol = "dubbo")public interface DubboFeignRestService {
              @GetMapping("/param")    String param(@RequestParam("param") String param);
              @PostMapping("/params") String params(@RequestParam("b") String paramB, @RequestParam("a") int paramA);
          }
          (4)使用 RestTemplate 或 OpenFeign 調用 Dubbo 服務。
          使用 RestTemplate調用的方式如下:
          restTemplate.getForEntity(“http://dubbo-provider-service/param?param=deepinspringcloud”, String.class);
          使用 OpenFeign調用的方式如下:
          dubboFeignRestService.param(“deepinspringcloud”);

          03
          再談路由和負載均衡

          基于Netflix Ribbon的Spring Cloud 負載均衡設計了以下兩個核心接口:

          • 路由對應的ILoadBalancer 接口,獲取服務的 Server 實例列表。

          • 負載均衡對應的 IRule 接口,從服務的 Server 實例列表中根據(jù)負載均衡算法獲取一個實例。

          Spring Cloud應用的流量控制本質上就是對 Server 列表的控制:
          • 自定義 ILoadBalancer 接口,重寫獲取 Server 列表的邏輯(找出與當前請求匹配的 Server 列表)。

          • 自定義 IRule 接口,從所有的 Server 列表里找出與當前請求匹配的 Server。

          很明顯,第一種基于 ILoadBalancer 的方式更加合理。
          我們來看 Dubbo 路由 Router 的實現(xiàn)。
          Route 方法會從 Invoker 列表中過濾一批 Invoker,得到另一批 Invoker 列表:
          public interface Router extends Comparable<Router{
          <T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException;
          }
          然后 Router 在RouterChain 里被使用:
          public class RouterChain<T{
              public List<Invoker<T>> route(URL url, Invocation invocation) {        List<Invoker<T>> finalInvokers = invokers;        for (Router router : routers) {            finalInvokers = router.route(finalInvokers, url, invocation);        }        return finalInvokers;    }
          }
          RouterChain中的Router列表可以隨意被添加,開發(fā)者可以基于SPI添加各式各樣的Router。
          筆者認為 Duboo 在路由側的實現(xiàn)更加優(yōu)雅。在Spring Cloud的設計中,Ribbon的路由設計與Request(流量)請求信息是解耦的,而 Dubbo 的 Router與Invocation(流量)是綁定的,這意味著路由過程可以直接基于流量特征進行動態(tài)操作,無須引入類似 ThreadLocal 的方式來傳遞流量特征。
          另外,我們提到過Spring Cloud默認提供的ZoneAvoidanceRule這個IRule負載均衡策略,它內(nèi)部會依賴ServerStats去根據(jù)Server狀態(tài)摘除異常節(jié)點。
          Spring Cloud 提供的其他 IRule 負載均衡策略并沒有這個能力,如果想在自定義的 IRule 負載均衡也擁有摘除異常節(jié)點的能力,需要在代碼里配合 ServerStats 使用。
          ▊ 更多相關內(nèi)容請看《深入理解Spring Cloud與實戰(zhàn)》一書!



          ▼點擊閱讀原文,獲取本書詳情~
          瀏覽 15
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  超碰97人妻 | 一级黄色片免费观看 | 欧美后门菊门交3p、 | 成人天堂一级婬片A片AAA软件 | 青青草原免费在线视频 |