文章插图
![负载均衡服务器有哪些 服务器负载均衡器](http://img.hubeilong.com/220624/230IU962-0.jpg)
文章插图
1.什么是负载均衡
首先我们来看看维基百科对负载均衡的说明:
负载平衡(Load balancing)是一种计算机技术,用来在多个计算机(计算机集群)、网络连接、CPU、磁盘驱动器或其他资源中分配负载,以达到最优化资源使用、最大化吞吐率、最小化响应时间、同时避免过载的目的 。使用带有负载平衡的多个服务器组件,取代单一的组件,可以通过冗余提高可靠性 。负载平衡服务通常是由专用软件和硬件来完成 。主要作用是将大量作业合理地分摊到多个操作单元上进行执行,用于解决互联网架构中的高并发和高可用的问题 。举个例子来解释下负载均衡
下图中,一群人在银行排队办理业务,假设只有一个服务窗口,那么一个服务窗口来处理所有人员业务办理,人少的时候,肯定是能够办理完的,如果人特别多的时候恩?一个服务窗口肯定是没有办法处理完这么多业务办理的 。于是就出现如下图这样,一大堆人排队 。
为什么?因为没办法保证让某个人在某个窗口办理业务 。大家可能还是会乱套(举个极端例子:假设A窗口的小姐姐特别的漂亮,会不会她那里会有很多的男客户排队办理业务恩?),因此银行除了多开几个窗口以外,还会设置一个排号,你拿到排号在哪个窗口,你就在哪个窗口进行办理业务 。
2.注册多个服务
在微服务Spring Cloud快速入门中,如果我们的商品服务一个不够用的话,根据负载均衡的理论,那我们就可以多注册几个服务 。防止一个服务无法承载高并发时的情况 。
启动注册中心、商品服务,订单服务,登录注册中心,查看我们当前的服务
2.1向注册中心注册多个服务
以同样的项目代码,设定端口为8091,其余配置均和之前的商品服务保持一致,然后启动商品服务 。
server:port:8091#服务端口spring:application:name:hutao-microservice-item#指定服务名eureka:client:registerWithEureka:true#是否将自己注册到Eureka服务中,默认为truefetchRegistry:true#是否从Eureka中获取注册信息,默认为trueserviceUrl:#Eureka客户端与Eureka服务端进行交互的地址defaultZone:http://127.0.0.1:9090/eureka/instance:prefer-ip-address:true#将自己的ip地址注册到Eureka服务中
点击如下所示,可以看到我们启动了1个注册中心,1个订单服务,2个商品服务2.2通过服务ID找到服务
在微服务Spring Cloud快速入门中我们定义了如下Feign接口,在这个接口上面,[email protected],指定了服务ID:hutao-microservice-item 。这个Feign接口会给我发起Http调用 。当然在这里我们可能无法看到负载均衡的效果,因此我们需要稍微深入下底层代码 。
@FeignClient(value="http://www.mnbkw.com/jxjc/188204/hutao-microservice-item")@RequestMapping("/itemservice")[email protected]:使用声明式HTTP客户端发起请求:[email protected][email protected][email protected][email protected][email protected](value="http://www.mnbkw.com/jxjc/188204/item/{itemId}")ItemsqueryItem(@PathVariable("itemId")StringitemId);}
大家应该还记得,我们的商品服务和订单服务,注册到注册中心的时候,我们在启动类上面添加了一个注解:@EnableDiscoveryClient 。现在我们来看下DiscoveryClient这个接口
2.2.1.DiscoveryClient 解读
DiscoveryClient接口源码如下,他是用来发现服务的,比如发现Netflix服务,其中有个方法List getInstances(String serviceId)是根据服务ID获取服务实例集合 。
/***Representsreadoperationscommonlyavailabletodiscoveryservicess[email protected][email protected][email protected]thediscoveryclient.*/intDEFAULT_ORDER=0;/***Ahuman-readabledescriptionoftheimplementation,[email protected]*/Stringdescription();[email protected][email protected]*/List<ServiceInstance>getInstances(StringserviceId);[email protected]*/List<String>getServices();[email protected][email protected](){returnDEFAULT_ORDER;}}
我们可以看到DiscoveryClient 有4个实现,当然这里我们用的肯定是Eureka 。现在我们来使用下DiscoveryClient 这个接口
首先把这个接口依赖注入到我们的Controller中,我们看下能获取到什么
@AutowiredprivateDiscoveryClientdiscoveryClient;@GetMapping(value="http://www.mnbkw.com/jxjc/188204/order/{orderId}")publicOrderqueryOrderById(@PathVariable("orderId")StringorderId){StringserviceId="hutao-microservice-item";List<ServiceInstance>instances=discoveryClient.getInstances(serviceId);System.out.println(instances);returnnull;}
通过调试代码,我们发现如我们之前所说,我们可以通过服务ID:hutao-microservice-item,找到两个服务实例 。2.2.3.从服务实例中获取服务信息,发起Http请求
那么这个时候,我们怎么去发起请求恩?很简单,就是从服务实例中,获取到服务信息后,将接口的请求地址拼接出来 。然后使用restTemplate发起Http请求
@AutowiredprivateRestTemplaterestTemplate;@GetMapping(value="http://www.mnbkw.com/jxjc/188204/order/{orderId}")publicOrderqueryOrderById(@PathVariable("orderId")StringorderId){StringserviceId="hutao-microservice-item";List<ServiceInstance>instances=discoveryClient.getInstances(serviceId);ServiceInstanceserviceInstance=instances.get(0);Stringurl=serviceInstance.getHost()+":"+serviceInstance.getPort();Itemsitems=restTemplate.getForObject("http://"+url+"/itemservice/item/1",Items.class);System.out.println(items);returnnull;}
可以看到我们的请求是能正常访问的 。当然也有问题存在,那就是我们拿到的是多个服务,程序怎么知道我要调用的是哪一个服务呢?上述案例中,我们获取到的实例是两个,那么每次调用的时候,我们怎么来确定,我要调用的是哪一个服务?,因为这时候我们拿到的两个服务,也就是两个不同的IP地址,这时候就需要一个负载均衡器来帮我们选择一个IP进行访问 。
在Spring Cloud中,netfix提供一个负载均衡器Ribbon,该负载均衡器是声明式的,其用法如下所示,[email protected]Balanced,这时候我们的RestTemplate就具备了负载均衡的功能 。
注意:RestTemplate底层默认使用的jdk的标准实现,如果我们想让RestTemplate的底层使用okhttp,可以替换实现的 。如下源码所示,RestTemplate提供了三个构造方法 。
@[email protected]@LoadBalancedpublicRestTemplaterestTemplate(){returnnewRestTemplate();}}
在上面的一个案例中,我们通过从服务实例中,获取到服务,然后再从服务中心获取具体的IP地址信息,发起请求 。Stringurl=serviceInstance.getHost()+":"+serviceInstance.getPort();Itemsitems=restTemplate.getForObject("http://"+url+"/itemservice/item/1",
但是,现在我们不需要这么做了,因为我们对restTemplate声明了是需要负载均衡的,因此我们发起请求的时候,就不需要指定IP地址了,我们可以用服务ID来代替IP地址,然后由restTemplate来帮我选择需要调用的IP 。因此上述代码会被简化为如下所示,被注释掉的代码就是被优化的代码 。@GetMapping(value="http://www.mnbkw.com/jxjc/188204/order/{orderId}")publicOrderqueryOrderById(@PathVariable("orderId")StringorderId){StringserviceId="hutao-microservice-item";//List<ServiceInstance>instances=discoveryClient.getInstances(serviceId);//ServiceInstanceserviceInstance=instances.get(0);//Stringurl=serviceInstance.getHost()+":"+serviceInstance.getPort();//Itemsitems=restTemplate.getForObject("http://"+url+"/itemservice/item/1",Items.class);Itemsitems=restTemplate.getForObject("http://"+serviceId+"/itemservice/item/1",Items.class);System.out.println(items);returnnull;}
重启服务后,商品服务仍然可用,那么这时候怎么来验证我们的负载均衡成功了?2.2.5.简单验证负载均衡
其实最简单的验证方式就是,在商品服务中,添加日志,看看哪个服务记录了日志或者debug调试,看走哪一个服务的代码 。即可验证我们的负载均衡是否成功 。
当然这里我们就不做上述方式的演示,来做一点高难度的代码分析 。
[email protected]te源码解析
1、首先看org.springframework.web.client.RestTemplate类 。
当我们执行如下代码时
restTemplate.getForObject("http://"+serviceId+"/itemservice/item/1",Items.class);
最终会执行到如下方法doExecute(URI,HttpMethod,RequestCallback,ResponseExtractor<T>)
逐步深入代码,我们找到了如下的拦截器 。LoadBalancerInterceptororg.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor
继续深入代码,我们找到了RibbonLoadBalancerClient这个类org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient通过查看代码,我们发现了getLoadBalancer(String)这个方法通过serviceId找到了两个服务实例,
protectedServergetServer(ILoadBalancerloadBalancer,Objecthint){if(loadBalancer==null){returnnull;}//Use'default'onanullhint,orjustpassiton?returnloadBalancer.chooseServer(hint!=null?hint:"default");}
4.负载均衡代码验证演示
通过上述源码分析,我们发现如果我们开启了负载均衡,但是没有配置负载均衡参数,则会采用默认的配置,也就是轮询算法来实现负载均衡 。
通过上述的debug阅读,我们参照getServer这个方法来写代码测试下负载均衡
@AutowiredprivateLoadBalancerClientloadBalancerClient;@GetMapping(value="http://www.mnbkw.com/jxjc/188204/order/{orderId}")publicOrderqueryOrderById(@PathVariable("orderId")StringorderId){StringserviceId="hutao-microservice-item";for(inti=0;i<10;i++){ServiceInstancechoose=loadBalancerClient.choose(serviceId);System.out.println(choose);}//List<ServiceInstance>instances=discoveryClient.getInstances(serviceId);//ServiceInstanceserviceInstance=instances.get(0);//Stringurl=serviceInstance.getHost()+":"+serviceInstance.getPort();//Itemsitems=restTemplate.getForObject("http://"+serviceId+"/itemservice/item/1",Items.class);//System.out.println(items);returnnull;}
在我们之前调试代码的时候我们发现源码中定义了IRule.choose(Object objet)这个接口,并且如下几个实现 。
比如,我们设置为随机策略 。
hutao-microservice-item是我们需要对某个服务设定NFLoadBalancerRuleClassName是我们的策略(也就是实现类的路径)
【负载均衡服务器有哪些 服务器负载均衡器】
hutao-microservice-item:ribbon:NFLoadBalancerRuleClassName:com.netflix.loadbalancer.RandomRule
重启服务后,再看我们的负载均衡,是随机的,而不是轮询的 。- 免费使用的服务器 服务器免费用
- 企业邮件服务器租用 租用邮政信箱
- ftp上传文件失败原因 ftp服务器传输数据失败的原因
- linux重启apache服务器命令 怎么重启apache服务器
- 浪潮服务器ipmi默认ip 浪潮ipmi地址配置
- 云主机服务器哪里好 云主机性价比
- 代理服务器网址设置 上网设置代理服务器
- 如何把文件上传服务器 上传文件到服务器命令
- 虚拟主机和云服务器的区别 虚拟主机和服务器有什么区别
- 怎么开通地图服务 自己搭建地图服务器