微服务之Ribbon原理解析

客户端负载均衡 Ribbon RibbonLoadBalanceClient是的实现类,它用来执行最终的负载均衡请求。其中,的一个choose()方法用于选择具体的服务实例,其内部是通过方法交给完成的。是一个接口,该接口定义了一系列实现负载均衡的方法。接口的实现类结果如下图所示。 阅读详情

Ribbon原理解析

1.引言

什么是Ribbon

  • Ribbon是Netflix公司的一个负载均衡项目,可以在进行服务调用时做负载均衡;

2.Ribbon基本使用

Ribbon结合Http

  • Ribbon通常和Http请求结合,对Http请求进行负载均衡;最简单的使用如下,通过注入RestTemplate,并且打上@LoadBlanced注解,即可得到一个带有负载均衡效果的RestTemplate
@Configuration
public class HttpConfiguration {
    @Bean
    @LoadBalanced
    public RestTempttpTlate restTemplate() {
        return new RestTemplate();
    }
}
  • 使用时,只需要把RestTemplate发送请求时的URL中的主机名host替换为服务提供方的名字;那么在调用时,就会自动进行负载均衡
@RestController
public class TestController {
    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/test")
    public String test() {
        //HelloServiceProvider为服务提供方名称
        return restTemplate.getForEntity("http://HelloServiceProvider/hello?info=okkk", String.class).getBody();
    }
}
  • 当然,这里还有配置好注册中心,将服务提供方和消费方都注册到注册中心上

3.Ribbon和RestTemplate整合原理

原理概述

  • RestTemplate相信大家都有用过,相当于一个发送Http请求的工具;但是为何引入@LoadBlanced就可以实现负载均衡了呢?
  • 简单来说:
    • RestTemplate在发送请求过程中,会构造一条具有多个拦截器的执行链
    • Ribbon可以借助拦截器,在RestTemplate中加入一个LoadBalancerInterceptor拦截器;
    • 这样在发送请求时,请求经过拦截器,Ribbon就可以根据请求的URL中的主机名(即服务名, 下面的HelloServiceProvider),去注册中心拿到提供该服务的所有主机
    • 并且根据负载均衡策略,选择其中一个,然后把服务名替换为真正的IP,接着继续执行下一个拦截器,最终发送请求
//restTempalte负载均衡发送请求示例,其中HelloServiceProvider为服务名,需要被替换为真实IP地址
restTemplate.getForEntity("http://HelloServiceProvider/hello?info=okkk", String.class).getBody();

源码解析

  • Spring的IOC容器在刷新过程中,会执行到如下过程;该过程是bean容器刷新比较后面的一步,这是大部分单例bean都已经实例化完成;会遍历所有实现了SmartInitializingSingleton接口的bean,并调用它的afterSingletonsInstantiated方法
//DefaultListableBeanFactory#preInstantiateSingletons部分代码

for (String beanName : beanNames) {
    Object singletonInstance = getSingleton(beanName);
    if (singletonInstance instanceof SmartInitializingSingleton) {
        final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                smartSingleton.afterSingletonsInstantiated();
                return null;
            }, getAccessControlContext());
        }
        else {
            //调用afterSingletonsInstantiated方法
            smartSingleton.afterSingletonsInstantiated();
        }
    }
}
  • LoadBalancerAutoConfiguration类:SpringCloud中的一个自动配置类,负责负载均衡方面的配置,会向容器中注入如下几个Bean对象(截取部分源码); 其中第一个是SmartInitializingSingleton类型的对象,也就是上面所说的接口;所以它的方法会在上面的过程中被调用;具体方法内容看下面注释;(下面这两个Bean对象都是lambda表达式的形式,注意别看混了)
//LoadBalancerAutoConfiguration

public class LoadBalancerAutoConfiguration {
    
    @Bean //参数传入的是restTemplateCustomizers,这个应该是有ApplicationContext进行注入所有的customizer
    public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
        final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
        return () -> restTemplateCustomizers.ifAvailable(customizers -> {
            //遍历所有RestTemplate对象
            for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
                for (RestTemplateCustomizer customizer : customizers) {
                    //调用customizer#customize方法,对restTemplate做一些操作,具体看下面的Bean
                    customizer.customize(restTemplate);
                }
            }
        });
    }

    //注入customizer对象
    @Bean
    @ConditionalOnMissingBean
    public RestTemplateCustomizer restTemplateCustomizer(
        final LoadBalancerInterceptor loadBalancerInterceptor) {
        return restTemplate -> {
            //这就是上面的Bean执行customize方法,拿到该restTemplate所有拦截器
            List<ClientHttpRequestInterceptor> list = new ArrayList<>(
                restTemplate.getInterceptors());
            //加入负载均衡拦截器
            list.add(loadBalancerInterceptor);
            //重新设置拦截器给restTemplate
            restTemplate.setInterceptors(list);
        };
    }
}
  • 通过上面的步骤,restTemplate中就会被注入了LoadBalancerInterceptor拦截器;发送http请求时会经过拦截器,就可以将URL的服务名替换为负载均衡过后的真正IP地址了

4.负载均衡流程

核心类

  • LoadBalanceClient:上面说到Http请求发送时,会经过Ribbon的LoadBalancerInterceptor拦截器进行负载均衡,该拦截器会把请求交给LoadBalancerClient进行负载均衡;该类是负载均衡客户端,也可以看成负载均衡的入口;采用的实现类是RibbonLoadBalancerClient,看一下继承图

在这里插入图片描述

  • ILoadBalancer:RibbonLoadBalancerClient内部的execute方法会以Http请求的服务名为key,找到ILoadBalancer对象,这个ILoadBalancer就是专门负责这个服务的负载均衡;继承图如下
    • DynamicServerListLoadBalance: 具有ServerList功能的ILoadBalance,ServerList后面会讲,它能够维护和更新本服务对应的所有主机信息
    • ZoneAwareLoadBalance: 该类是DynamicServerListLoadBalancer的子类,具有区域感知(ZoneAware)功能,它可以把所有主机根据请求状况进行区域划分,当主机请求超时时,它会把相关主机从活跃区域踢出,避免影响服务质量;详情可看类上的注释
/**
 * Load balancer that can avoid a zone as a whole when choosing server. 
 *<p>
 * The key metric used to measure the zone condition is Average Active Requests,
which is aggregated per rest client per zone. It is the
total outstanding requests in a zone divided by number of available targeted instances (excluding circuit breaker tripped instances).
This metric is very effective when timeout occurs slowly on a bad zone.
<p>
The  LoadBalancer will calculate and examine zone stats of all available zones. If the Average Active Requests for any zone has reached a configured threshold, this zone will be dropped from the active server list. In case more than one zone has reached the threshold, the zone with the most active requests per server will be dropped.
Once the the worst zone is dropped, a zone will be chosen among the rest with the probability proportional to its number of instances.
A server will be returned from the chosen zone with a given Rule (A Rule is a load balancing strategy, for example {@link AvailabilityFilteringRule})
For each request, the steps above will be repeated. That is to say, each zone related load balancing decisions are made at real time with the up-to-date statistics aiding the choice.
 */

在这里插入图片描述

  • IRule:代表负载均衡策略,ILoadBalancer的负载均衡由它进行处理,Ribbon内置了多种负载均衡策略,都实现了该接口

在这里插入图片描述

源码流程

  • 前面说了负载均衡入口是RestTemplate拦截器,所以看一下LoadBalancerInterceptor的intercept方法
//LoadBalancerInterceptor#intercept
@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);
    //拿到loadBalancer,它是一个LoadBalancerClient类型对象,并调用execute方法
    return this.loadBalancer.execute(serviceName,
                                     this.requestFactory.createRequest(request, body, execution));
}
  • 上述LoadBalancerClient实际用的实现类是RibbonLoadBalancerClient,先看一下其父接口LoadBalancerClient的方法
public interface LoadBalancerClient extends ServiceInstanceChooser {
    //用于执行http负载均衡请求
	<T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException;

	<T> T execute(String serviceId, ServiceInstance serviceInstance,
			LoadBalancerRequest<T> request) throws IOException;
    //重构URI,替换服务名
	URI reconstructURI(ServiceInstance instance, URI original);

}
  • RibbonLoadBalancerClient的execute方法如下
//RibbonLoadBalancerClient#execute
public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint)
    throws IOException {
    //根据serviceId拿到ILoadBalancer,交由它进行负载均衡
    ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
    //根据loadBalancer拿到真正的服务提供者
    Server server = getServer(loadBalancer, hint);
    if (server == null) {
        throw new IllegalStateException("No instances available for " + serviceId);
    }
    //包装Server
    RibbonServer ribbonServer = new RibbonServer(serviceId, server,
                                                 isSecure(server, serviceId),
                                                 serverIntrospector(serviceId).getMetadata(server));

    //执行请求
    return execute(serviceId, ribbonServer, request);
}

//RibbonLoadBalancerClient#getLoadBalancer
protected ILoadBalancer getLoadBalancer(String serviceId) {
	//从clientFactory中获得该服务对应的ILoadBalancer	
    return this.clientFactory.getLoadBalancer(serviceId);
}
  • 这里ILoadBalancer loadBalancer = getLoadBalancer(serviceId)这句代码是重点,它会根据当前URL中的serviceId,先从工厂中拿到对应的ApplicationContext(首次取没有则新建容器并refresh),接着再从IOC容器中拿到ILoadBalancer类型的bean;由于调用栈比较复杂,下面只摘取部分重点
protected ILoadBalancer getLoadBalancer(String serviceId) {
    //从SpringClientFactory工厂中获取该serviceId对应的ILoadBalancer
    return this.clientFactory.getLoadBalancer(serviceId);
}

public ILoadBalancer getLoadBalancer(String name) {
    return getInstance(name, ILoadBalancer.class);
}

public <T> T getInstance(String name, Class<T> type) {
    //获取服务名对应的ApplicationContext
    AnnotationConfigApplicationContext context = getContext(name);
    if (BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context,
                                                            type).length > 0) {
        //从ApplicationContext中后去ILoadBalancer类型的bean
        return context.getBean(type);
    }
    return null;
}

protected AnnotationConfigApplicationContext getContext(String name) {
    //大致逻辑就是直接容map中拿,没有则创建一个并缓存
    if (!this.contexts.containsKey(name)) {
        synchronized (this.contexts) {
            if (!this.contexts.containsKey(name)) {
                this.contexts.put(name, createContext(name));
            }
        }
    }
    return this.contexts.get(name);
}
  • 因此可以看出,Ribbon中,每个服务会对应一个ApplicationContext,内部维护了各种bean信息,包括负责负载均衡的ILoadBalancer;每个ApplicationContext内部都有自己的ILoadBalancer
  • getServer()方法最终会调用ILoadBalancer的chooseServer方法,代码如下
//BaseLoadBalancer#chooseServer
public Server chooseServer(Object key) {
    if (counter == null) {
        counter = createCounter();
    }
    counter.increment();
    //如果没有配置rule则返回
    if (rule == null) {
        return null;
    } else {
        try {
            //由rule执行真正的负载均衡
            return rule.choose(key);
        } catch (Exception e) {
            logger.warn("LoadBalancer [{}]:  Error choosing server for key {}", name, key, e);
            return null;
        }
    }
}
  • 下面以RandomRule为例看一下choose方法,篇幅原因只保留部分代码,详情可自己debug
//RandomRule#choose
public Server choose(ILoadBalancer lb, Object key) {
    if (lb == null) {
        return null;
    }
    Server server = null;

    while (server == null) {
        //... 从ILoadBalancer中拿到该服务对应的所有Server
        List<Server> upList = lb.getReachableServers();
        List<Server> allList = lb.getAllServers();
		//... 产生随机数,并拿到对应Server
        int index = chooseRandomInt(serverCount);
        server = upList.get(index);
		//...

        if (server.isAlive()) {
            return (server);
        }
		//...
    }
    return server;
}

小结

  • 这样就完成了负载均衡过程,梳理一下大致流程
    • Http请求经过LoadBalancerInterceptor拦截器,它将调用LoadBalancerClient进行处理
    • LoadBalancerClient(实现类Ribbon``LoadBalancerClient)根据服务名拿到对应的ApplicationContext,并从容器中拿到ILoadBalancer(实际类ZoneAwareLoadBalancer)
    • 从ILoadBalancer中获取服务提供者Server,具体是调用chooseServer方法,内部会使用IRule进行负载均衡,并返回合适的Server
    • IRule才是真正的负载均衡实现接口,Ribbon内置多种默认负载均衡策略
  • 以上流程讲述了从RestTemplate与Ribbon整合,到一次请求发起实现负载均衡的大致流程;但是还不涉及Ribbon如何维护注册中心中的服务及对应的主机列表操作;即Ribbon需要定时获取注册中心的服务信息,供负载均衡使用

5.服务列表拉取和刷新

核心类

  • ServerList:该接口用于表示向注册中心拉取服务信息
public interface ServerList<T extends Server> {
    public List<T> getInitialListOfServers();
    
    public List<T> getUpdatedListOfServers();   
}

源码流程

  • 前面说到过,每个服务都有自己的ILoadBalancer(默认是ZoneAwareLoadBalancer),其父类为DynamicServerListLoadBalancer,它会负责服务对应的主机列表信息;
  • DynamicServerListLoadBalancer在创建过程中,会调用如下方法进行服务列表初始化
public DynamicServerListLoadBalancer(IClientConfig clientConfig, IRule rule, IPing ping,
                                     ServerList<T> serverList, ServerListFilter<T> filter,
                                     ServerListUpdater serverListUpdater) {
    super(clientConfig, rule, ping);
    this.serverListImpl = serverList;
    this.filter = filter;
    this.serverListUpdater = serverListUpdater;
    if (filter instanceof AbstractServerListFilter) {
        ((AbstractServerListFilter) filter).setLoadBalancerStats(getLoadBalancerStats());
    }
    //调用该方法进行主机列表初始化
    restOfInit(clientConfig);
}

void restOfInit(IClientConfig clientConfig) {
    //...
    updateListOfServers();
    //...
}

//这是另一个构造方法,可能是使用自定义配置时
public DynamicServerListLoadBalancer(IClientConfig clientConfig) {
    initWithNiwsConfig(clientConfig);
}
    
//DynamicServerListLoadBalancer#initWithNiwsConfig
public void initWithNiwsConfig(IClientConfig clientConfig) {
    try {
        super.initWithNiwsConfig(clientConfig);
        //从配置文件中拿到NIWSServerListClassName对应的值,应该是拿到配置的ServerList实现类,负责维护服务信息
        //当注册中心不同时,应该可以动态替换
        String niwsServerListClassName = clientConfig.getPropertyAsString(
            CommonClientConfigKey.NIWSServerListClassName,
            DefaultClientConfigImpl.DEFAULT_SEVER_LIST_CLASS);
		//实例化ServerList
        ServerList<T> niwsServerListImpl = (ServerList<T>) ClientFactory
            .instantiateInstanceWithClientConfig(niwsServerListClassName, clientConfig);
        //保存
        this.serverListImpl = niwsServerListImpl;
		//...
		//拿到ServerListUpdaterClassName配置的类
        String serverListUpdaterClassName = clientConfig.getPropertyAsString(
            CommonClientConfigKey.ServerListUpdaterClassName,
            DefaultClientConfigImpl.DEFAULT_SERVER_LIST_UPDATER_CLASS
        );
		//实例化
        this.serverListUpdater = (ServerListUpdater) ClientFactory
            .instantiateInstanceWithClientConfig(serverListUpdaterClassName, clientConfig);
		//在该函数中,会进行服务初始化
        restOfInit(clientConfig);
    } catch (Exception e) {
        throw new RuntimeException(
            "Exception while initializing NIWSDiscoveryLoadBalancer:"
            + clientConfig.getClientName()
            + ", niwsClientConfig:" + clientConfig, e);
    }
}
  • 接下来调用DynamicServerListLoadBalancer#restOfInit方法,最终会调用updateListOfServers方法进行列表更新
@VisibleForTesting
public void updateListOfServers() {
    List<T> servers = new ArrayList<T>();
    //判断serverListImpl是否有配置
    if (serverListImpl != null) {
        //拉取所有的Servers
        servers = serverListImpl.getUpdatedListOfServers();
        LOGGER.debug("List of Servers for {} obtained from Discovery client: {}",
                     getIdentifier(), servers);
		//如果由过滤规则,对Server进行过滤
        if (filter != null) {
            servers = filter.getFilteredListOfServers(servers);
            LOGGER.debug("Filtered List of Servers for {} obtained from Discovery client: {}",
                         getIdentifier(), servers);
        }
    }
    //更新本地的ServerList
    updateAllServerList(servers);
}

@Override
public List<DiscoveryEnabledServer> getUpdatedListOfServers() {
    List<DiscoveryEnabledServer> servers = setZones(
        this.list.getUpdatedListOfServers());	//这里才是真正获取主机的方法, list是一个ServerList类型的变量,根据注册中心不同,具体实现不同
    return servers;
}
  • 如果注册中心使用Eureka,那么ServerList使用的是DiscoveryEnabledNIWSServerList,如果是其他注册中心,可以替换,下面看一下它的getUpdatedListOfServers方法,层层调用后进入如下方法,篇幅原因省略部分代码
//DiscoveryEnabledNIWSServerList#obtainServersViaDiscovery
private List<DiscoveryEnabledServer> obtainServersViaDiscovery() {
    List<DiscoveryEnabledServer> serverList = new ArrayList<DiscoveryEnabledServer>();
	//...
	//拿到Eureka客户端,它可以进行服务拉取,注册等
    EurekaClient eurekaClient = eurekaClientProvider.get();
    if (vipAddresses!=null){
        for (String vipAddress : vipAddresses.split(",")) {
            // if targetRegion is null, it will be interpreted as the same region of client
            List<InstanceInfo> listOfInstanceInfo = eurekaClient.getInstancesByVipAddress(vipAddress, isSecure, targetRegion);
            for (InstanceInfo ii : listOfInstanceInfo) {
                if (ii.getStatus().equals(InstanceStatus.UP)) {
					//... 封装服务并保存
                    DiscoveryEnabledServer des = createServer(ii, isSecure, shouldUseIpAddr);
                    serverList.add(des);
                }
            }
            if (serverList.size()>0 && prioritizeVipAddressBasedServers){
                break; // if the current vipAddress has servers, we dont use subsequent vipAddress based servers
            }
        }
    }
    return serverList;
}

6.服务列表更新

  • Ribbon服务列表更新是通过定时任务来完成的;相关类是PollingServerListUpdater;可以看一下它的start方法
public synchronized void start(final UpdateAction updateAction) {
    if (isActive.compareAndSet(false, true)) {
        //创建定时任务
        final Runnable wrapperRunnable = new Runnable() {
            @Override
            public void run() {
                //...
                try {
                    //更新主机信息
                    updateAction.doUpdate();
                    lastUpdated = System.currentTimeMillis();
                } catch (Exception e) {
                    logger.warn("Failed one update cycle", e);
                }
            }
        };
		//设置定时任务
        scheduledFuture = getRefreshExecutor().scheduleWithFixedDelay(
            wrapperRunnable,
            initialDelayMs,
            refreshIntervalMs,
            TimeUnit.MILLISECONDS
        );
    }
}
  • 另外,Ribbon还会定期去Ping每一个主机,保证主机存活

7.服务注册中心

  • Ribbon默认的服务注册中心是eureka,如果想用nacos做服务注册中心,可以直接添加nacos依赖即可;
  • nacos中包含了Ribbon,并且提供了NacosServerList来与注册中心进行信息拉取
  • 而Eureka中使用的是DiscoveryEnabledNIWSServerList
  • 以上纯属猜测,具体需要自己实践一下;但Ribbon的注册中心替换原理应该类似,通过提供ServerList来实现
2021升级版微服务教程6—Ribbon使用+原理+整合Nacos权重+实战优化 一篇搞定 2021升级版SpringCloud教程从入门到实战精通「H版&alibaba&链路追踪&日志&事务&锁」 教程全目录「含视频」:https://gitee.com/bingqilinpeishenme/Java-Wiki Ribbon使用+原理+整合Nacos权重+实战优化 一篇搞定 Ribbon基本使用 简介 Ribbon是一个客户端负载均衡工具,封装Netflix Ribbon组件,能够提供客户端负载均衡能力。 理解Ribbon最重要的就是理解客户端这个概念 阅读详情

相关推荐

Ribbon架构和原理

文章重点介绍了Ribbon一个久经考验的功能:区域感知负载均衡器(Zone Aware Load Balancer)。 区域感知负载均衡器内置电路跳闸逻辑,可被配置基于区域同源关系(Zone Affinity,也就是更倾向于选择发出调用的服务所在的托管区域内,这样可用降低延迟,节省成本)选择目标服务实例。它监控每个区域中运行的实例的运 维行为,而且能够实时快速丢弃一整个区域。在面对整个区域的故障时,这帮我们提升了弹性。

Ribbon实战与原理剖析

通过实现IRule接口可以自定义负载策略,主要的选择服务逻辑在 choose 方法中。}

qq_38639813的博客 2846

手把手教你配置MCAL中的CAN模块:从基础参数到实战避坑指南

本文提供了一份详尽的MCAL CAN模块配置指南,涵盖从基础参数设置到实战避坑的全过程。文章深入解析了CAN控制器核心参数、硬件对象配置、数据流处理及常见问题排查,并结合源码分析,帮助嵌入式开发者构建稳定高效的CAN通信链路,是汽车电子领域通信开发的实用参考。

weixin_29165465的博客 336

Ribbon原理解析

一. 核心接口 ILoadBalancer Ribbon通过ILoadBalancer接口对外提供统一的选择服务器(Server)的功能,此接口会根据不同的负载均衡策略(IRule)选择合适的Server返回给使用者。其核心方法如下: public interface ILoadBalancer { public void addServers(List<Server> newServers); public Server chooseServer(Object key);

奋斗吧_-小青年 2664

UR10e+D435+ag95夹爪 gazebo 仿真记录(一)

学习仿真环境gazebo下利用UR10e机械臂搭建模拟平台,此博客用于记录搭建过程!!主要参考光头明明、总有一天全城的人都要高看我们和bug404_三位博主。最终自己功能包的主要参考了bug404_的ur_platform,感觉这个结构比较合理。运行环境:Ubuntu18.04+Ros-melodic+Gazebo9。

Forbiven的博客 6328

操作不能完成 (错误 0x00000709) 共享打印机无法连接解决办法

环境:windows Server 2012 + Win10 客户端 问题:使用计算机名和IP地址可以正常连接打印机,但是使用另外的A记录或CN记录无法连接,报此错误 原因:这是打印服务DNS解析的问题 故障补充:假设你的服务器电脑名称叫print01,但是你又建了一条A记录或者CNname 叫PR01,就会发现使用额外的A记录或CN记录就无法连接 故障截图: 操作不能完成 (错误...

瑞哥的博客 3万+

Ribbon框架原理及解析

Ribbon框架原理及解析

多看多听多总结 1103

Comsol固体力学仿真﹣﹣受均匀内压的厚壁球壳弹塑性分析(加载卸载全流程)

COMSOL固体力学及结构力学仿真较少,故而查询了有关资料,才建立了如下模型。图4 加载卸载全历程中的冯米塞斯应力变化。该有限元模型是通过扫掠而得的结构化网格。图2 加载卸载全历程中的塑型区域变化。图3 加载卸载全历程中的位移应力变化。图6 关键节点第一,第三主应力分布。图5 关键节点应力场与塑性区分布。《弹塑性力学》大作业,记录一下。图1 球体的有限元网格模型。

weixin_62236383的博客 1484

SpringCloud——Ribbon 微服务负载均衡原理解析

首先,order-service发送请求,但请求会被Ribbon给拦截,它会识别要发送请求的对象是哪个模块的,然后向我们的eureka-server去要,eureka-server有就会返回给它,然后Ribbon将HTTP请求进行加工处理,通过自身的负载均衡算法,去挑选其中一个user-service发送请求,再得到返回的结果,然后将结果返回给order-service。不难猜想,中间一定有一个角色,帮我们实现了这个功能,它就是我们上面所提到的Ribbon,我们来看下面这幅图,就是Ribbon的工作原理。

m0_70325779的博客 624

Windows Server 2016上,手把手教你搭建MDT 8456自动化部署环境(含ADK 2004与WDS配置)

本文详细指导在Windows Server 2016上搭建MDT 8456自动化部署环境,涵盖ADK 2004与WDS配置全流程。通过标准化操作系统部署、应用程序静默安装和驱动程序注入,实现企业级自动化部署解决方案,显著提升IT运维效率。特别针对兼容性问题和权限陷阱提供实战解决方案。

weixin_29876033的博客 386

研发工作量科学量化评估模型:从多维系数到等级落地指南

摘要:本文提出了一套基于多维系数的科学量化评估模型,用于精准评估软件开发工作量。该模型从需求复杂度、技术难度、质量要求和依赖风险四个核心维度进行量化评估,通过系数乘积计算综合工作量。文章详细说明了各维度的系数区间划分标准,并演示了从基础工作量估算到综合系数计算的具体步骤。该模型通过结构化评估过程,将主观经验转化为客观量化指标,帮助团队提高工作量评估的准确性,增强项目交付的可预测性。其价值在于使评估过程透明化、结构化和可追溯,从而减少项目延期风险,优化资源规划。

友莘居士的博客 1681

SpringCloud(7)Ribbon 与负载均衡

Ribbon SpringCloud Ribbon 是基于NetFlix Ribbon实现的一套客户端负载均衡的工具 简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法和服务调用。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer (简称LB) 后面所有的机器,Ribbon 会自动帮助你基于某种规则(如 简单轮询,随机连接等 )去连接这些机器。我们容易使用Ribbon 实现自定义负载均衡的算法

OVO_LQ_Start的博客 711

【Flutter 问题系列第 85 篇】Xcode 运行 Flutter 提示 The Dart VM Service was not discovered after 60 seconds.

在 Xcode 上运行 Flutter 时提示 `The Dart VM Service was not discovered after 60 seconds. This is taking much longer than expected...`,意思是 `60秒后未发现Dart虚拟机服务。这比预期的要长得多`

“Allen Su”的博客 2235

微服务精通之Ribbon原理解析

文章目录前言一、Ribbon是什么?二、负载均衡是什么?三、Ribbon原理解析1.Ribbon工作流程2.Eureka高可用架构3.Eureka服务端缓存架构4.Eureka健康检查5.Eureka分区四、Eureka实战1.创建Eureka服务端(1)创建名为eureka-server的maven工程(2)引入Eureka-server依赖(3)创建启动类(4)创建application.yml配置文件2.创建Eureka客户端(1)创建名为service-hi的maven工程(2)引入Eureka-c

欢迎关注同名公众号,一起探索Java技术的奥秘,共同成长! 1441

手把手教你学Simulink——基于Simulink的无位置传感器PMSM滑模观测器(SMO)控制

本文基于Simulink平台实现无位置传感器PMSM滑模观测器(SMO)控制,解决了传统机械位置传感器存在的成本高、体积大、抗干扰差等问题。SMO通过滑模切换函数估算反电动势,进而获得转子位置和速度,具有强鲁棒性(参数变化20%误差仅0.4°)和良好低速性能(50rpm转矩衰减<5%)。文章详细介绍了PMSM数学模型、SMO算法设计、Simulink建模步骤及参数优化方法,提供了可直接工程应用的MATLAB代码和仿真模型,为电动汽车驱动、工业机器人等高精度控制场景提供了有效解决方案。

MHD0815的博客 229

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

Spring Cloud Ribbon客户端负载均衡深度解析:从原理到实战,打造高效微服务调用

本文深入剖析Spring Cloud Ribbon客户端负载均衡的核心机制与实战应用,结合Eureka服务注册中心,详解其高可用架构设计及内置算法实现(如轮询、随机、响应时间加权等)。通过源码逐层解读RoundRobinRule轮询策略,手把手指导如何通过@RibbonClient注解实现服务级负载策略定制,并规避@ComponentScan作用域陷阱。 更提供独创性实战案例:基于自旋锁实现原子计数器,手写仿Ribbon轮询算法,助你掌握微服务调用的底层逻辑。适合微服务开发者、架构师及对分布式系统设计感兴趣

Zyw907155124的博客 1157

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

【深入理解SpringCloud微服务】深入理解Ribbon原理并手写一个微服务负载均衡器

创建LoadBalancer前首先通过Java的SPI机制加载所有的负载均衡策略类LoadBalanceRule,再通过@Rule注解与配置文件的配置进行匹配,匹配出一个LoadBalanceRule。即使只有一个服务提供者,它的ip地址和端口好也是有可能会变的。由于有了负载均衡器,服务消费者请求服务提供者不再需要通过ip地址加端口号的方式,而是可以以服务名作为域名,负载均衡器会通过一定的负载均衡策略,选择服务名对应的微服务集群中的其中一个服务提供者节点,将请求地址中的服务名替换为该节点的ip地址端口号。

weixin_43889578的博客 1376

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

【SpringCloud微服务系列】SpringCloud组件原理:Eureka,Feign,Ribbon,Hystrix,Zuul

目录 1.前序 1.1 分布式的优缺点 1.1.1 分布式优点 1.1.2 分布式缺点 1.2 分布式服务框架 2.SpringCloud常用组件 2.1 Eureka 2.1.1 同为注册中心,Eureka和Zookeeper的区别: 2.2 Feign 2.3 Ribbon 2.4 Hystrix ...

Yangy的博客 1万+

spring cloud Ribbon的使用和实现原理

转载链接:https://blog.youkuaiyun.com/qq_20597727/article/details/82860521 简介 这篇文章主要介绍一下ribbon在程序中的基本使用,在这里是单独拿出来写用例测试的,实际生产一般是配置feign一起使用,更加方便开发。同时这里也通过源码来简单分析一下ribbon的基本实现原理。 基本使用 这里使用基于zookeeper注册中心+...

qq_29860591的博客 267

【一起学源码-微服务】Ribbon源码五:Ribbon源码解读汇总篇~

前言 想说的话 【一起学源码-微服务-Ribbon】专栏到这里就已经全部结束了,共更新四篇文章。 Ribbon比较小巧,这里是直接 读的spring cloud 内嵌封装的版本,里面的各种configuration确实有点绕,不过看看第三讲Ribbon初始化的过程总结图就会清晰很多。 紧接着会继续整理学习Feign源码相关的,敬请期待。 说明 原创不易,如若转载 请标明来源! 总结...

weixin_44626952的博客 286

Ribbon详解

简介 Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netflix Ribbon实现。通过Spring Cloud的封装,可以让我们轻松地将面向服务的REST模版请求自动转换成客户端负载均衡的服务调用。Spring Cloud Ribbon虽然只是一个工具类框架,它不像服务注册中心、配置中心、API网关那样需要独立部署,但是它几乎存在...

清纯玉面可爱小郎君 662

微服务流程介绍

原地址:https://blog.youkuaiyun.com/qq_42046105 目录 一、业务场景介绍 二、Spring Cloud核心组件:Eureka 三、Spring Cloud核心组件:Feign 四、Spring Cloud核心组件:Ribbon 五、Spring Cloud核心组件:Hystrix 六、Spring Cloud核心组件:Zuul 七、总结 ...

天才战士的博客 1万+

【详解】Ribbon 负载均衡服务调用原理及默认轮询负载均衡算法源码解析、手写

Ribbon 负载均衡服务调用 一、什么是 Ribbon Spring Cloud Ribbon 是基于 Netflix Ribbon 实现的一套客户端 负载均衡的工具。 简单的说,Ribbon 是 Netflix 发布的开源项目,主要功能是提供客户端负载均衡算法和服务调用。Ribbon 客户组件提供一系列完善的配置如连接超时时,重试等。简单的说,就是在配置文件中列出 Load Balancer(简称 L B)后面的所有机器,Ribbon 会自动的帮助我们基于某种规则(如简单的轮询,随机连接等)去连接这些机

Welcome,Everyone. 2601

SpringCloud-Ribbon负载均衡

本文描述了Ribbon的负载均衡策略并对其中的轮询策略进行了详细分析

weixin_46120888的博客 4222

SpringCloud Ribbon 设计原理

Ribbon 是netflix 公司开源的基于客户端的负载均衡组件,是Spring Cloud大家庭中非常重要的一个模块; Ribbon应该也是整个大家庭中相对而言比较复杂的模块,直接影响到服务调度的质量和性能。 全面掌握Ribbon可以帮助我们了解在分布式微服务集群工作模式下,服务调度应该考虑到的每个环节。 本文将详细地剖析Ribbon的设计原理,帮助大家对Spring Cloud 有一个更好...

jackcheng1117的博客 1475
上一篇: Java线程池源码详解(一)
下一篇: 微服务之Hystrix原理解析
___mystack
博客等级 码龄9年 3粉丝 20原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值