Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to use Ribbon in springcloud

2025-01-14 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

Editor to share with you how to use Ribbon in springcloud, I believe most people do not know much about it, so share this article for your reference, I hope you can learn a lot after reading this article, let's go to know it!

Basic use

Here, a simple client-side load balancing case is implemented based on zookeeper registry + ribbon.

Service provider

The first is a service provider. The code is as follows.

Application.properties profile

Spring.application.name=discovery-serviceserver.port=0service-B.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRulebootstrap.properties profile

Spring.cloud.zookeeper.connect-string=192.168.0.15:2181 bootstrap, provides a ribbonService rest interface service, registers the program to zookeeper.

SpringBootApplication@EnableDiscoveryClient@RestControllerpublic class DiscoverClient {public static void main (String [] args) {SpringApplication.run (DiscoverClient.class, args);} @ RequestMapping ("/ ribbonService") public String ribbonService () {return "hello too ribbon";}}

Service caller

The service caller is the one who carries on the load balancing and uses the RestTemplate of ribbo to invoke the service.

RibbonConfig, configure the RestTemplate of ribbon, which is implemented by @ LoadBalanced annotation. The specific principle will be analyzed later.

@ Configurationpublic class RibbonConfig {/ * instantiate RestTemplate * @ return * / @ Bean @ LoadBalanced public RestTemplate rebbionRestTemplate () {return new RestTemplate ();} / * configure random load policy, you need to configure the attribute service-B.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule * / @ Bean public IRule ribbonRule () {return new RandomRule ();}}

Bootstrap

@ SpringBootApplication (scanBasePackages = "garine.learn.ribbon.loadblance") @ EnableDiscoveryClient@RestControllerpublic class TestRibbonApplocation {public static void main (String [] args) {SpringApplication.run (TestRibbonApplocation.class, args);} @ Autowired @ LoadBalanced RestTemplate restTemplate; @ GetMapping ("/ {applicationName} / ribbonService") public String ribbonService (@ PathVariable ("applicationName") String applicationName) {return restTemplate.getForObject ("http://" + applicationName+" / ribbonService ", String.class);}}

The configuration file is the same as above, and the service name can be modified.

test

Start two discovery-service, which is a random port because the port is set to 0.

Start the service caller

The browser accesses the interface provided by the service caller, and the path parameter needs to be added with the name of the invoked service, such as http://localhost:8080/discovery-service/ribbonService, and then the service caller invokes the provider's interface using ribbon's RestTemplate.

The result returns: hello too ribbon, and both services initiated by the service provider may be invoked, depending on how the load policy is configured.

The above is an example of a simple use of ribbon, using feign is basically similar to the work written above, so how on earth is ribbon implemented?

Principle and source code analysis

The key point of ribbon implementation is that the RestTemplate,ribbon customized for ribbon uses the interceptor mechanism of RestTemplate to realize the load balancing of ribbon in the interceptor. The basic implementation of load balancing is to use applicationName to obtain the list of available service addresses from the service registry, and then decide which service address to use for http calls through a certain algorithm load.

RestTemplate of Ribbon

An attribute in RestTemplate is List interceptors. If the interceptor data in interceptors is not empty, when RestTemplate makes a http request, the request will be intercepted by the interceptor. The interceptor implements the interface ClientHttpRequestInterceptor, which needs to be implemented as follows

ClientHttpResponse intercept (HttpRequest request, byte [] body, ClientHttpRequestExecution execution) throws IOException

That is, the interceptor needs to complete the http request and encapsulate a standard response return.

Interceptor in ribbon

Such an interceptor is also defined in Ribbon and injected into RestTemplate. How is it implemented?

In the Ribbon implementation, a LoadBalancerInterceptor is defined. Not to mention the specific logic, ribbon intercepts the request through this interceptor, and then implements the load balancer call.

Interceptor is defined in org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration.LoadBalancerInterceptorConfig#ribbonInterceptor

@ Configuration@ConditionalOnMissingClass ("org.springframework.retry.support.RetryTemplate") static class LoadBalancerInterceptorConfig {@ Bean / / defines ribbon's interceptor public LoadBalancerInterceptor ribbonInterceptor (LoadBalancerClient loadBalancerClient, LoadBalancerRequestFactory requestFactory) {return new LoadBalancerInterceptor (loadBalancerClient, requestFactory);} @ Bean @ ConditionalOnMissingBean / / defines the injector to inject the interceptor into RestTemplate, using public RestTemplateCustomizer restTemplateCustomizer (final LoadBalancerInterceptor loadBalancerInterceptor) {return restTemplate-> {List list = new ArrayList (restTemplate.getInterceptors ()); list.add (loadBalancerInterceptor); restTemplate.setInterceptors (list) };}}

Interceptor in ribbon is injected into RestTemplate

When an interceptor is defined, you naturally need to inject the interceptor into RestTemplate to take effect, so how is it implemented in ribbon? The definition of interceptor and interceptor injector are mentioned above, so there must be a place to use injector to inject interceptor.

In the org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration#loadBalancedRestTemplateInitializerDeprecated method, the injection is performed as follows.

@ Configuration@ConditionalOnClass (RestTemplate.class) @ ConditionalOnBean (LoadBalancerClient.class) @ EnableConfigurationProperties (LoadBalancerRetryProperties.class) public class LoadBalancerAutoConfiguration {@ LoadBalanced @ Autowired (required = false) private List restTemplates = Collections.emptyList (); @ Bean public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated (final ObjectProvider restTemplateCustomizers) {/ / traverses the injector in context, calling the injection method. Return ()-> restTemplateCustomizers.ifAvailable (customizers-> {for (RestTemplate restTemplate: LoadBalancerAutoConfiguration.this.restTemplates) {for (RestTemplateCustomizer customizer: customizers) {customizer.customize (restTemplate);});} /. }

Traversing the injector in context, calling the injection method, injecting interceptor, injector and interceptor for the target RestTemplate are all defined by us.

There is also a key point: what is the target restTemplates that needs to be injected into the interceptor? Because there may be multiple RestTemplate instances in context, it is impossible to inject all of them into interceptors, so this is the time for the @ LoadBalanced annotation to come into play.

LoadBalanced comments

Strictly speaking, this annotation is implemented by spring cloud, not in ribbon, and its purpose is to inject only instances that are modified by @ LoadBalanced when instantiated during dependency injection.

For example, when we define RestTemplate for Ribbon, it looks like this.

@ Bean @ LoadBalanced public RestTemplate rebbionRestTemplate () {return new RestTemplate ();}

Therefore, it is possible to inject an interceptor for the RestTemplate we define.

So how does @ LoadBalanced do this? In fact, they are all native operations of spring. The source code of @ LoadBalance is as follows

/ * * Annotation to mark a RestTemplate bean to be configured to use a LoadBalancerClient * @ author Spencer Gibb * / @ Target ({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD}) @ Retention (RetentionPolicy.RUNTIME) @ Documented@Inherited@Qualifierpublic @ interface LoadBalanced {}

Obviously, the annotation @ Qualifier is inherited. We all know that in the past, when xml defined bean, it used Qualifier to specify the instances that you want to rely on certain features. The annotation here is a similar implementation. RestTemplates is injected with @ Autowired and modified by @ LoadBalanced, so only @ LoadBalanced-modified RestTemplate, our target RestTemplate, is injected.

Logic implementation of interceptor

The LoadBalancerInterceptor source code is as follows.

Public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {private LoadBalancerClient loadBalancer; private LoadBalancerRequestFactory requestFactory; public LoadBalancerInterceptor (LoadBalancerClient loadBalancer, LoadBalancerRequestFactory requestFactory) {this.loadBalancer = loadBalancer; this.requestFactory = requestFactory;} public LoadBalancerInterceptor (LoadBalancerClient loadBalancer) {/ / for backwards compatibility this (loadBalancer, new LoadBalancerRequestFactory (loadBalancer));} @ Override public ClientHttpResponse intercept (final HttpRequest request, final byte [] body, final ClientHttpRequestExecution execution) throws IOException {final URI originalUri = request.getURI (); String serviceName = originalUri.getHost () Assert.state (serviceName! = null, "Request URI does not contain a valid hostname:" + originalUri); return this.loadBalancer.execute (serviceName, requestFactory.createRequest (request, body, execution);}}

Intercept request execution

@ Overridepublic T execute (String serviceId, LoadBalancerRequest request) throws IOException {ILoadBalancer loadBalancer = getLoadBalancer (serviceId); / / here the load balancer selects service Server server = getServer (loadBalancer); if (server = = null) {throw new IllegalStateException ("No instances available for" + serviceId);} RibbonServer ribbonServer = new RibbonServer (serviceId, server, isSecure (server, serviceId), serverIntrospector (serviceId) .getmetadata (server)); / / execute request logic return execute (serviceId, ribbonServer, request);}

Let's focus on the getServer method to see how the service is selected

Protected Server getServer (ILoadBalancer loadBalancer) {if (loadBalancer = = null) {return null;} / / return loadBalancer.chooseServer ("default"); / / TODO: better handling of key}

Code configuration random loadBlancer, enter the following code

Public Server chooseServer (Object key) {if (counter = = null) {counter = createCounter ();} counter.increment (); if (rule = = null) {return null;} else {try {/ / use configuration corresponding payload rule selection service return rule.choose (key);} catch (Exception e) {logger.warn ("LoadBalancer [{}]: Error choosing server for key {}", name, key, e); return null;}

RandomRule is configured here, so enter the RandomRule code

Public Server choose (ILoadBalancer lb, Object key) {if (lb = = null) {return null;} Server server = null; while (server = = null) {if (Thread.interrupted ()) {return null;} / / get the list of available services List upList = lb.getReachableServers (); List allList = lb.getAllServers (); / / A random number int serverCount = allList.size (); if (serverCount = = 0) {/ * No servers. End regardless of pass, because subsequent passes * only get more restrictive. * / return null;} int index = rand.nextInt (serverCount); server = upList.get (index); if (server = = null) {/ * The only time this should happen is if the server list were * somehow trimmed. This is a transient condition. Retry after * yielding. * / Thread.yield (); continue;} if (server.isAlive ()) {return (server);} / / Shouldn't actually happen.. But must be transient or a bug. Server = null; Thread.yield ();} return server;}

Random load rules are very simple, random integer selection of services, and finally achieve random load balancing. We can configure different Rule to achieve different load patterns.

The above is all the contents of the article "how to use Ribbon in springcloud". Thank you for reading! I believe we all have a certain understanding, hope to share the content to help you, if you want to learn more knowledge, welcome to follow the industry information channel!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report