リボンは、Netflixがリリースしたオープンソースプロジェクトです。その主な機能は、Netflixのミドル層サービスを接続するために、クライアント側のソフトウェアロードバランシングアルゴリズムを提供することです。リボンクライアントコンポーネントは、接続タイムアウト、再試行などの一連の完全な構成アイテムを提供します。簡単に言えば、構成ファイルのロードバランサー(略してLB)の背後にあるすべてのマシンをリストすることです。リボンは、特定のルール(単純なポーリング、インスタント接続など)に基づいてこれらのマシンを接続するのに自動的に役立ちます。また、リボンを使用してカスタムロードバランシングアルゴリズムを実装する非常に簡単な方法もあります。
ロードバランスに関しては、通常、サーバー上のロードバランスを考えます。一般的に使用される製品には、LBSハードウェアまたはクラウドサービス、Nginxなどが含まれます。これらはすべて馴染みのある製品です。
Spring Cloudはリボンを提供します。これにより、サービス発信者はロードバランス機能を持つことができます。 Eurekaとの緊密な統合により、サービスクラスター内のロードバランシングサービスをセットアップする必要はありません。これにより、サービスクラスター内のアーキテクチャが大幅に簡素化されます。
とにかく、より多くの仮想紹介を詳細に書きたくありません。関連する紹介をどこでも見ることができます。
コードを開いて、コードを介してリボンがどのように実装されるかを確認してください。
構成
詳細な説明:
1。リボンノートコンフィギュレーション構成リボンロードバルバルマルクリエントインスタンスを生成します。
コード場所:
Spring-Cloud-Netflix-Core-1.3.5.Release.jar
org.springframework.cloud.netflix.ribbon
ribbonautoconfiguration.class
@configuration@conditionalonclass({iclient.class、retstemplate.class、asyncresttemplate.class、ribbon.class})@ribbonclients@autoconfigureaffter(name = "org.springframework.cloud.netflix.eureka.eurekaclientautoconfiguration")@autoconfigurebebefore({loadbalancerautoconfiguration.class、asyncloadbalancerautoconfiguration.class}) ribbonautoconfiguration {// omit @bean @conditionalonmissingbean(loadbalancerclient.class)public loadbalancerclient loadbalancerclient(){return new ribbonloadbalancerclient(SpringClientFactory()); } // omit}まず、構成条件項目を見てみましょう。 Ribbonautoconfigurationの構成は、ロードバラランカルコーンフィギュレーションの構成で使用されるため、ロードバルランランアウトコンフィギュレーション構成の前に実行する必要があります。
リボンロードバラマルクリエントは、ロードバラマルクライエントインターフェイスから継承され、ロードバランシングクライアントであり、ロードバランシングポリシーの発信者です。
2.LoadBalancerInterceptorConfig構成生成:
1)。 Load BalancerInterceptorインスタンス
含む:
ロードバルアクレント実装クラスのリボンロードバラマルコリエントインスタンス
LoadBalancerRequestFactory:インスタンス
2).RESTTEMPLATEカスタムRESTTEMPLATECUSTOMIZERインスタンス
コード場所:
Spring-Cloud-Commons-1.2.4.Release.jar
org.springframework.cloud.client.loadbalancer
loadbalancerautoconfiguration.class
@configuration@conditionalonclass(retstemplate.class)@conditionalonbean(loadbalancerclient.class)@enableconfigurationproperties(loadbalancerretrytroperties.class)パブリッククラスloadbalancerautoconfiguration {// omit @bean @bean loadbalancerRequestFactory(loadbalancerclient loadbalancerclient){return new loadbalancerRequestFactory(loadbalancerclient、transformers); } @Configuration @ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate") static class LoadBalancerInterceptorConfig { @Bean public LoadBalancerInterceptor ribbonInterceptor( LoadBalancerClient loadBalancerClient, LoadBalancerRequestFactory requestFactory) { return new LoadBalancerInterceptor(loadbalancerclient、requestFactory); } @bean @conditionalonmissingbean public rettemplatecustomizer Resttemplatecustomizer(final loadbalancerinterceptor loadbalancerceptor){return new rettemplatecustomizer(){@override public void customize(retttemplate rettemplate){listhtprequestor> arrayceptiestor RESTTEMPLATE.GETINTERCEPTORS()); list.add(loadbalancerinterceptor); RESTTEMPLATE.SETINTERCEPTORS(list); }}; } } // 省略}最初に構成条件を見てみましょう。
プロジェクト環境にレストテンプレートクラスが必要である必要があります。
LoadBalancerclientインターフェイスの実装クラスのインスタンス、つまり前のステップで生成されたリボンロードバラマンカリエントのインスタンスが必要です。
3.上記のステップで作成されたRESTTEMPLATECUSTUMIZERを使用して、すべてのRESTTEMPLATEインスタンスを構成します。これは、reastTemplateインスタンスにロードバランスインターセプターを設定することです。
@Configuration@ConditionalOnClass(RestTemplate.class)@ConditionalOnBean(LoadBalancerClient.class)@EnableConfigurationProperties(LoadBalancerRetryProperties.class)public class LoadBalancerAutoConfiguration { // omit @Bean public SmartInitializingSingleton loadBalancedRestTemplateInitializer( final List <RestTemplateCustomizer>カスタマイザー){new SmartInitializingSingleton(){@Override public void aftersingletonsinStantideated(){for(restTemplate:loadbalancerautoconfiguration.this.restemplates){for(rettemplatecustecustomizers:customizers:customizer customizer.customize(rettemplate); }}}}}}}; } // omit @configuration @conditionalonmissingingclass( "org.springframework.retry.support.retrytemplate")static class loadbalancerceptorconfig {@bean public loadbalancerceptor ribbonecterceptor(loadbalancercorederient、loadbalancerrectoryfucefutfucefuteffectorfuteffectoryfuquestofyfuquestoryfuceftoryfutorefutoryfutoryfutoryfurcetory LoadBalancerInterceptor(loadbalancerclient、requestFactory); } @bean @conditionalonmissingbean public rettemplatecustomizer Resttemplatecustomizer(final loadbalancerinterceptor loadbalancerceptor){return new rettemplatecustomizer(){@override public void customize(retttemplate rettemplate){listhtprequestor> arrayceptiestor RESTTEMPLATE.GETINTERCEPTORS()); list.add(loadbalancerinterceptor); RESTTEMPLATE.SETINTERCEPTORS(list); }}; } } // 省略}RESTTEMPLATE.SECTINTERCEPTORS(リスト)この場所は、負荷分散インターセプターが注入される場所です。
実際に、この場所から、Restemplateが注入されたインターセプターを介した負荷分散を達成するために、対応するリクエストを構築できることを推測できます。
また、インターセプターをカスタマイズして他の目的を達成できることもわかります。
4。RibbonClientConfiguration構成Zoneawareloadbalancerインスタンスを生成します
コード場所:
Spring-Cloud-Netflix-Core-1.3.5.Release.jar
org.springframework.cloud.netflix.ribbon
RibbonClientConfiguration.class
@suppresswarnings( "deprecation")@configuration@enableconfigurationProperties //注文はここで重要です。 https://github.com/spring-cloud/spring-cloud-netflix/issues/2086#issuecomment-316281653@import( {okhttpribbonconfiguration.class、rectclientribbonconfiguration.class、httpclientribbonconfiguration.publinfguration @bean @conditionalonmissingbean public iloadbalancer ribbonloadbalancer(iclientconfig config、serverList <server> serverList、serverListfilter <server> serverListfilter、iruleルール、iping ping、serverlistupdater serverListupdater){(この.PROPERTIESFECTITIESTIRESTITITIESTORIESTORIST() {return this.propertiesfactory.get(iloadbalancer.class、config、name); } new Zoneawareloadbalancer <>(config、rule、ping、serverList、serverListfilter、serverListUpDater)を返します。 } // 省略}Zoneawareloadbalancerは、Iloadbalancerインターフェイスから継承します。これには次の方法があります。
/***ロードバランサーからサーバーを選択します。 * * @paramキーロードバランサーが返すサーバーを決定するために使用できるオブジェクト。 null *ロードバランサーがこのパラメーターを使用しない場合。 * @return server chosen */ public server chooseServer(object key);
Zoneawareloadbalancerは、特定の負荷分散実装クラスであり、デフォルトの負荷分散クラスでもあります。特定のサービスインスタンスは、選択者メソッドを実装することにより選択されます。
インターセプトとリクエスト
1. RESTTEMPLATEを使用して、Getや投稿などのさまざまなリクエストを実行します。これらはすべて、DoExecuteメソッドを使用して実装されます。
コード場所:
Spring-Web-4.3.12.Release.jar
org.springframework.web.client
RESTTEMPLATE.CLASS
パブリッククラスのrettemplateは、interceptinghttpacsesserを実装するretsoperations {//わずかに保護された<t> t doexecute(uri url、httpmethodメソッド、requestcallback requestcallback、responsexcltor <t> responsextractor)を拡張します。 assert.notnull(method、 "'method'はnullでなければなりません"); clienthttpresponse応答= null; try {clienthttprequest request = createrequest(url、method); if(requestCallback!= null){requestCallback.DowithRequest(request); } response = request.execute(); Handleresponse(url、method、response); if(responsextractor!= null){repurn responsextractor.extractdata(response); } else {return null; }} catch(ioException ex){string resource = url.toString();文字列query = url.getRawQuery(); resource =(query!= null?resource.substring(0、resource.indexof( '?'))):resource);新しいresourceaccessexception( " + method.name() +" lequest for/"" + resource + "/": " + ex.getMessage()、ex); }最後に{if(response!= null){respons.close(); } } } // 省略}さまざまなサポートされているHTTPリクエストメソッドは、最終的にDoExecuteメソッドを呼び出します。これは、作成方法を呼び出してリクエストインスタンスを作成し、リクエストを実行して応答オブジェクトを取得します。
2。リクエストインスタンスを生成して、工場を作成します
前のコードでは、Creater Equestメソッドが呼び出され、リクエストインスタンスを作成します。これは、親クラスで定義されています。
最初に主要な相続関係を整理します。
Createrequestメソッドは、実際にはHTTPACCERSER抽象クラスで定義されています。
パブリックアブストラクトクラスhttpaccessor {private clienthttprequestfactory requestfactory = new simpleclienthttprequestfactory(); public void setRequestFactory(clienthttprequestfactory requestfactory){assert.notnull(requestFactory、 "clienthttprequestfactoryはnullでなければ"); this.requestFactory = requestFactory; } public clienthttprequestFactory getRequestFactory(){return this.requestFactory; } Protected ClientHttprequest Createrequest(uri url、httpmethodメソッド)throws ioexception {clienthttprequest request = getRequestFactory()。 if(logger.isdebugenabled()){logger.debug( "created" + method.name() + "request for /" " + url +" /""); }リクエストを返します。 }}CreaterEquestメソッドのGetRequestFactoryメソッドを呼び出して、リクエストインスタンスを取得して工場を作成します。実際、GetRequestFactoryは現在のHTTPACCERSERクラスでは定義されていませんが、サブクラスInterceptingHTTPACCERSERで定義されています。
public abstract class interceptinghttpacsessor extends httpaccessor {private list <clienthttprequestInterceptor> interceptors = new arrayList <ClientHttpRequestInterceptor>(); public void setInterceptors(list <clienthttprequestInterceptor>インターセプター){this.interceptors = interceptors; } public List <ClientHttpRequestInterceptor> getInterceptors(){return interceptors; } @Override public clienthttprequestFactory getRequestFactory(){clientHttpRequestFactory Delegate = super.getRequestFactory(); if(!collectutils.isempty(getInterceptors())){return new InterceptingClientHttpRequestFactory(DeLegate、getInterceptors()); } else {return delegate; }}}ここで小さな行動を起こしました。最初に、HTTPACCERSERクラスを通じてSimpleClientHTTPRequestFactoryファクトリーを作成して取得しました。この工場は、主にインターセプターがないときに基本的な要求インスタンスを作成します。
第二に、インターセプター注入がある場合は、InterceptingClienthttpRequestFactoryファクトリを作成します。この工場は、インターセプターを使用してリクエストインスタンスを作成します。負荷分散インターセプターが注入されるため、InterceptingClientHttpRequestFactory Factoryから作成されます。
3.工場からリクエストインスタンスを作成します
インスタンスを作成するとき、それは工場のCreaterのEquest Methodに依存します。
パブリッククラスInterceptingClienthttpRequestFactory拡張abstractClientHttpRequestFactoryWrapper {プライベート最終リスト<ClientHTTPREQUESTINTERCEPTOR>インターセプター。 public InterceptingClientHttpRequestFactory(clienthttprequestFactory requestFactory、list <ClientHttpRequestInterceptor>インターセプター){super(requestFactory); this.interceptors =(interceptors!= null?interceptors:collections。<clienthttprequestInterceptor> emmtylist()); } @Override Protected ClientHttpRequest Createrequest(uri uri、httpmethod httpmethod、clienthttprequestfactory requestfactory){return new InterceptingClienthttprequest(requestFactory、this.interceptors、uri、httpmethod); }}これは、新しいInterceptingClienthttpRequestインスタンスを意味し、インターセプターおよび基本的なリクエストインスタンス作成ファクトリを注入します。
4.構成段階で注入された負荷バランスインターセプトのインターセプトメソッドを呼び出すインスタンスを要求します
ステップ1から、リクエストインスタンスを作成した後、リクエストインスタンスの実行方法を実行することによりリクエストが実行されることがわかります。
clienthttprequest request = createrequest(url、method); if(requestcallback!= null){requestCallback.DowithRequest(request);} respons = request.execute();実際のリクエストインスタンスは、clienthttpRequestをインターセプトすることであり、実行は実際には親クラスにあります。
クラス定義場所:
Spring-Web-4.3.12.Release.jar
org.springframework.http.client
InterceptingClienthttprequest.class
相続関係を見てください。
サブクラスによって実装された実行中のexecuteinternalメソッドは、実際には実行方法で呼び出されます。
パブリックアブストラクトクラスAbstractClientHttpRequestは、clienthttprequest {private final httpheaders headers = new httpheaders(); private boolean実行= false; @Override public final httpheaders getheaders(){return(this.executed?httpheaders.readonlyhttpheaders(this.headers):this.headers); } @Override public final outputStream getBody()throws ioException {assertnotexecuted(); getBody -internal(this.headers)を返します。 } @Override public final clienthttpresponse execute()throws ioexception {assertnotexecuted(); clienthttpresponse result = executeinternal(this.headers); this.executed = true;返品結果; } protected void assertnotexecuted(){assert.state(!this.executed、 "clienthttprequest既に実行されている"); }保護された要約outputStream getBody -internal(httpheadersヘッダー)スローIoException;保護された抽象的なclienthttpresponse executeterternal(httpheadersヘッダー)はioexceptionをスローします;}実際、それはInterceptingClienthttpRequestクラスの内部的な方法です。この中で、エグゼキューターの実行が再クエストセクションを傍受することが呼び出されます。レベルに合格し、インターセプターが注入されている場合、インターセプターのインターセプト方法が呼び出されることを決定します。
ここでのインターセプターは、実際には、構成段階でRESTTEMPLATEインスタンスに注入されたロードバランシングインターセプターロードバランサーインターセプターインスタンスです。上記の構成段階のステップ2を参照できます。
クラスInterceptingClientHttpRequestはAbstractBufferingClientHttpRequestを拡張します{// Omit @Override Protected FinalHttPresponse ExecuteInternal(httpheadersヘッダー、Byte [] BufferedOutput)Throws IoException {requestexecution execution execution extexecution = new cepteptectepestexectexecution( RequestExecution.execute(this、bufferedOutput); } private class InterceptingRequestexecutionは、clienthttprequestexecution {private final iterator <clienthttprequestinterceptor> iterator; public InterceptingRequestExecution(){this.iterator = interceptors.iterator(); } @Override public clienthttpresponse execute(httprequest request、byte [] body)throws ioexception {if(this.iterator.hasnext()){clienthttprequestInterceptor next interceptor = this.iterator.next(); nextinterceptor.intercept(request、body、this)を返します。 } else {clienthttprequest delegate = requestfactory.createrequest(request.geturi()、request.getmethod()); for(map.entry <string、list <string >> entry:request.getheaders()。entryset()){list <string> values = entry.getValue(); for(string value:values){delegate.getheaders()。add(entry.getKey()、value); }} if(body.length> 0){rreatrutils.copy(body、delegate.getbody()); } return delegate.execute(); }}}}5.負荷分散インターセプターは、ロードバランシングクライアントを呼び出します
ロードバランスインターセプタークラスロードバランサーインターセプタークラスのインターセプトメソッドでは、ロードバランシングクライアントロードバラマンカリエント実装クラスの実行方法が呼び出されます。
Public Class LoadBalancerInterceptorは、clienthttprequestinterceptor {private loadbalancerclient loadbalancer; private loadbalancerRequestFactory requestFactory; public loadbalancerInterceptor(loadbalancerclient loadbalancer、loadbalancerrequestfactory requestfactory){this.loadbalancer = loadbalancer; this.requestFactory = requestFactory; } public loadBalancerInterceptor(loadbalancerclient loadbalancer){//後方互換性については(Loadbalancer、new loadbalancerRequestFactory(loadbalancer)); } @Override public clienthttpresponseインターセプト(最終httprequest request、final byte [] body、final clienthttprequestexecution execution)をスロー{final uri originaluri = request.geturi(); string servicename = originaluri.gethost(); assert.state(servicename!= null、 "request uriには有効なホスト名が含まれていません:" + originaluri); this.loadbalancer.execute(servicename、requestfactory.createrequest(request、body、execution))を返します。 }}構成フェーズのステップ1では、実装クラスがRibbonLoadBalancerclientであることがわかります。
6.ロードバランシングクライアントは、ロードバランシングポリシーを呼び出して、ターゲットサービスインスタンスを選択し、リクエストを開始します
最初の実行メソッドおよびリボンロードバルランカルコリエントのGetServerメソッドでは、実際には、iLoadbalancer実装クラスの選択サーバー方法が選択され、次のリクエストオブジェクトに引き渡されてリクエストを開始することがわかります。
ここのロードバランシングの実装クラスは、デフォルトではZoneawareloadbalancerエリアアウェアロードバランサーインスタンスであり、バランスポリシーを通じて内部的にサービスを選択します。
Zoneawareloadbalancerの作成は、構成フェーズのステップ4にあります。
パブリッククラスのリボンロードバラランカルコリエントloadbalancerclient {@override public <t> t execute(string serviceid、loadbalancerrequest <t> request)throws ioexception {iloadbalancer loadbalancer = getloadbalancer(serviceID);サーバーサーバー= getServer(loadbalancer); if(server == null){新しいIllegalStateException( "" + serviceIDに使用できるインスタンスはありません); } ribbonserver ribbonserver = new ribbonserver(serversid、server、yusecure(server、serviceID)、serverIntrospector(serviceID).getMetadata(server)); return execute(serviceid、ribbonserver、request); } @override public <t> t execute(string serviceId、serviceinstance andersstance、loadbalancerrequest <t> request)throws ioexception {server server = null; if(serviceinstance of ribbonserver){server =((ribbonserver)serviceinstance).getServer(); } if(server == null){新しいIllegalStateExceptionをスロー( "" + serviceIdに使用できるインスタンスはありません); } ribbonloadbalancercontext context = this.clientFactory .GetLoadBalancerContext(serviceID); RibbonStatsRecorder StatsRecorder = new RibbonStatsRecorder(Context、Server); try {t returnval = request.apply(serviceinstance); statsrecorder.recordstats(returnval); Returnval; } // ioExceptionとrethrowをキャッチして、rettemplateが正しく動作するように動作する(ioexception ex){statsrecorder.recordstats(ex); Exを投げる; } catch(Exception ex){statsrecorder.recordstats(ex); ReflectionUtils.RethrowRuntimeException(Ex); } nullを返します。 } //わずかに保護されているサーバーgetServer(iloadbalancer loadbalancer){if(loadbalancer == null){return null; } return loadbalancer.chooseserver( "default"); // todo:キーのより良い取り扱い}保護されたiloadbalancer getloadbalancer(string serviceid){return this.clientfactory.getloadbalancer(serviceId); } public static class ribbonserverはserviceinstance {private final string serviceid;プライベートファイナルサーバーサーバー。プライベートファイナルブールセキュア。プライベートマップ<文字列、文字列>メタデータ; public ribbonserver(String ServiceID、Server Server){this(serversid、server、false、collections。<string、string> emptymap()); } public ribbonserver(String ServiceID、Server Server、Boolean Secure、Map <String、String> Metadata){this.serviceid = serviceId; this.server = server; this.secure = secure; this.metadata = metadata; } // 省略}}コードを完了したら、要約しましょう。
RestTemplateを使用して他のサービスをリクエストする場合、通常のHTTPリクエストインスタンスは、リクエストを送信するために内部的に使用されます。
@loanbalanced AnnotationをRestTemplateに追加した後、実際には構成を介して、ロードバランシングインターセプターがレストテンプレートに注入され、リクエストを送信する前にロードバランサーが対応するポリシーに従って適切なサービスを選択できるようにします。
上記はこの記事のすべての内容です。みんなの学習に役立つことを願っています。誰もがwulin.comをもっとサポートすることを願っています。