Ribbon adalah proyek open source yang dirilis oleh Netflix. Fungsi utamanya adalah menyediakan algoritma penyeimbang beban perangkat lunak sisi klien untuk menghubungkan layanan tingkat menengah Netflix bersama-sama. Komponen klien pita menyediakan serangkaian item konfigurasi lengkap seperti batas waktu koneksi, coba lagi, dll. Sederhananya, itu adalah mendaftar semua mesin di belakang load balancer (singkatnya LB) dalam file konfigurasi. Pita akan secara otomatis membantu Anda menghubungkan mesin -mesin ini berdasarkan aturan tertentu (seperti polling sederhana, koneksi instan, dll.). Kami juga memiliki cara yang sangat mudah untuk menerapkan algoritma penyeimbangan beban khusus menggunakan pita.
Ketika datang untuk memuat penyeimbangan, Anda biasanya memikirkan penyeimbangan beban di server. Produk yang umum digunakan termasuk perangkat keras LBS atau layanan cloud, nginx, dll., Yang semuanya merupakan produk yang akrab.
Spring Cloud menyediakan pita, yang memungkinkan penelepon layanan memiliki kemampuan penyeimbangan beban. Melalui integrasi erat dengan Eureka, tidak perlu mengatur layanan penyeimbangan beban di kluster layanan, yang sangat menyederhanakan arsitektur dalam cluster layanan.
Saya tidak ingin menulis lebih banyak perkenalan virtual secara detail, bagaimanapun, saya dapat melihat perkenalan yang relevan di mana -mana.
Cukup buka kode dan lihat bagaimana pita diimplementasikan melalui kode.
Konfigurasi
Penjelasan terperinci:
1. Konfigurasi Ribbonautoconfiguration Menghasilkan instance RibbonloadBalanCerClient.
Lokasi Kode:
Spring-cloud-netflix-core-1.3.5.release.jar
org.springframework.cloud.netflix.ribbon
Ribbonautoconfiguration.class
@Configuration@conditionAnclass ({iclient.class, resttemplate.class, asyncresttemplate.class, ribbon.class})@ribbonClients@autoconfigureafter (name = "org.springframework.cloud.netflix.eurek RibbonAutoconfiguration {// omit @Bean @ConditionAlonMissingBean (LoadBalancerClient.Class) Public LoadBalanCerClient LoadBalancerClient () {return New RibboBloadBalanCerClient (SpringClientFactory ()); } // hilangkan}Pertama -tama mari kita lihat item bersyarat konfigurasi. Konfigurasi konfigurasi pitautokonfigurasi harus dieksekusi sebelum konfigurasi loadbalancerautoconfiguration, karena instance RibbonloadBalanCerClient akan digunakan dalam konfigurasi konfigurasi loadbalancerautoconfiguration.
RibbonLoadBalanCerClient mewarisi dari antarmuka LoadBalancerClient, adalah klien penyeimbang beban dan penelepon dari kebijakan penyeimbangan beban.
2.LoadBalancerInceptorConfig Generasi Konfigurasi:
1). Load BalancerInterceptor instance
Termasuk:
Contoh RibbonloadBalancerClient dari kelas implementasi LoadBalancerClient
LoadBalanCerRequestFactory: Instance
2.
Lokasi Kode:
Spring-cloud-commons-1.2.4.release.jar
org.springframework.cloud.client.loadBalancer
LoadBalanCerautoconfiguration.class
@Configuration@conditionAnclass (resttemplate.class) @conditionAlonbean (loadbalancerclient.class) @EnableConfigurationProperties (loadBalancerretryproperties.class) Public Class Loadanterautoconfiguration {// omit @bean @beanalononMissingbeArbeArance {// omit @bean @beondononeMissingBean 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 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 (daftar); }}; }} // dihilangkan}Mari kita lihat kondisi konfigurasi terlebih dahulu:
Diperlukan bahwa harus ada kelas RestTemplate di lingkungan proyek.
Diperlukan bahwa harus ada contoh dari kelas implementasi antarmuka loadbalancerclient, yaitu, RibbonloadBalancerClient yang dihasilkan pada langkah sebelumnya.
3. Mengkonfigurasi semua instance resttemplate melalui resttemplateCustomizer yang dibuat pada langkah di atas, yaitu untuk mengatur pencegat penyeimbang beban ke instance restemplate.
@Configuration@ConditionalOnClass(RestTemplate.class)@ConditionalOnBean(LoadBalancerClient.class)@EnableConfigurationProperties(LoadBalancerRetryProperties.class)public class LoadBalancerAutoConfiguration { // omit @Bean public SmartInitializingSingleton loadBalancedRestTemplateInitializer( final Daftar <resttemplatecustomizer> kustomisasi) {return baru SmartInitializingingSingLeTon () {@Override public void aftersingletonsInstantiated () {for (restTemplate restTemplate: loadbalancereutoconfiguration: thiscustomizer: thisstemplate: for for (resttemplate: thiscustomizer: thistemplate: resttemplate: thistemplate: for for (restemplate: thistemplate: for (foreCtemplate: thistemplate: for (resttemplate) customizer.customize (resttemplate); }}}}}}}; } // oMit @configuration @conditionAlonMissingClass ("org.springframework.retry.support.retryTemplate") kelas statis loadBalancerInterceptorConfig {@Bean loadBalancerCeptor RibbonIcteptor (LoadBalancerClient {LoadBalancoryclient {LoadBoacToryclient {LoadBonCericclient {loadclient publicerclient publicclient publicclient {@bean, loadantercericclient {loadanterclient publicclient {loadanterclient publicclient {loadanterclient publicclient publicclient, 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 (daftar); }}; }} // dihilangkan}resttemplate.setInterceptors (daftar) Tempat ini adalah tempat di mana pencegat penyeimbang beban disuntikkan.
Sebenarnya dapat ditebak dari tempat ini bahwa RestTemplate dapat membangun permintaan yang sesuai untuk mencapai keseimbangan beban melalui penyegar yang disuntikkan.
Dapat juga dilihat bahwa Anda dapat menyesuaikan pencegat untuk mencapai tujuan lain.
4. Konfigurasi Konfigurasi Konfigurasi RibbonClient Menghasilkan Instance ZoneAwareloadbalancer
Lokasi Kode:
Spring-cloud-netflix-core-1.3.5.release.jar
org.springframework.cloud.netflix.ribbon
RibbonClientConfiguration.class
@SuppressWarnings ("Deprecation")@configuration@enableConfigurationProperties // pesanan penting di sini, terakhir harus menjadi default, pertama harus opsional // lihat https://github.com/spring-cloud/spring-cloud-netflix/issues/2086#issueComment-316281653@import( {okhttpribbonConfiguration.classcclasscconfiguration.classcclass.class, httpconfiguration.classcclass.class, httpconfiguration.classcclass.classcconfiguration.classcconfiguration oMit @Bean @ConditionAlonMissingBean Iloadbalancer RibbonLoadBalancer Publik (ICLIENTCONCONFIG, ServerList <Server> Disterion, serverListFilter <Server> serverListFilter, aturan iRule) {serverlistupater (serverlistUpdater) {if ini. kembalikan this.propertiesfactory.get (iloadbalancer.class, config, name); } return zoneagareLoadBalancer baru <> (config, aturan, ping, serverlist, serverlistFilter, serverlistupdater); } // dihilangkan}ZoneAwareloadbalancer mewarisi dari antarmuka Iloadbalancer, yang memiliki metode:
/*** Pilih server dari load balancer. * * @param Key Suatu objek yang dapat digunakan oleh penyeimbang beban untuk menentukan server mana yang akan dikembalikan. null jika * penyeimbang beban tidak menggunakan parameter ini. * @Return Server yang dipilih */ server publik memilih server (kunci objek);
ZoneAwareLoadBalancer adalah kelas implementasi penyeimbangan beban tertentu, dan juga merupakan kelas penyeimbang beban default. Contoh layanan tertentu dipilih dengan mengimplementasikan metode Choiceserver.
Mencegat & permintaan
1. Gunakan RestTemplate untuk melakukan berbagai permintaan seperti GET dan POST, yang semuanya diimplementasikan melalui metode DoExecute.
Lokasi Kode:
Spring-Web-4.3.12.release.jar
org.springframework.web.client
Resttemplate.class
RESTTemplate kelas publik memperluas intersepingHttpaccessor mengimplementasikan resoperasi {// sedikit dilindungi <t> t doexecute (URI url, httpmethod metode, requestCallback requestCallback, responseExtractor <T> ResponseExtractor) no noTclientException {assert.notnull (UR "; Assert.notnull (metode, "'metode' tidak boleh nol"); ClientHttpresponse response = null; coba {clientHttpRequest request = createRequest (url, metode); if (requestCallback! = null) {requestCallback.dowithRequest (request); } response = request.execute (); handleresponse (url, metode, respons); if (responseExtractor! = null) {return responseExtractor.extractData (respons); } else {return null; }} catch (ioException ex) {String Resource = url.toString (); String kueri = url.getRawQuery (); resource = (kueri! = null? resource.substring (0, resource.indexof ('?')))): sumber daya); Lempar New ResourceAccessException ("I/O Error pada" + Method.name () + "Permintaan untuk/" " + Sumber Daya +"/":" + Ex.getMessage (), ex); } akhirnya {if (response! = null) {response.close (); }}} // dihilangkan}Berbagai metode permintaan HTTP yang didukung pada akhirnya memanggil metode DoExecute, yang memanggil metode pembuatan untuk membuat instance permintaan, dan menjalankan permintaan untuk mendapatkan objek respons.
2. Hasilkan instance permintaan untuk membuat pabrik
Dalam kode sebelumnya, metode CreateRequest dipanggil untuk membuat instance permintaan, yang didefinisikan dalam kelas induk.
Pertama mengatur hubungan warisan utama:
Metode CreateRequest sebenarnya didefinisikan dalam kelas abstrak httpaccessor.
kelas abstrak publik httpaccessor {private clientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory (); public void setRequestFactory (clientHttprequestFactory requestFactory) {assert.notnull (requestFactory, "clientHttprequestFactory tidak boleh null"); this.RequestFactory = requestFactory; } public clientHttpRequestFactory getRequestFactory () {return this.RequestFactory; } clientHttpRequest createReQuest (URL URL, metode httpMethod) melempar ioException {clientHttpRequest request = getRequestFactory (). CRIPERHTTTPREEST = getRequestFactory (). CreateRequest (URL, Metode); if (logger.isdebugeNabled ()) {logger.debug ("dibuat" + method.name () + "permintaan /" " + url +" /""); } permintaan pengembalian; }}Hubungi metode GetRequestFactory dalam metode CreateRequest untuk mendapatkan instance permintaan untuk membuat pabrik. Faktanya, GetRequestFactory tidak didefinisikan dalam kelas httpaccessor saat ini, tetapi didefinisikan dalam subkelas intersepingHttpaccessor.
kelas abstrak abstrak publik interceptinghttpaccessor memperluas httpaccessor {daftar privat <clientHttpRequestInterceptor> interceptors = new arraylist <clientHttpRequestInterceptor> (); public void setIterceptors (Daftar <ClientHttPRequestInterceptor> Interceptors) {this.interceptors = Interceptors; } Daftar Publik <ClientHttPRequestInterceptor> getInterceptors () {return interceptors; } @Override Public ClientHttPRequestFactory getRequestFactory () {clientHttpRequestFactory delegate = super.getRequestFactory (); if (! collectionSils.isempty (getInterceptors ())) {return new InterceptingClientHttpRequestFactory (delegate, getInterceptors ()); } else {return delegate; }}}Saya membuat tindakan kecil di sini. Pertama, saya membuat dan memperoleh pabrik SimpleClientHttprequestFactory melalui kelas HTTPAccessor. Pabrik ini terutama menciptakan instance permintaan dasar ketika tidak ada interseptor.
Kedua, ketika ada injeksi interceptor, buat pabrik intersepingClientHttprequestFactory. Pabrik ini membuat instance permintaan dengan pencegat. Karena pencegat penyeimbang beban disuntikkan, itu dibuat dari pabrik intersepingClientHttpRequestFactory.
3. Buat instance permintaan melalui pabrik
Saat membuat instance, itu tergantung pada metode CreateRequest pabrik.
Public Class IntercepingClientHttPRequestFactory memperluas AbstractClientHtPRequestFactoryWrapper {Private Final List <ClientHttPRequestInterCeptor> Interceptors; Public InterceptingClientHttPRequestFactory (clientHttPRequestFactory requestFactory, daftar <clientHttpRequestInterceptor> Interceptors) {super (requestFactory); this.interceptors = (interceptors! = null? Interceptors: collections. <clienthttprequestinterceptor> emptylist ()); } @Override Dilindungi ClientHttpRequest CreateRequest (URI URI, httpMethod httpmethod, clienthttprequestFactory requestFactory) {return new interceptingClientHtpRequest (requestFactory, this.ceptors, uri, httpmeethod); }}Ini berarti instance IntercepingClientHttpRequest baru dan menyuntikkan pabrik pembuatan insteptor dan instance dasar.
4. Minta instance untuk memanggil metode intersep dari penyeimbang beban yang disuntikkan pada tahap konfigurasi
Dapat dilihat dari langkah 1 bahwa setelah membuat instance permintaan, permintaan dijalankan dengan mengeksekusi metode eksekusi dari instance permintaan.
ClientHttpRequest request = createRequest (url, metode); if (requestCallback! = Null) {requestCallback.dowithRequest (request);} response = request.execute ();Contoh permintaan yang sebenarnya adalah interseptingClientHttpRequest, dan dieksekusi sebenarnya ada di kelas induknya.
Lokasi Definisi Kelas:
Spring-Web-4.3.12.release.jar
org.springframework.http.client
InterceptingClientHttpRequest.class
Lihatlah hubungan warisan mereka.
Metode ExecuteInternal yang diimplementasikan oleh subclass sebenarnya dipanggil dalam metode Execute.
Kelas Publik Abstrak AbstrakClientHttPRequest mengimplementasikan clientHttpRequest {private final httpheaders headers = httpheaders baru (); Private Boolean dieksekusi = false; @Override public final httpheaders getHeaders () {return (this.executed? Httpheaders.readonlyhttpheaders (this.headers): this.headers); } @Override public outputStream getBody () melempar ioException {AssertNotExecuted (); kembali GetBodyInternal (This.Headers); } @Override public clientHttpresponse execute () melempar ioException {assertNotExecuted (); ClientHttpresponse hasil = ExecuteInternal (this.headers); this.executed = true; hasil pengembalian; } Protected void AssertNotExecuted () {assert.state (! this.executed, "clientHttpRequest yang sudah dieksekusi"); } protected abstrak outputStream getBodyInternal (header httpheaders) melempar ioException; Lindung Abstrak ClientHttPresponse ExecuteInternal (header httpheaders) melempar IOException;}Faktanya, ini adalah metode eksekusi dari kelas intersepingClientHttpRequest. Di mana, pelaksanaan pelaksana pencegat rexceptequesticution dipanggil. Lewati level dan tentukan bahwa jika interseptor telah disuntikkan, metode intersepsi dari interseptor dipanggil.
Interceptor di sini sebenarnya adalah instance Load Balancing Interceptor LoadBalancerCeptor yang disuntikkan ke instance RestTemplate selama tahap konfigurasi. Anda dapat merujuk pada langkah 2 dari tahap konfigurasi di atas.
class InterceptingClientHttpRequest extends AbstractBufferingClientHttpRequest { // omit @Override protected final ClientHttpResponse executeInternal(HttpHeaders headers, byte[] bufferedOutput) throws IOException { InterceptingRequestExecution requestExecution = new InterceptingRequestExecution(); pengembalian requestExecution.Execute (ini, bufferedOutput); } private class interceptingRequestExecution mengimplementasikan clientHttpRequestExecution {private final iterator <ClientHttpRequestInterceptor> iterator; Public InterceptingRequestExecution () {this.iterator = Interceptors.iterator (); } @Override Public ClientHttPresponse Execute (httpRequest request, byte [] body) melempar ioException {if (this.iterator.hasnext ()) {clientHttpRequestInterceptor nextInterceptor = this.iterator.next (); return nextInterceptor.Intercept (permintaan, tubuh, ini); } else {clientHttpRequest delegate = requestFactory.createRequest (request.geturi (), request.getMethod ()); untuk (map.entry <string, daftar <string>> entri: request.getHeaders (). entryset ()) {list <string> values = entry.getValue (); untuk (nilai string: values) {delegate.getHeaders (). add (entry.getKey (), value); }} if (body.length> 0) {streamutils.copy (body, delegate.getbody ()); } return delegate.execute (); }}}}5. Interceptor penyeimbang beban memanggil klien penyeimbang beban
Dalam metode intersep dari kelas penyeimbang beban kelas interceptor loadBalancerCeptor kelas, metode pelaksanaan kelas implementasi loadbalancerclient klien load balancing dipanggil.
kelas publik LoadBalancerInterceptor mengimplementasikan ClientHttPRequestInterceptor {Private LoadBalancerClient LoadBalancer; Private LoadBalancerRequestFactory RequestFactory; Public LoadBalancerInterceptor (LoadBalanCerClient LoadBalancer, LoadBalancerRequestFactory RequestFactory) {this.loadBalancer = loadBalancer; this.RequestFactory = requestFactory; } public LoadBalancerInterceptor (LoadBalanCerClient LoadBalancer) {// Untuk kompatibilitas mundur ini (LoadBalancer, LoadBalancerRequestFactory baru (LoadBalancer)); } @Override Public ClientHttPresponse Intercept (Permintaan HTTPRequest akhir, byte final [] body, clientHttpRequestExecution Execution) Melempar ioException {final uri originaluri = request.geturi (); String serviceName = originaluri.getHost (); Assert.state (serviceName! = Null, "permintaan uri tidak berisi nama host yang valid:" + originaluri); kembalikan this.loadBalancer.execute (serviceName, requestFactory.createRequest (permintaan, bodi, eksekusi)); }}Pada langkah 1 dari fase konfigurasi, Anda dapat melihat bahwa kelas implementasi adalah RibbonLoadBalanCerClient.
6. Klien penyeimbang beban memanggil kebijakan penyeimbang beban untuk memilih instance layanan target dan memulai permintaan
Dalam metode Execute pertama dan metode Goterver dari RibbonloadBalanCerClient, kita dapat melihat bahwa pada kenyataannya, metode Choiceserver dari kelas implementasi Iloadbalancer dipilih dan diserahkan ke objek permintaan berikutnya untuk memulai permintaan.
Kelas implementasi penyeimbang beban di sini adalah zoneawareloadbalancer Area-Aware Load Balancer instance secara default, dan memilih layanan secara internal melalui kebijakan penyeimbang.
Penciptaan zoneagareloadbalancer dapat ditemukan pada langkah 4 dari fase konfigurasi.
Kelas Publik RibbonLoadBalanCerClient mengimplementasikan LoadBalancerClient {@Override public <t> t mengeksekusi (String serviceID, LoadBalancerRequest <T> permintaan) melempar ioException {iloadbalancer loadBalancer = GetLoadBallancer (serviceID); Server Server = GetServer (LoadBalancer); if (server == null) {lempar baru ilegalstateException ("Tidak ada instance yang tersedia untuk" + serviceId); } Ribbonserver Ribbonserver = Ribbonserver baru (serviceId, server, issecure (server, serviceId), serverintrospector (serviceId) .getMetadata (server)); Return Execute (ServiceID, Ribbonserver, Request); } @Override public <t> t execute (string serviceId, serviceInstance serviceInstance, loadBalancerRequest <T> permintaan) melempar ioException {server server = null; if (serviceInstance instance dari Ribbonserver) {server = ((Ribbonserver) ServiceInstance) .getServer (); } if (server == null) {lempar baru ilegalstateException ("Tidak ada instance yang tersedia untuk" + serviceId); } RibbonLoadBalanCerContext Context = this.clientFactory .getLoadBalancerContext (serviceId); RibbonStAsRecorder StatSrecorder = RibbonStAsRecorder baru (konteks, server); coba {t returnVal = request.Apply (serviceInstance); StatSrecorder.Recordstats (returnVal); return returnval; } // Tangkap IoException dan rethrow sehingga restTemplate berperilaku dengan benar (ioException ex) {statsrecorder.recordstats (ex); lempar ex; } catch (exception ex) {statsrecorder.recordstats (ex); Reflectionutils.rethrowruntimeException (EX); } return null; } // Server Sedikit Dilindungi GetServer (ILoadBalancer LoadBalancer) {if (loadBalancer == null) {return null; } return loadbalancer.chooseserver ("default"); // TODO: Penanganan Kunci yang Lebih Baik} Dilindungi Iloadbalancer GetloadBalancer (String ServiceID) {return this.clientfactory.getLoadBalancer (serviceId); } public static class Ribbonserver mengimplementasikan layananinstance {private final string serviceId; server server akhir pribadi; private final boolean aman; peta pribadi <string, string> metadata; Public Ribbonserver (String ServiceID, Server Server) {this (serviceId, 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 = aman; this.metadata = metadata; } // dihilangkan}}Setelah menyelesaikan kode, mari kita ringkasnya.
Saat menggunakan RestTemplate untuk meminta layanan lain, instance permintaan HTTP reguler digunakan secara internal untuk mengirim permintaan.
Setelah menambahkan anotasi @loanbalanced ke resisttemplate, sebenarnya, melalui konfigurasi, pencegat penyeimbang beban disuntikkan ke restTemplate, memungkinkan penyeimbang beban untuk memilih layanan yang sesuai sesuai dengan kebijakan yang sesuai sebelum mengirimkan permintaan.
Di atas adalah semua konten artikel ini. Saya berharap ini akan membantu untuk pembelajaran semua orang dan saya harap semua orang akan lebih mendukung wulin.com.