为了减少服务器的负载,针对IIS使用ServerFarm做了负载均衡,ServerFarm实质上是个消息分发模块。
不过ServerFarm有个不好的问题,所有对该服务器的访问都会被ServerFarm分发,没办法指定特定的端口(目前还没找到解决办法,望各位大神不吝赐教)。负载均衡之后一个紧急的问题就是服务器端的文件部署。
目前实现服务器端文件下载部署的死路有如下几个:
- 通过SVN或者TFS等源代码管理器,设置源代码的自动下载,达到文件统一部署的目的;
- 使用NodeJS在每个服务器添加一个端口监听,自己写一个文件下载服务,下载部署提交之后,调用Post请求每个服务器的监听端口,NodeJS在接收到请求之后,从文件服务器下载相应的文件。
对比两种思路,第一种虽然有可用的程序,但是无法达到自定义的目的,包括下载失败的提醒,下载日志的分发。所以采用了第二张思路。第二个思路主要分为两步,建立文件下载服务和创建端口监听
- 文件下载服务比较简单,在文件下载服务器添加一个网站,写一个文件上传的页面,将服务器文件上传至网站的特定目录(ServerFiles),这里就不再提供代码了;
- 创建端口监听:包括使用http.get从URL获取文件,由于文件都是zip压缩的,然后调用unzipper进行解压缩,指定解压缩的存放路径,最后删掉zip文件。当然,在下载过程中也可以对每一步添加日志记录,并且在下载之后对服务器的管理员添加消息分发。由于是服务器端的文件部署,为了防止意外,还可以在下载服务中添加回滚处理。由于只是做了个一个简单的下载部署,代码中没有包含这些,大家凑合着看哈。
const http = require('http'); const unzip = require('unzipper'); const filedeployserver = "http://FileServer:xxxx/ServerFiles/"; var download = function (url, dest, cb) { var fs = require('fs'); var file = fs.createWriteStream(dest); var request = http.get(url, function (response) { //下载文件保存 response.pipe(file); cb(`download ${dest} succ`); //将文件进行解压缩 fs.createReadStream(dest).pipe(unzip.Extract({ path: '..\\Bin\\' })); cb(`unzip ${dest} succ`); file.on('finish', function () { //删除zip文件 fs.unlink(dest, (err) => { if (err) throw err; cb(`delete ${dest} succ`); }); file.close(); }); }).on('error', function (err) { //出现下载失败 // fs.unlink(dest, (err) => { if (err) cb(`delete error: ${err.message} `); }); cb(`download error: ${err.message} `); }); }; const server = http.createServer((req, res) => { if (req.method === 'POST') { collectRequestData(req, result => { if (result != undefined) { var strs = result.replace(new RegExp('"', 'g'), '').split(","); for (var i in strs) { download(filedeployserver + strs[i], '..\\Bin\\' + strs[i], function (result) { var dt = new Date(); console.log(`${dt.toLocaleString()} ${result}`); }) } } console.log(`download all files succes`); res.end(`download all files succes`); }); } else { res.end(` <!doctype html> <html> <title>fileupload</title> <body> <form action="/" method="post"> <input type="text" name="fname" /><br /> <input type="text" name="url" /><br /> <input type="file" name="photo" /><br /> <button>commit</button> </form> </body> </html> `); } }); server.listen(3000); function collectRequestData(request, callback) { const FORM_URLENCODED = 'application/json'; if (request.headers['content-type'] === FORM_URLENCODED) { let body = ''; request.on('data', chunk => { body += chunk.toString(); }); request.on('end', () => { callback(body); }); } else { callback(null); } }