洗脚城太多不知道去哪个?用负载均衡思想啦!(一)
前序
近年来社会经济发展迅速,人均消费水平提升,民众也越来越开始注重身体健康,于是,足疗按摩等服务行业如雨后春笋般蓬勃发展。前端时间热播的<<屌丝男士>>里大鹏与乔杉的搞笑(精彩)演出,更是生动地表现出了民众的丰富的业余生活,让“上钟”、“特色服务”等行业术语进入了民众的茶余笑料。
现实是,当可选项多时,人会陷入迷茫和纠结,洗脚城多了也是一样。对于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

浙公网安备 33010602011771号