当前位置:网站首页>微服务实战|手把手教你开发负载均衡组件
微服务实战|手把手教你开发负载均衡组件
2022-07-02 06:33:00 【_时光煮雨】
前言
上一篇文章中我们通过原生态的方式实现了服务的发现和调用,但是在集群环境中,并没有达到负载均衡的目的,这一篇文章,我们将编写自己的负载均衡器,以实现服务调用的负载均衡功能。
自定义负载均衡
回顾
首先,我们再先来回顾一下上一篇文章中的代码:
@GetMapping("/hello")
public String hello(String name) {
List<ServiceInstance> list = discoveryClient.getInstances("provider");
ServiceInstance instance = list.get(0);
String host = instance.getHost();
int port = instance.getPort();
String returnInfo = restTemplate.getForObject("http://" + host + ":" + port + "/hello?name={1}", String.class, name);
return returnInfo;
}
我们先通过discoveryClient获取了注册中心的其中一个服务的ip和端口,然后使用restTemplate调用其getForObjec()方法进行接口的调用。
通过跟踪该方法的源码,我们发现最终都会调用其doExecute()方法,源码如下:
@Nullable
protected <T> T doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor) throws RestClientException {
Assert.notNull(url, "URI is required");
Assert.notNull(method, "HttpMethod is required");
ClientHttpResponse response = null;
Object var14;
try {
ClientHttpRequest request = this.createRequest(url, method);
if (requestCallback != null) {
requestCallback.doWithRequest(request);
}
response = request.execute();
this.handleResponse(url, method, response);
var14 = responseExtractor != null ? responseExtractor.extractData(response) : null;
} catch (IOException var12) {
String resource = url.toString();
String query = url.getRawQuery();
resource = query != null ? resource.substring(0, resource.indexOf(63)) : resource;
throw new ResourceAccessException("I/O error on " + method.name() + " request for \"" + resource + "\": " + var12.getMessage(), var12);
} finally {
if (response != null) {
response.close();
}
}
return var14;
}
那我们能不能继承RestTemplate类,并重写doExecute方法,在doExecute方法中调用createRequest之前对其做一下改变呢?
实现负载均衡
首先创建我们自己的RestTemplate,命名为MyRestTemplate.java,示例如下:
/** * 自定义负载均衡器 * @Author:公众号:程序员965 * @create 2022-06-06 **/
public class MyRestTemplate extends RestTemplate {
private DiscoveryClient discoveryClient;
public MyRestTemplate (DiscoveryClient discoveryClient) {
this.discoveryClient = discoveryClient;
}
/** * 接口调用 * @Author:公众号:程序员965 * @create 2022-06-06 **/
protected <T> T doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback,
@Nullable ResponseExtractor<T> responseExtractor) throws RestClientException {
Assert.notNull(url, "URI is required");
Assert.notNull(method, "HttpMethod is required");
ClientHttpResponse response = null;
try {
System.out.println("替换前url :"+url.toString());
url = replaceUrl(url);
System.out.println("替换后url :"+url.toString());
ClientHttpRequest request = createRequest(url, method);
if (requestCallback != null) {
requestCallback.doWithRequest(request);
}
response = request.execute();
handleResponse(url, method, response);
return (responseExtractor != null ? responseExtractor.extractData(response) : null);
}
catch (IOException ex) {
String resource = url.toString();
String query = url.getRawQuery();
resource = (query != null ? resource.substring(0,resource.indexOf('?')) : resource);
throw new ResourceAccessException("I/O error on " + method.name() +
" request for \"" + resource + "\": " + ex.getMessage(), ex);
} finally {
if (response != null) {
response.close();
}
}
}
/** * 替换url * @Author:公众号:程序员965 * @create 2022-06-06 **/
private URI replaceUrl(URI url){
String sourceUrl = url.toString();
String [] httpUrl = sourceUrl.split("//");
int index = httpUrl[1].replaceFirst("/","@").indexOf("@");
String serviceName = httpUrl[1].substring(0,index);
List<ServiceInstance> serviceInstanceList = discoveryClient.getInstances(serviceName);
//采取随机算法,获取其中一个服务信息
Random random = new Random();
Integer randomIndex = random.nextInt(serviceInstanceList.size());
String serviceIp = serviceInstanceList.get(randomIndex).getUri().toString();
String targetSource = httpUrl[1].replace(serviceName,serviceIp);
try {
return new URI(targetSource);
} catch (URISyntaxException e) {
e.printStackTrace();
}
return url;
}
}
在doExecute方法中,调用createRequest方法之前,我们增加了一行replaceUrl()方法调用,在该方法中,我们通过解析Url,获得服务名称,然后依然根据服务名称获取服务信息列表,并通过随机算法,返回服务信息列表中其中一个服务的uri并返回,实现了随机算法的负载均衡。
接口调用
回过头来,我们修改一下接口的调用点,首先restTemplate改为创建我们自定义的MyRestTemplate:
@Bean
RestTemplate restTemplate(DiscoveryClient discoveryClient) {
return new MyRestTemplate(discoveryClient);
}
然后修改接口,将接口地址直接改为用服务名称进行调用:
@GetMapping("/hello2")
public String hello2(String name) {
String returnInfo = restTemplate.getForObject( "http://provider/hello?name={1}", String.class, name);
return returnInfo;
}
启动调试

运行成功,正确返回了我们的结果!
这时候,可能有人会有疑问:直接在接口调用处随机获取一个ip和端口进行调用不就行了?为什么费劲扒源码然后继承RestTemplate类并改写其doExecute方法呢?不是多此一举吗?
小伙伴们?想想看,为什么要这么做呢?这个问题留到我们使用负载均衡组件的时候再讲吧。
总结
本文中,我们使用随机算法实现了负载均衡的功能,当然你也可以根据需要实现比如轮询,权重等各种各样的负载算法。你学会了吗?
边栏推荐
- Find the node with the smallest value range in the linked list and move it to the front of the linked list
- Introduction to the basic concept of queue and typical application examples
- Dix ans d'expérience dans le développement de programmeurs vous disent quelles compétences de base vous manquez encore?
- C# 调用系统声音 嘀~
- C4D quick start tutorial - C4d mapping
- 查看was发布的应用程序的端口
- oracle修改数据库字符集
- Image transformation, transpose
- Tensorflow2 keras classification model
- Linux二进制安装Oracle Database 19c
猜你喜欢

整理秒杀系统的面试必备!!!

oracle修改数据库字符集

MYSQL安装出现问题(The service already exists)

C nail development: obtain all employee address books and send work notices

盘点典型错误之TypeError: X() got multiple values for argument ‘Y‘

汉诺塔问题的求解与分析

Redis zadd导致的一次线上问题排查和处理

Hengyuan cloud_ Can aiphacode replace programmers?

commands out of sync. did you run multiple statements at once

查看was发布的应用程序的端口
随机推荐
Data type case of machine learning -- using data to distinguish men and women based on Naive Bayesian method
Qunhui NAS configuring iSCSI storage
Kubernetes deploys Loki logging system
Programmers with ten years of development experience tell you, what core competitiveness do you lack?
C# 调用系统声音 嘀~
Leetcode sword finger offer brush questions - day 23
Kubesphere virtualization KSV installation experience
使用IBM MQ远程连接时报错AMQ 4043解决思路
Using recursive functions to solve the inverse problem of strings
Mirror protocol of synthetic asset track
Pdf document of distributed service architecture: principle + Design + practice, (collect and see again)
QT drag event
判断是否是数独
Linux binary installation Oracle database 19C
[staff] the lines and spaces of the staff (the nth line and the nth space in the staff | the plus N line and the plus N space on the staff | the plus N line and the plus N space below the staff | the
「Redis源码系列」关于源码阅读的学习与思考
C call system sound beep~
Matplotlib剑客行——容纳百川的艺术家教程
Solution and analysis of Hanoi Tower problem
机器学习之数据类型案例——基于朴素贝叶斯法,用数据辩男女