리본은 Netflix가 발표 한 오픈 소스 프로젝트입니다. 주요 기능은 클라이언트 측 소프트웨어로드 밸런싱 알고리즘을 제공하여 Netflix의 중간 계층 서비스를 함께 연결하는 것입니다. 리본 클라이언트 구성 요소는 연결 시간 초과, 재 시도 등과 같은 일련의 완전한 구성 항목을 제공합니다. 리본은 특정 규칙 (예 : 간단한 폴링, 인스턴트 연결 등)에 따라 이러한 기계를 자동으로 연결하는 데 도움이됩니다. 또한 리본을 사용하여 맞춤형로드 밸런싱 알고리즘을 구현할 수있는 매우 쉬운 방법이 있습니다.
로드 밸런싱과 관련하여 일반적으로 서버의로드 밸런싱을 생각합니다. 일반적으로 사용되는 제품에는 LBS 하드웨어 또는 클라우드 서비스, NGINX 등이 모두 친숙한 제품입니다.
Spring Cloud는 리본을 제공하여 서비스 호출자가로드 밸런싱 기능을 가질 수 있습니다. Eureka와의 긴밀한 통합을 통해 서비스 클러스터에서로드 밸런싱 서비스를 설정할 필요가 없으며, 이는 서비스 클러스터 내의 아키텍처를 크게 단순화합니다.
어쨌든 더 많은 가상 소개를 자세히 쓰고 싶지 않습니다. 어쨌든 모든 곳에서 관련 소개를 볼 수 있습니다.
코드를 열고 코드를 통해 리본이 구현되는 방법을 확인하십시오.
구성
상해:
1. Ribbonautoconfiguration 구성 구성 Ribbonloadbalancerclient 인스턴스를 생성합니다.
코드 위치 :
Spring-Cloud-Netflix-Core-1.3.5.release.jar
org.springframework.cloud.netflix.ribbon
Ribbonautoconfiguration. 클래스
@configuration@conditionalOnclass ({iclient.class, resttemplate.class, asyncresttemplate.class, ribbon.class})@ribbonclients@autoconfiguR (name = "org.springframework.cloud.netflix.eureka.eurekaclientautoconfiguration")@autoconfigurebeforefore ({loadbalancerautoconfiguration.class, asyncloadbalancerautoconfiguration.class})@enableconfiguration -properties.clasorperties.class {// @bean @conditionalonmissingbean (loadbalancerclient.class) public loadbalancerclient loadbalancerclient () {return new ribbonloadbalancerclient (springclientfactory ()); } // 생략}먼저 구성 조건부 항목을 살펴 보겠습니다. RibbonAutoconfiguration 구성은 LoadBalancerAutoconfiguration 구성에 사용되므로 LoadBalanceraUtoconfiguration 구성 전에 RibbonAutoconfiguration 구성을 실행해야합니다.
RibbonloadBalancerClient는 LoadBalancerClient 인터페이스에서 상속되며로드 밸런싱 클라이언트이며로드 밸런싱 정책의 발신자입니다.
2.로드 밸런스 interninterceptorconfig 구성 생성 :
1). 밸런서 린더 셉터 인스턴스로드
포함하다:
LoadBalancerClient 구현 클래스의 RibbonloadBalancerClient 인스턴스
loadBalancerRequestFactory : 인스턴스
2) .RestTemplate Custom RestTemPlateCustomizer 인스턴스
코드 위치 :
Spring-Cloud-Commons-1.2.4. Release.jar
org.springframework.cloud.client.loadbalancer
loadbalancerautoconfiguration.class
@configuration@conditionalOnclass (resttemplate.class) @conditionalOnbean (loadbalancerClient.class) @enableconFigurationProperties (loadbalancerRetryProperties.class) public class loadbalancerautoconfiguration {// @bean @bean @conditionalonmissingbean publicequestortory LoadBalancerRequestFactory (LoadBalancerClient LoadBalancerClient) {return new loadbalancerRequestFactory (LoadbalancerClient, Transformers); } @configuration @ConditionalOnMissingClass ( "org.springframework.retry.support.retrytemplate") 정적 클래스 LoadbalancerInterceptorconfig {@bean public loadbalancerinterceptor roadbalancerclient loadbalancclient, loadbalancerquestore) {retory newlocerquestore) loadbalancerinterceptor (loadbalancerclient, requestFactory); } @Bean @ConditionalOnMissingBean public RestTemplateCustomizer restTemplateCustomizer( final LoadBalancerInterceptor loadBalancerInterceptor) { return new RestTemplateCustomizer() { @Override public void customize(RestTemplate restTemplate) { List<ClientHttpRequestInterceptor> list = new ArrayList<>( resttemplate.getInterceptors ()); list.add (loadbalancerinterceptor); resttemplate.setinterceptors (list); }}; }} // 생략}먼저 구성 조건을 살펴 보겠습니다.
프로젝트 환경에 RestTemplate 클래스가 있어야합니다.
LoadBalancerClient 인터페이스의 구현 클래스, 즉 이전 단계에서 생성 된 RibbonloadBalancerClient의 인스턴스가 있어야합니다.
3. 위의 단계에서 생성 된 RestTemPlateCustomizer를 통해 모든 resttemplate 인스턴스를 구성하는데, 이는로드 밸런싱 인터셉터를 resttemplate 인스턴스로 설정하는 것입니다.
@configuration@conditionalOnclass (resttemplate.class) @conditionalOnbean (loadbalancerClient.class) @enableconfigurationProperties (loadbalancerRetryProperties.class) public class loadbalancerautoconfiguration {// avit @bean public smartinitializingsingingletonington initializer (levean public smartinitializingsing) <resttemplatecustomizer> customizers) {return new smartinitializingsingingingingsingingleton () {@override public void afteringletonSinstantiated () {for (resttemplate resttemplate : loadbalancerautoconfiguration. customizer.customize (resttemplate); }}}}}}}}; } // @configuration @ConditionalOnMissingClass ( "org.springframework.retry.support.retrytemplate") 정적 Class LoadBalancerInterceptorConfig {@Bean Public LoadBalancerInterceptor Ribbon -BalancerClient BalancerClient (LoadbalancerCleiver) {LoadbalancerRequestorfortfactortfactortfactortfactortfactortorctor loadbalancerinterceptor (loadbalancerclient, requestFactory); } @Bean @ConditionalOnMissingBean public RestTemplateCustomizer restTemplateCustomizer( final LoadBalancerInterceptor loadBalancerInterceptor) { return new RestTemplateCustomizer() { @Override public void customize(RestTemplate restTemplate) { List<ClientHttpRequestInterceptor> list = new ArrayList<>( resttemplate.getInterceptors ()); list.add (loadbalancerinterceptor); resttemplate.setinterceptors (list); }}; }} // 생략}resttemplate.setinterceptor (목록)이 장소는로드 밸런싱 인터셉터가 주입되는 곳입니다.
RestTemplate이 주입 된 인터셉터를 통해로드 밸런싱을 달성하기 위해 해당 요청을 구축 할 수 있다는 것은 실제로이 장소에서 추측 할 수 있습니다.
또한 인터셉터를 사용자 정의하여 다른 목적을 달성 할 수 있음을 알 수 있습니다.
4. RibbonclientConfiguration 구성 구성 Zoneawareloadbalancer 인스턴스를 생성합니다
코드 위치 :
Spring-Cloud-Netflix-Core-1.3.5.release.jar
org.springframework.cloud.netflix.ribbon
RibbonclientConfiguration.class
@SuppressWarnings ( "Dequrecation")@configuration@enableConfigurationProperties // 순서는 여기에서 중요합니다. 마지막으로 기본값이어야합니다. 먼저 선택 사항이어야합니다. // see해야합니다. https://github.com/spring-cloud/spring-cloud-netflix/issues/2086#issuecomment-316281653@import ({khttpribbonconconfiguration.class, restclientribbonconfiguration.class, httpclientribbonconconfiguration.publassclass rivbonclientscigeration})))))). @bean @conditionalonmissingbean public iloadbalancer ribbonloadbalancer (iclientconfig config, serverList> ServerList, ServerListFilter <Server> ServerListFilter, Irule Rule, IPing Ping, ServerListUpdater ServerListupDater) {thistlist. reture this.propertiesFactory.get (iloadbalancer.class, config, name); } 새 ZoneAwarEloadBalancer <> (config, Rule, Ping, ServerList, ServerListFilter, ServerListUpDater); } // 생략}Zoneawareloadbalancer는 Iloadbalancer 인터페이스에서 물려받으며 방법이 있습니다.
/***로드 밸런서에서 서버를 선택하십시오. * * @param 키로드 밸런서가 반환 할 서버를 결정하는 데 사용할 수있는 객체입니다. null if *로드 밸런서 가이 매개 변수를 사용하지 않습니다. * @return 서버 선택 */ public server schooseServer (Object Key);
Zoneawareloadbalancer는 특정로드 밸런싱 구현 클래스이며 기본로드 밸런싱 클래스이기도합니다. 선택 서버 메소드를 구현하여 특정 서비스 인스턴스가 선택됩니다.
인터셉트 및 요청
1. RestTemplate을 사용하여 Get and Post와 같은 다양한 요청을 수행하며,이 모든 요청은 모두 DoExecute 메소드를 통해 구현됩니다.
코드 위치 :
Spring-Web-4.3.12. Release.jar
org.springframework.web.client
resttemplate.class
공개 클래스 RestTemplate 확장 httpaccessor retsoperations {// 약간 보호 된 <t> t doExecute (uri url, httpmethod 메서드, requestCallback requestCallback, ResponseExtractor) restClientException {assert.null (url,”). assert.notnull (메소드, '메소드'는 널 널 늘어나지 않아야한다 "); ClientHttPresponse 응답 = null; try {clienthttprequest request = createrequest (url, method); if (requestCallback! = null) {requestCallback.DowItRequest (request); } response = request.execute (); 핸들러 응답 (URL, 메소드, 응답); if (responsextractor! = null) {return responsextractor.extractData (응답); } else {return null; }} catch (ioexception ex) {문자열 resource = url.tostring (); 문자열 query = url.getRawquery (); resource = (query! = null? resource.substring (0, resource.indexof ( '?')) : resource); 새 ResourceAccessException ( " + method.name () +"request for/"" + resource + "/": " + ex.getMessage (), ex)의"I/O 오류 "를 던지십시오. } 마지막으로 {if (응답! = null) {response.close (); }}} // 생략}지원되는 다양한 HTTP 요청 방법은 궁극적으로 DoExecute 메소드를 호출하여 작성 메소드를 호출하여 요청 인스턴스를 작성하고 응답 객체를 가져 오려는 요청을 실행합니다.
2. 요청 인스턴스를 생성하여 공장을 생성합니다
이전 코드에서는 Createreigest 메소드가 호출되어 요청 인스턴스를 작성하여 상위 클래스에 정의됩니다.
먼저 주요 상속 관계를 구성하십시오.
Createrequest 방법은 실제로 Httpaccessor Abstract 클래스에서 정의됩니다.
공개 초록 클래스 httpaccessor {private clienthttprequestFactory requestFactory = new SimpleClientHttPrequestFactory (); public void setRequestFactory (clientHttpRequestFactory requestFactory) {assert.NOTNULL ( "ClientHttPrequestFactory"는 assert.NOTNULL (requestFactory); this.requestFactory = requestFactory; } public clienthttprequestFactory getRequestFactory () {return this.RequestFactory; } protected ClientHttPrequest CREATEREETEST (uri url, httpMethod 메서드)는 ioException {clientHttpRequest request = getRequestFactory (). CreaterEquest (url, method); if (logger.isdebugenabled ()) {logger.debug ( "created" + method.name () + "request for /" " + url +" /""); } 반환 요청; }}Createrequest 메소드에서 getRequestFactory 메소드를 호출하여 요청 인스턴스를 가져와 공장을 생성하십시오. 실제로, getRequestFactory는 현재 HTTPACCESSOR 클래스에서 정의되지 않지만 서브 클래스 인터 셉팅 httpaccessor에서 정의됩니다.
공개 초록 클래스 interceptinghttpaccessor 확장 httpaccessor {private list <clienthttprequestinterceptor> interceptor = new arraylist <clienthttprequestinterceptor> (); public void setinterceptors (list <clienthttprequestinterceptor> 인터셉터) {this.interceptors = 인터셉터; } public list <clienthttprequestinterceptor> getInterceptors () {return interceptors; } @override public clienthttprequestFactory getRequestFactory () {clientHttPrequestFactory delegate = super.getRequestFactory (); if (! collectionUtils.isempty (getInterceptors ()) {return new interceptingclienthttprequestFactory (Delegate, getInterceptors ()); } else {return delegate; }}}나는 여기서 작은 행동을했다. 먼저, 나는 Httpaccessor 클래스를 통해 SimpleclienthttprequestFactory Factory를 만들고 얻었습니다. 이 공장은 주로 인터셉터가 없을 때 기본 요청 인스턴스를 만듭니다.
둘째, 인터셉터 주입이있을 때, 인터셉트 클리어를 작성하십시오. 이 공장은 인터셉터로 요청 인스턴스를 만듭니다. 로드 밸런싱 인터셉터가 주입되기 때문에 인터셉트 클리어 htttprequestfactory 공장에서 생성됩니다.
3. 공장을 통해 요청 인스턴스를 만듭니다
인스턴스를 생성 할 때는 공장의 크리터가 가장 좋은 방법에 따라 다릅니다.
public class interceptingclienthttprequestFactory 확장 actractHttpRequestFactoryWrapper {private final List <clienthttprequestinterceptor> interceptors; public interceptingclienthttprequestFactory (clienthttprequestFactory requestFactory, list <clientHttPrequestInterceptor> interceptors) {super (requestFactory); this.interceptors = (인터셉터! = null? 인터셉터 : 컬렉션. <clienthttprequestinterceptor> emptylist ()); } @override protected clienthttprequest createrequest (uri uri, httpmethod httpmethod, clienthttprequestFactory requestFactory) {return new interceptingClientHttPrequest (retuckErceptingClientHttPrequest (retureCheceptingClientHttPrequest); }}이는 새로운 인터셉트 클리어 httprequest 인스턴스를 의미하고 인터셉터 및 기본 요청 인스턴스 생성 공장을 주입합니다.
4. 구성 단계에서 주입 된로드 밸런싱 절편의 인터셉트 메소드를 호출하도록 인스턴스를 요청합니다.
1 단계에서 요청 인스턴스를 작성한 후 요청 인스턴스의 실행 메소드를 실행하여 요청이 실행된다는 것을 알 수 있습니다.
clientHttPrequest 요청 = CreaterEquest (url, method); if (requestCallback! = null) {requestCallback.DowItRrequest (request);} response = request.execute ();실제 요청 인스턴스는 clienthttprequest를 가로 채며 실행은 실제로 부모 클래스에 있습니다.
수업 정의 위치 :
Spring-Web-4.3.12. Release.jar
org.springframework.http.client
인터셉트 클리어 httprequest.class
상속 관계를 살펴보십시오.
서브 클래스에 의해 구현 된 ExecuteInternal 메소드는 실제로 실행 메소드에서 호출됩니다.
공개 초록 클래스 AbstractClientHttpRequest ClientHttpRequest {private final httpheaders headers = new httpheaders (); 개인 부울 실행 = 거짓; @override public final httpheaders getheaders () {return (this.executed? httpheaders.readonlyhttpheaders (this.headers) : this.headers); } @override public final outputstream getbody ()는 ioexception {assertnotexecuted (); GetBodyInternal (this.Headers)을 반환합니다. } @override public final clienthttpresponse execute ()는 ioexception {assertNoteXecuted (); ClientHttPresponse result = ExecuteInternal (this.headers); this.Executed = true; 반환 결과; . . 보호 된 추상 Clienthtttttpresponse executeInternal (httpheaders headers)은 ioexception;}실제로, 그것은 가로 채기 httprequest 클래스의 실행 인테일 방법입니다. 여기서, 집행자의 실행은 requestExecution을 가로 채립니다. 레벨을 통과하고 인터셉터가 주입 된 경우 인터셉터의 절편 방법이 호출되는지 확인하십시오.
여기서 인터셉터는 실제로 구성 단계에서 resttemplate 인스턴스에 주입 된로드 밸런싱 인터셉터로드 밸런스 린어처 인스턴스입니다. 위의 구성 단계의 2 단계를 참조 할 수 있습니다.
클래스 인터셉트 클래스를 확장합니다. return 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)는 ioexception {if (this.terator.hasnext ()) {clientHttPrequestInterceptor nextInterceptor = this.terator.next (); Nextinterceptor.intercept (요청, 본문, 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 (문자열 값 : 값) {delegate.getheaders (). add (enther.getKey (), value); }} if (body.length> 0) {streamutils.copy (body, delegate.getbody ()); } return delegate.execute (); }}}}5.로드 밸런싱 인터셉터는로드 밸런싱 클라이언트를 호출합니다.
로드 밸런싱 인터셉터 클래스로드 밸런스 린어처 클래스의 인터셉트 메소드에서,로드 밸런싱 클라이언트로드 밸런스 클라이언트 구현 클래스의 실행 방법이 호출됩니다.
공개 클래스로드 밸런스 린터 셉터는 클라이언트를 구현합니다. Private BalancerRequestFactory RequestFactory; public loadbalancerinterceptor (loadbalancerclient loadbalancer, loadbalancerRequestFactory requestFactory) {this.loadbalancer = loadbalancer; this.requestFactory = requestFactory; } public loadbalancerinterceptor (loadbalancerclient loadbalancer) {// 거꾸로 호환성에 대한 (loadbalancer, new loadbalancerRequestFactory (loadbalancer)); } @override public clienthtttpresponse intercept (최종 httprequest 요청, 최종 바디 [] 바디, 최종 clienthttprequestexecution execution) ioexception {final uri originalUri = request.geturi (); 문자열 serviceName = originalUri.gethost (); assert.state (serviceName! = null, "request uri는 유효한 호스트 이름을 포함하지 않습니다 :" + originalUri); reture this.loadbalancer.execute (serviceName, requestFactory.createrequest (요청, 신체, 실행)); }}구성 단계의 1 단계에서 구현 클래스가 RibbonloadBalancerClient임을 알 수 있습니다.
6.로드 밸런싱 클라이언트는로드 밸런싱 정책을 호출하여 대상 서비스 인스턴스를 선택하고 요청을 시작합니다.
RibbonloadBalancerClient의 첫 번째 실행 메소드 및 GetServer 메소드에서 실제로 Iloadbalancer 구현 클래스의 선택 서버 메소드가 선택되고 다음 요청 객체로 전달되어 요청을 시작 함을 알 수 있습니다.
여기에서로드 밸런싱 구현 클래스는 기본적으로 Zoneawareloadbalancer 지역 인식로드 밸런서 인스턴스이며 밸런싱 정책을 통해 내부적으로 서비스를 선택합니다.
zoneawareloadbalancer의 생성은 구성 단계의 4 단계에서 찾을 수 있습니다.
공개 클래스 RibbonloadBalancerClient는 LoadBalancerClient {@override public <t> t execute (String ServiceId, LoadBalancerRequest <T> 요청)를 IOException {iloadbalancer loadbalancer = getloadbalancer (serviceId); 서버 서버 = GetServer (loadbalancer); if (server == null) {새로운 불법 스테이트 exception ( " + serviceID에 사용할 수있는 인스턴스 없음); } ribbonserver ribbonserver = new Ribbonserver (ServiceId, Server, issecure (Server, ServiceId), ServerIntrospector (ServiceId) .getmetadata (Server)); return execute (service, ribbonserver, request); } @override public <t> t execute (String ServiceId, ServiceInstance ServiceInstance, loadBalancerRequest <t> request) IoException {Server Server = null; if (ribbonserver의 serviceInstance 인스턴스) {server = ((ribbonserver) serviceInstance) .getServer (); } if (server == null) {throw new New ElegalStateException ( " + serviceID에 사용할 수있는 인스턴스 없음); } ribbonloadbalancerContext context = this.clientFactory .getLoadBalanCerContext (serviceId); RibbonStatsRecorder StatsRecorder = New RibbonStatsRecorder (Context, Server); try {t returnVal = request.Apply (serviceInstance); statsRecorder.recordstats (returnVal); return returnval; } // resttemplate가 올바르게 행동하도록 ioexception과 재고를 잡아 당기십시오 (ioexception ex) {statsrecorder.recordstats (ex); ex 던지기; } catch (Exception Ex) {statsRecorder.recordStats (ex); ReflectionUtils.RethrowRuntImeexception (예); } return 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 (service, server, false, collections. <string, string> emplymap ()); } public ribbonserver (String ServiceId, Server Server, Boolean Secure, Map <String, String> Metadata) {this.serviceid = serviceId; this.server = 서버; this.secure = 보안; this.metadata = 메타 데이터; } // 생략}}코드를 완료 한 후에는 요약하겠습니다.
RestTemplate를 사용하여 다른 서비스를 요청할 때 일반 HTTP 요청 인스턴스는 내부적으로 요청을 보내는 데 사용됩니다.
@loanbalanced 주석을 RestTemplate에 추가 한 후 실제로 구성을 통해로드 밸런싱 인터셉터가 RestTemplate에 주입되어로드 밸런서가 요청을 보내기 전에 해당 정책에 따라 적절한 서비스를 선택할 수 있습니다.
위는이 기사의 모든 내용입니다. 모든 사람의 학습에 도움이되기를 바랍니다. 모든 사람이 wulin.com을 더 지원하기를 바랍니다.