当前位置:网站首页>微服务实战|手把手教你开发负载均衡组件
微服务实战|手把手教你开发负载均衡组件
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方法呢?不是多此一举吗?
小伙伴们?想想看,为什么要这么做呢?这个问题留到我们使用负载均衡组件的时候再讲吧。
总结
本文中,我们使用随机算法实现了负载均衡的功能,当然你也可以根据需要实现比如轮询,权重等各种各样的负载算法。你学会了吗?
边栏推荐
- QT qtimer class
- Win10 uses docker to pull the redis image and reports an error read only file system: unknown
- 【Go实战基础】gin 如何绑定与使用 url 参数
- 判断是否是数独
- C#钉钉开发:取得所有员工通讯录和发送工作通知
- Minecraft install resource pack
- 队列管理器running状态下无法查看通道
- C Gaode map obtains the address according to longitude and latitude
- C# 百度地图,高德地图,Google地图(GPS) 经纬度转换
- Leetcode sword finger offer brush questions - day 23
猜你喜欢
Move a string of numbers backward in sequence
Function ‘ngram‘ is not defined
Kubernetes deploys Loki logging system
Programmers with ten years of development experience tell you, what core competitiveness do you lack?
[go practical basis] how to bind and use URL parameters in gin
Mysql安装时mysqld.exe报`应用程序无法正常启动(0xc000007b)`
概率还不会的快看过来《统计学习方法》——第四章、朴素贝叶斯法
Finishing the interview essentials of secsha system!!!
以字节跳动内部 Data Catalog 架构升级为例聊业务系统的性能优化
Minecraft air Island service
随机推荐
Oracle 相关统计
Jingdong senior engineer has developed for ten years and compiled "core technology of 100 million traffic website architecture"
AMQ6126问题解决思路
C language - Blue Bridge Cup - 7 segment code
以字节跳动内部 Data Catalog 架构升级为例聊业务系统的性能优化
【Go实战基础】gin 如何自定义和使用一个中间件
[staff] time mark and note duration (staff time mark | full note rest | half note rest | quarter note rest | eighth note rest | sixteenth note rest | thirty second note rest)
Shengshihaotong and Guoao (Shenzhen) new energy Co., Ltd. build the charging pile industry chain
十年開發經驗的程序員告訴你,你還缺少哪些核心競爭力?
Hengyuan cloud_ Can aiphacode replace programmers?
Redis sorted set data type API and application scenario analysis
Driving test Baodian and its spokesperson Huang Bo appeared together to call for safe and civilized travel
C# 调用系统声音 嘀~
Sentinel reports failed to fetch metric connection timeout and connection rejection
[staff] time sign and note duration (full note | half note | quarter note | eighth note | sixteenth note | thirty second note)
Aneng logistics' share price hit a new low: the market value evaporated by nearly 10 billion yuan, and it's useless for chairman Wang Yongjun to increase his holdings
kubernetes部署loki日志系统
Move a string of numbers backward in sequence
Dix ans d'expérience dans le développement de programmeurs vous disent quelles compétences de base vous manquez encore?
Cartoon rendering - average normal stroke