1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        【送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)的路由和負(fù)載均衡又是怎樣的呢?
        本文就帶大家來一探究竟!
        以下節(jié)選自深入理解Spring Cloud與實戰(zhàn)》一書。
        01
        什么是Dubbo Spring Cloud
        Dubbo Spring Cloud是Spring Cloud Alibaba項目內(nèi)部提供的一個可以使用Spring Cloud客戶端RestTemplate或OpenFeign調(diào)用Dubbo服務(wù)的模塊。
        Apache Dubbo和Spring Cloud是兩套架構(gòu)完全不同的開發(fā)框架。
        在講解Dubbo Spring Cloud之前,我們先來看這個問題:Apache Dubbo暴露的服務(wù)都是接口級別的,而Spring Cloud暴露的服務(wù)是應(yīng)用級別的,RestTemplate或OpenFeign發(fā)起調(diào)用服務(wù)都會有對應(yīng)的URL Path、Query Parameter、Header等內(nèi)容(這是HTTP協(xié)議調(diào)用),如何讓這些內(nèi)容關(guān)聯(lián)Dubbo服務(wù)呢?
        針對上述問題,Dubbo Spring Cloud實現(xiàn)了以應(yīng)用為粒度的注冊機制,每個Dubbo應(yīng)用注冊到注冊中心后有且僅有一個服務(wù)。那么原先以接口為維度的那些接口信息去哪里了?
        Dubbo Spring Cloud 定義了 DubboMetadataService 元數(shù)據(jù)服務(wù)的概念。這是一個專門用于存儲 Dubbo 服務(wù)的元數(shù)據(jù)接口。DubboMetadataService 接口定義如下:
        public interface DubboMetadataService {
        // 最核心的接口,用于獲取 Dubbo 服務(wù)的 Rest 元數(shù)據(jù) String getServiceRestMetadata();
        // 返回所有 Dubbo 服務(wù)的 ServiceKey 集合 Set<String> getAllServiceKeys();
        // 返回所有對外暴露的Dubbo服務(wù)。key為ServiceKey,value為URL的json格式 Map<String, String> getAllExportedURLs();
        // 基于接口名分組及版本獲取到 URL 的 json 格式 String getExportedURLs(String serviceInterface, String group, String version);
        }
        核心方法 getServiceRestMetadata 獲取 Dubbo 服務(wù)的 Rest 元數(shù)據(jù)是指:當(dāng)一個 Dubbo 服務(wù)同時也被 SpringMVC 相關(guān)注解修飾時,SpringMVC 相關(guān)注解修飾的內(nèi)容就是這些 Rest 元數(shù)據(jù)。這些 Rest 元數(shù)據(jù)由 RestMethodMetadata 類修飾,比如,這個 Dubbo 服務(wù) RestService 接口,其定義如下:
        @Service@RestControllerpublic class SpringRestService implements RestService {
            @Override    @GetMapping("/param")    public String param(@RequestParam String param) {        return param;    }
        }
        RestService服務(wù)對應(yīng)的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相關(guān)注解,當(dāng)Dubbo服務(wù)自身也暴露Rest協(xié)議的時候,這些JAX-RS相關(guān)注解修飾的內(nèi)容也會被解析成Rest元數(shù)據(jù)。比如,這個Dubbo服務(wù)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服務(wù)對應(yīng)的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)容關(guān)聯(lián)上Dubbo服務(wù)。
        使用RestTemplate或OpenFeign調(diào)用Dubbo服務(wù)會經(jīng)歷以下過程:
        (1)根據(jù)服務(wù)名得到注冊中心的Dubbo服務(wù)DubboMetadataService。
        (2)使用DubboMetadataService里提供的getServiceRestMetadata方法獲取要使用的Dubbo服務(wù)和對應(yīng)的Rest元數(shù)據(jù)。
        (3)基于Dubbo服務(wù)和Rest元數(shù)據(jù)構(gòu)造GenericService。
        (4)服務(wù)調(diào)用過程中使用GenericService發(fā)起泛化調(diào)用。
        02
        調(diào)用Dubbo服務(wù)的步驟
        下面是使用Dubbo Spring Cloud調(diào)用Dubbo服務(wù)的開發(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 相關(guān)注解或使用JAX-RS暴露Rest協(xié)議。
        ① 加上 SpringMVC 相關(guān)注解。
        @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 調(diào)用 Dubbo 服務(wù)。
        使用 RestTemplate調(diào)用的方式如下:
        restTemplate.getForEntity(“http://dubbo-provider-service/param?param=deepinspringcloud”, String.class);
        使用 OpenFeign調(diào)用的方式如下:
        dubboFeignRestService.param(“deepinspringcloud”);

        03
        再談路由和負(fù)載均衡

        基于Netflix Ribbon的Spring Cloud 負(fù)載均衡設(shè)計了以下兩個核心接口:

        • 路由對應(yīng)的ILoadBalancer 接口,獲取服務(wù)的 Server 實例列表。

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

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

        • 自定義 IRule 接口,從所有的 Server 列表里找出與當(dāng)前請求匹配的 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。
        筆者認(rèn)為 Duboo 在路由側(cè)的實現(xiàn)更加優(yōu)雅。在Spring Cloud的設(shè)計中,Ribbon的路由設(shè)計與Request(流量)請求信息是解耦的,而 Dubbo 的 Router與Invocation(流量)是綁定的,這意味著路由過程可以直接基于流量特征進行動態(tài)操作,無須引入類似 ThreadLocal 的方式來傳遞流量特征。
        另外,我們提到過Spring Cloud默認(rèn)提供的ZoneAvoidanceRule這個IRule負(fù)載均衡策略,它內(nèi)部會依賴ServerStats去根據(jù)Server狀態(tài)摘除異常節(jié)點。
        Spring Cloud 提供的其他 IRule 負(fù)載均衡策略并沒有這個能力,如果想在自定義的 IRule 負(fù)載均衡也擁有摘除異常節(jié)點的能力,需要在代碼里配合 ServerStats 使用。
        ▊ 更多相關(guān)內(nèi)容請看《深入理解Spring Cloud與實戰(zhàn)》一書!



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

        手機掃一掃分享

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

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            国产视频黄色 | 欧美色图 | 69国产精品人妻无码免费 | 国产精品久久影院 | 超碰在线a | 国产网址 | 激情婷婷综合网 | 国产特黄无码A片免费看 | 国产三级久久 | 偷窥韩国女浴室女体天国 |