Eine Vorstudie zum Ribbon-Prinzip

Machen Sie es sich zur Gewohnheit, gemeinsam zu schreiben! Dies ist der 11. Tag meiner Teilnahme an der „Nuggets Daily New Plan·April Update Challenge“, klicken Sie hier, um die Veranstaltungsdetails anzuzeigen

Eine Vorstudie zum Ribbon-Prinzip

Entschlossenheit ist der Beginn des Erfolgs

So verwenden Sie die Multifunktionsleiste

    Die Möglichkeit, Ribbon zu verwenden, besteht darin, der RestTemplate-Methode eine **@LoadBalanced ** -Anmerkung hinzuzufügen, und dann können Lastausgleichsanforderungen gestellt werden, wenn diese Methode eine Anforderung stellt.

@Configuration
public class RestConfig {
    @LoadBalanced
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}
复制代码

Prinzipdiagramm des Lastausgleichs

Bild.png

Verwendung der RestTemplate-Methode

    Wenn Sie Ribbon nicht verwenden, können Sie bei einer HTTP-Anforderung direkt ein neues RestTemplate- Objekt erstellen und es über die entsprechende Methode wie z. B. getForEntity() aufrufen.
Bild.png

@Override
public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, 
                                          Object... uriVariables)
        throws RestClientException {
    RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
    ResponseExtractor<ResponseEntity<T>> responseExtractor = 
        responseEntityExtractor(responseType);
    // 执行请求
    return nonNull(execute(url, HttpMethod.GET, requestCallback, 
                           responseExtractor, uriVariables));
}
复制代码

@LoadBalanced-Annotationsquellcode

/**
 * Annotation to mark a RestTemplate bean to be configured to use a LoadBalancerClient.
 */
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface LoadBalanced {
}
复制代码

Ein Blick auf die Anmerkung soll zeigen, dass diese Anmerkung verwendet wird, um LoadBalancerClient     in der RestTemplate-Klasse zu konfigurieren.Lassen Sie uns nach der LoadBalancerClient - Schnittstelle suchen, um zu sehen, welches Paket package org.springframework.cloud.client.loadbalancer;

public interface LoadBalancerClient extends ServiceInstanceChooser {
    // 执行负载均衡器指定的服务请求
	<T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException;
    // 执行负载均衡器指定的服务请求
	<T> T execute(String serviceId, ServiceInstance serviceInstance,
			LoadBalancerRequest<T> request) throws IOException;
    // 创建一个具有真实主机和端口的适当URI,供系统使用。
    // 一些系统使用带有逻辑服务名称的URI作为主机,
    // 例如 http://myservice/path/to/service
    // 这将用ServiceInstan中的主机:端口替换服务名称
	URI reconstructURI(ServiceInstance instance, URI original);
}
/**
 * 通过负载均衡器选择一个服务实例
 */
public interface ServiceInstanceChooser {
	ServiceInstance choose(String serviceId);
}
复制代码

Ribbon-Clientkonfigurationsklasse RibbonClientConfiguration

public class RibbonClientConfiguration {
// 客户端链接超时
public static final int DEFAULT_CONNECT_TIMEOUT = 1000;

// 客户端读取超时
public static final int DEFAULT_READ_TIMEOUT = 1000;

@RibbonClientName
private String name = "client";

@Autowired
private PropertiesFactory propertiesFactory;
    ......
}
复制代码

1. RibbonClientConfig-Clientkonfigurationsklasse

// Ribbon 客户端配置类
@Bean
@ConditionalOnMissingBean
public IClientConfig ribbonClientConfig() {
    DefaultClientConfigImpl config = new DefaultClientConfigImpl();
    config.loadProperties(this.name);
    config.set(CommonClientConfigKey.ConnectTimeout, DEFAULT_CONNECT_TIMEOUT);
    config.set(CommonClientConfigKey.ReadTimeout, DEFAULT_READ_TIMEOUT);
    config.set(CommonClientConfigKey.GZipPayload, DEFAULT_GZIP_PAYLOAD);
    return config;
}
复制代码

2. RibbonRule-Regeln

// Ribbon 规则类
@Bean
@ConditionalOnMissingBean
public IRule ribbonRule(IClientConfig config) {
    if (this.propertiesFactory.isSet(IRule.class, name)) {
        return this.propertiesFactory.get(IRule.class, config, name);
    }
    ZoneAvoidanceRule rule = new ZoneAvoidanceRule();
    rule.initWithNiwsConfig(config);
    return rule;
}
复制代码

3. RibbonPing Ping-Methode

// Ribbon Ping类
@Bean
@ConditionalOnMissingBean
public IPing ribbonPing(IClientConfig config) {
    if (this.propertiesFactory.isSet(IPing.class, name)) {
        return this.propertiesFactory.get(IPing.class, config, name);
    }
    return new DummyPing();
}

复制代码

4. Ribbon RibbonServerList-Dienstliste

// Ribbon 服务列表
@Bean
@ConditionalOnMissingBean
@SuppressWarnings("unchecked")
public ServerList<Server> ribbonServerList(IClientConfig config) {
    if (this.propertiesFactory.isSet(ServerList.class, name)) {
        return this.propertiesFactory.get(ServerList.class, config, name);
    }
    ConfigurationBasedServerList serverList = new ConfigurationBasedServerList();
    serverList.initWithNiwsConfig(config);
    return serverList;
}
复制代码

5. RibbonServerListUpdater Ribbon-Dienstlistenaktualisierungsprogramm

// Ribbon 服务列表更新器,默认选择的是 PollingServerListUpdater 定时拉取
@Bean
@ConditionalOnMissingBean
public ServerListUpdater ribbonServerListUpdater(IClientConfig config) {
    return new PollingServerListUpdater(config);
}

复制代码

6. Load Balancer für den RibbonLoadBalancer-Dienst

// Ribbon 服务的负载均衡器
@Bean
@ConditionalOnMissingBean
public ILoadBalancer ribbonLoadBalancer(IClientConfig config,
        ServerList<Server> serverList, ServerListFilter<Server> serverListFilter,
        IRule rule, IPing ping, ServerListUpdater serverListUpdater) {
    if (this.propertiesFactory.isSet(ILoadBalancer.class, name)) {
        return this.propertiesFactory.get(ILoadBalancer.class, config, name);
    }
    return new ZoneAwareLoadBalancer<>(config, rule, ping, serverList,
            serverListFilter, serverListUpdater);
}
复制代码

7. Dienstlistenfilter RibbonServerListFilter

// 服务列表筛选器
@Bean
@ConditionalOnMissingBean
@SuppressWarnings("unchecked")
public ServerListFilter<Server> ribbonServerListFilter(IClientConfig config) {
    if (this.propertiesFactory.isSet(ServerListFilter.class, name)) {
        return this.propertiesFactory.get(ServerListFilter.class, config, name);
    }
    ZonePreferenceServerListFilter filter = new ZonePreferenceServerListFilter();
    filter.initWithNiwsConfig(config);
    return filter;
}

复制代码

Kernkonfigurationsklasse für die Load Balancer-Initialisierung

Configuration
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration {

@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();

@Autowired(required = false)
private List<LoadBalancerRequestTransformer> transformers = Collections.emptyList();
// 负载均衡 RestTemplate 初始化配置
@Bean
public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
        final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
    return () -> restTemplateCustomizers.ifAvailable(customizers -> {
        for (RestTemplate restTemplate : 
             LoadBalancerAutoConfiguration.this.restTemplates) {
            for (RestTemplateCustomizer customizer : customizers) {
                customizer.customize(restTemplate);
            }
        }
    });
}

@Bean
@ConditionalOnMissingBean
public LoadBalancerRequestFactory loadBalancerRequestFactory(
        LoadBalancerClient loadBalancerClient) {
    return new LoadBalancerRequestFactory(loadBalancerClient, this.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 restTemplate -> {
            List<ClientHttpRequestInterceptor> list = new ArrayList<>(
                    restTemplate.getInterceptors());
            list.add(loadBalancerInterceptor);
            restTemplate.setInterceptors(list);
        };
    }
                        ......
}
复制代码

Load-Balancer-Interceptor LoadBalancerInterceptor

@Override
public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
        final ClientHttpRequestExecution execution) throws IOException {
    // 解析服务地址
    final URI originalUri = request.getURI();
    // 请求服务名称
    String serviceName = originalUri.getHost();
    // 执行的请求流程
    return this.loadBalancer.execute(serviceName,
            this.requestFactory.createRequest(request, body, execution));
}
复制代码

Der Load Balancer führt die Anfrage loadBalancer.execute aus

public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint)
        throws IOException {
    // 获取负载均衡器
    ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
    // 通过负载均衡器选择可利用的服务
    Server server = getServer(loadBalancer, hint);
    if (server == null) {
        throw new IllegalStateException("No instances available for " + serviceId);
    }
    // 创建 Ribbon 服务
    RibbonServer ribbonServer = new RibbonServer(serviceId, server,
            isSecure(server, serviceId),
            serverIntrospector(serviceId).getMetadata(server));
    // 真正的执行请求
    return execute(serviceId, ribbonServer, request);
}
复制代码

der eigentliche Ausführungsantrag

    Ausführung über LoadBalancerRequest-Anfrage

@Override
public <T> T execute(String serviceId, ServiceInstance serviceInstance,
        LoadBalancerRequest<T> request) throws IOException {
    Server server = null;
    if (serviceInstance instanceof RibbonServer) {
        server = ((RibbonServer) serviceInstance).getServer();
    }
    // 如果服务为空的情况下那么就抛出异常没有实例可以使用
    if (server == null) {
        throw new IllegalStateException("No instances available for " + serviceId);
    }

    RibbonLoadBalancerContext context = this.clientFactory
            .getLoadBalancerContext(serviceId);
    RibbonStatsRecorder statsRecorder = new RibbonStatsRecorder(context, server);

    try {
        // 真正的请求方法
        T returnVal = request.apply(serviceInstance);
        statsRecorder.recordStats(returnVal);
        return returnVal;
    }
    return null;
}

复制代码

ServiceRequestWrapper kapselt Anfragen für Dienstanfragen

@Override
public ListenableFuture<ClientHttpResponse> intercept(final HttpRequest request,
        final byte[] body, final AsyncClientHttpRequestExecution execution)
        throws IOException {
    // 获取请求的路径URI
    final URI originalUri = request.getURI();
    // 获取服务的地址
    String serviceName = originalUri.getHost();
    return this.loadBalancer.execute(serviceName,
            new LoadBalancerRequest<ListenableFuture<ClientHttpResponse>>() {
                // 执行的方法
                @Override
                public ListenableFuture<ClientHttpResponse> apply(
                        final ServiceInstance instance) throws Exception {
                    // 封装请求
                    HttpRequest serviceRequest = new ServiceRequestWrapper(request,
                            instance, AsyncLoadBalancerInterceptor.this.loadBalancer);
                    // 进行服务调用执行访问
                    return execution.executeAsync(serviceRequest, body);
                }

            });
}
复制代码

Zusammenfassung

    Tatsächlich wird die RestTemplate-Anforderung vom Interceptor gekapselt, und dann wird die Anforderungsadresse in die entsprechende verfügbare Dienstadresse geparst, und dann wird die Anforderung gestellt, aber die Dienstinstanz dieser Anforderung wird vom Load Balancer ausgewählt

Supongo que te gusta

Origin juejin.im/post/7085158150466175013
Recomendado
Clasificación