洗脚城太多不知道去哪个?用负载均衡思想啦!(一)

前序

近年来社会经济发展迅速,人均消费水平提升,民众也越来越开始注重身体健康,于是,足疗按摩等服务行业如雨后春笋般蓬勃发展。前端时间热播的<<屌丝男士>>里大鹏与乔杉的搞笑(精彩)演出,更是生动地表现出了民众的丰富的业余生活,让“上钟”、“特色服务”等行业术语进入了民众的茶余笑料。

现实是,当可选项多时,人会陷入迷茫和纠结,洗脚城多了也是一样。对于IT从业者来说,在实际的工作中,也会碰到类似的场景,那就是当服务集群化,如何合理分散服务请求到相应的服务器,是他们需要解决的一个问题。

正文

一:负载均衡的二种实现

1.1)服务端的负载均衡(Nginx)

 

①:我们用户服务发送请求首先打到Ng上,然后Ng根据负载均衡算法进行选择一个服务调用,而我们的Ng部署在服务器上的,所以Ng又称为服务端的负载均衡(具体调用哪个服务,由Ng所了算)
生活案例: 程序员张三 去盲人按摩, 前台的小姐姐接待了张三,然后为张三分派技师按摩.

1.2)客户端负载均衡(ribbon)

spring cloud ribbon是 基于NetFilix ribbon 实现的一套客户端的负载均衡工具,Ribbon客户端组件提供一系列的完善的配置,如超时,重试等。
通过Load Balancer(LB)获取到服务提供的所有机器实例,Ribbon会自动基于某种规则(轮询,随机)去调用这些服务。Ribbon也可以实现我们自己的负载均衡算法。

 

生活案例:

 

1.3)自定义的负载均衡算法(随机)
我们可以通过DiscoveryClient组件来去我们的Nacos服务端拉取给名称的微服务列表。我们可以通过这个特性来改写我们的RestTemplate组件.
①:经过阅读源码RestTemplate组件得知,不管是post,get请求最终是会调用我们的doExecute()方法,所以我们写一个ZhangjiangRestTemplate类继承RestTemplate,从写doExucute()方法。
 1  @Slf4j
 2 public class ZhangjiangRestTemplate extends RestTemplate {
 3     private DiscoveryClient discoveryClient;
 4     public ZhangjiangRestTemplate (DiscoveryClient discoveryClient) {
 5         this.discoveryClient = discoveryClient;
 6     }
 7 protected <T> T doExecute(URI url, @Nullable HttpMethod method, @Nullab le RequestCallback requestCallback,@Nullable ResponseExtractor<T> responseExtractor) throws RestClientExce ption {
 8     Assert.notNull(url, "URI is required");
 9     Assert.notNull(method, "HttpMethod is required");
10     ClientHttpResponse response = null;
11     try{
12         //判断url的拦截路径,然后去redis(作为注册中心)获取地址随机选取一个
13         log.info("请求的url路径为:{}",url);
14         url = replaceUrl(url);
15         log.info("替换后的路径:{}",url);
16         ClientHttpRequest request = createRequest(url, method);
17         if (requestCallback != null) {
18             requestCallback.doWithRequest(request);
19         }
20         response = request.execute();
21         handleResponse(url, method, response);
22         return (responseExtractor != null ? responseExtractor.extractData(respo nse) : null);
23     } catch (IOException ex) {
24          String resource = url.toString();  
25          String query = url.getRawQuery();
26          resource = (query != null ? resource.substring(0, resource.indexOf('?')) : resource);
27          throw new ResourceAccessException("I/O error on " + method.name() +" request for \"" + resource + "\": " + ex.getMessage(), ex);
28     }finally {
29      if (response != null) {
30            response.close();
31      }
32    }
33 }
34 /**
35 **把服务实例名称替换为ip:端口
36 **/
37 private URI replaceUrl(URI url){
38     //解析我们的微服务的名称
39     String sourceUrl = url.toString();
40     String [] httpUrl = sourceUrl.split("//");
41     int index = httpUrl[1].replaceFirst("/","@").indexOf("@");
42     String serviceName = httpUrl[1].substring(0,index);
43     //通过微服务的名称去nacos服务端获取 对应的实例列表
44     List<ServiceInstance> serviceInstanceList = discoveryClient.getInstance s(serviceName);
45     if(serviceInstanceList.isEmpty()) {
46         throw new RuntimeException("没有可用的微服务实例列表:"+serviceName);
47     }
48     //采取随机的获取一个
49     Random random = new Random();
50     Integer randomIndex = random.nextInt(serviceInstanceList.size());
51     log.info("随机下标:{}",randomIndex);
52     String serviceIp = serviceInstanceList.get(randomIndex).getUri().toStri ng();
53     log.info("随机选举的服务IP:{}",serviceIp);
54     String targetSource = httpUrl[1].replace(serviceName,serviceIp);
55     try {
56          return new URI(targetSource);
57     } catch (URISyntaxException e) {
58         e.printStackTrace();
59      }
60      return url;
61    }
62 }   
63             
View Code

 

posted @ 2020-10-16 12:56  powerZhangFly  阅读(136)  评论(0)    收藏  举报