Cloudflare Worker 是和 Amazon Lambda, Google Function 类似的无服务器 Serverless 技术. 我们可以写一些代码(JS)部署到 CloudFlare 的网络节点中. 这项技术的好处是我们并不需要去维护服务器(减少运维成本), 而且通过Serverless技术很容易就可以把程序跑在成千上万的节点上 (较强的可扩展性).
负载均衡服务器(Load Balancer)用于把用户的请求重新分配(Route)到提供真正服务的源服务器(Worker). 我们可以通过负载均衡来实现水平扩展(Horizontal Scaling). 当然如果负载均衡只有一台服务器, 也是会有单点故障的 (Single Point of Failure).
如果通过CloudFlare Worker来搭建负载均衡, 这样我们的负载均衡服务器会被自动部署到成千上万的CloudFlare节点中 – 可靠性 Durability 和可用性 Availability 就很靠谱了.
通过CloudFlare Worker搭建的分布式负载均衡服务器
设置分布式负载平衡器的成本是可以承受的. CloudFlare工作者有一个免费计划-每天为您提供10万个API调用, 每个API请求的最大CPU时间为10毫秒. 对于付费计划-每月报价为1000万个请求, 最长50ms CPU时间.
例如, 让我们首先定义分布式负载均衡器后面的源服务器列表. 源服务器也就是真正干活的节点.
let nodes = [
"https://api.justyy.com",
"https://api.steemyy.com"
];
我们需要一个 Promise.any 实现方法 – 在 CloudFlare Worker 里 并不支持 Promise.any 但我们可以定义如下:
function reverse(promise) {
return new Promise((resolve, reject) => Promise.resolve(promise).then(reject, resolve));
}
function promiseAny(iterable) {
return reverse(Promise.all([...iterable].map(reverse)));
};
Promise.race 是返回第一个被实现或者拒绝的 Promise 而相反 Promise.any 是返回第一个被实现的 Promise. 所以用在这里就是获得响应最快(成功)的源服务器.
async function contactServer(server) {
return new Promise((resolve, reject) => {
fetch(server, {
method: "GET"
}).then(response => {
resolve({
"server": server,
});
}).catch(function(error) {
reject(error);
});
});
}
我们还可以加于改进, 为每个源服务器添加一个返回当前负载的API – 这样一来, 我们就可以选出负载最小的那个源服务器了.
处理 跨域 CORs 和头部数据 Headers
以下JS代码用于处理跨域和相应的Headers.
function handleOptions(request) {
// Make sure the necesssary headers are present
// for this to be a valid pre-flight request
if (
request.headers.get('Origin') !== null &&
request.headers.get('Access-Control-Request-Method') !== null &&
request.headers.get('Access-Control-Request-Headers') !== null
) {
// Handle CORS pre-flight request.
// If you want to check the requested method + headers
// you can do that here.
return new Response(null, {
headers: corsHeaders,
})
} else {
// Handle standard OPTIONS request.
// If you want to allow other HTTP Methods, you can do that here.
return new Response(null, {
headers: {
Allow: 'GET, HEAD, POST, OPTIONS',
},
})
}
}
addEventListener('fetch', event => {
const request = event.request;
const method = request.method.toUpperCase();
if (method === 'OPTIONS') {
// Handle CORS preflight requests
event.respondWith(handleOptions(request))
} else if (
method === 'GET' ||
method === 'HEAD' ||
method === 'POST'
) {
// Handle requests to the API server
event.respondWith(handleRequest(request))
} else {
event.respondWith(
new Response(null, {
status: 405,
statusText: 'Method Not Allowed',
}),
)
}
});
转发请求
负载均衡最重要的部分就是转发请求. 一旦我们知道哪个(最快)服务器应满足当前请求. 然后, 我们需要将请求转发到原始服务器, 并在获得结果后将其转发回用户. 以下是分别转发GET和POST请求的两个功能-您可能希望添加其他请求, 例如PUT, PATCH, DELETE等.
async function forwardRequestGET(apiURL) {
return new Promise((resolve, reject) => {
fetch(apiURL, {
method: "GET",
headers: {
'Content-Type': 'application/json'
},
redirect: "follow"
}).then(response => {
resolve(response.text());
}).catch(function(error) {
reject(error);
});
});
}
async function forwardRequestPOST(apiURL, body) {
return new Promise((resolve, reject) => {
fetch(apiURL, {
method: "POST",
redirect: "follow",
headers: {
'Content-Type': 'application/json'
},
body: body
}).then(response => {
resolve(response.text());
}).catch(function(error) {
reject(error);
});
});
}
使用CloudFlare Worker的负载均衡器服务器
以下是CloudFlare负载均衡服务器的主要实现部分. 该脚本将在CloudFlare分布缘网络节点上运行.
/**
* Respond to the request
* @param {Request} request
*/
async function handleRequest(request) {
const country = request.headers.get('cf-ipcountry');
const servers = [];
for (const server of nodes) {
servers.push(contactServer(server));
}
const load = await promiseAny(servers);
const forwardedURL = load['server'];
const method = request.method.toUpperCase();
let result;
let res;
let version = "";
try {
version = await getVersion(load['server']);
} catch (e) {
version = JSON.stringify(e);
}
try {
if (method === "POST") {
const body = await request.text();
result = await forwardRequestPOST(forwardedURL, body);
} else if (method === "GET") {
result = await forwardRequestGET(forwardedURL);
} else {
res = new Response(null, {
status: 405,
statusText: 'Method Not Allowed',
});
res.headers.set('Access-Control-Allow-Origin', '*');
res.headers.set('Cache-Control', 'max-age=3600');
res.headers.set("Origin", load['server']);
res.headers.set("Country", country);
return res;
}
res = new Response(result, {status: 200});
res.headers.set('Content-Type', 'application/json');
res.headers.set('Access-Control-Allow-Origin', '*');
res.headers.set('Cache-Control', 'max-age=3');
res.headers.set("Origin", load['server']);
res.headers.set("Version", version);
res.headers.set("Country", country);
} catch (e) {
res = new Response(JSON.stringify(result), {status: 500});
res.headers.set('Content-Type', 'application/json');
res.headers.set('Access-Control-Allow-Origin', '*');
res.headers.set('Cache-Control', 'max-age=3');
res.headers.set("Origin", load['server']);
res.headers.set("Version", version);
res.headers.set("Country", country);
res.headers.set("Error", JSON.stringify(e));
}
return res;
}
我们还可以在负载均衡服务器返回数据前添加一些Headers数据, 比如我们可以 获得源服务器版本 信息.
async function getVersion(server) {
return new Promise((resolve, reject) => {
fetch(server, {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({"id":0,"jsonrpc":"2.0","method":"call","params":["login_api","get_version",[]]})
}).then(response => {
resolve(response.text());
}).catch(function(error) {
reject(error);
});
});
}
通过实现这种分布式负载均衡器 (Distributed Load Balancer) 节点, 我们以低成本提高了可用性 avaibability 和耐用性 durability , 因为由于无服务器技术 serverless , 我们实际上不需要维护(监控升级和安全补丁)服务器. 同时, 我们正在通过CloudFlare工作程序将请求转发到”最快的”原始服务器, 该节点在地理位置上会接近用户(拥有低延迟).
我们也可以: 通过AWS Lambda / API Gateway 架设负载均衡API服务器 (Load Balancer)
英文: Tutorial: How to Set Up a API Load Balancer by Using CloudFlare Worker?
本文一共 811 个汉字, 你数一下对不对.上一篇: HPZ800服务器主板太老不支持超过2TB的大硬盘
下一篇: 在竞赛中通过向标准输出stdout打印数据来调试leetcode程序


话说你这个是并发请求 接受最早返回的 不算负载均衡吧
负载均衡有很多算法, 可以是 Round-robin, 可以是 least load, 为什么就不能是 fastest 呢? 返回最快的那个而且必须是200的.