当前的多机集群系统中,文件(附件)的上传、下载服务是通过网络文件系统(NFS),在NFS的应用中,本地NFS的客户端应用可以透明地读写位于远端NFS服务器上的文件,就像访问本地文件一样,以此形成集成负载均衡方式环境下的共享盘功能,如下图所示。


[原]优化文件下载性能,缓存MongoDB GRIDFS文件(实践讨论稿)

在系统中,文件管理使用MongoDB Gridfs,如下图所示,文件下载过程中,先把MongoDB中的文件读取到NFS中,再通过系统Web服务下载文件,实际上是通过NFS缓存文件共享方式提供下载服务。


[原]优化文件下载性能,缓存MongoDB GRIDFS文件(实践讨论稿)

下面示例为Web服务端下载javascript代码。

//下载附件 function downloadFile(fileId) { $.cordys.utils.sendCordysAjax({ method: 'GetFileById', namespace: 'http://unicom.com/common/attachment', parameters: { fileId: fileId, gridFSName: window.isTransWkfl ? window.opener.bizRvsnNumber : window.bizRvsnNumber } }).done(function (response) { var downloadFileUrl = response['tuple']['old']['C_MONGODB_FILE']['FILE_PATH']; if (downloadFileUrl) { window.open(downloadFileUrl); } }).fail(function (returnData) { alert('附件下载失败!'); console.error('error' + returnData) }); }

下面示例为下载Webservice代码。

public static com.unicom.common.attachment.C_MONGODB_FILE getFileByIdImp(String fileId, String gridFSName) { try { DB db = MongoDBUtil.getDB(); GridFS gridFS = new GridFS(db, gridFSName); ObjectId objId = new ObjectId(fileId); GridFSDBFile gridFSDBFile = (GridFSDBFile) gridFS.findOne(objId); C_MONGODB_FILE fileDetail = new C_MONGODB_FILE(); if (gridFSDBFile != null) { SimpleDateFormat sdfFileName = new SimpleDateFormat("yyyy-MM-dd_hh-mm-ss.SSS"); String fileSize = Float.toString(gridFSDBFile.getLength()); String fileType = gridFSDBFile.getContentType(); String fileName = sdfFileName.format(new Date()) + "." + fileType; InputStream inputStream = gridFSDBFile.getInputStream(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); String datePath = sdf.format(new Date()); String downloadPath = EIBProperties.getInstallDir() + File.separator + "webroot" + File.separator + "shared" + File.separator + "download" + File.separator + datePath + File.separator; String fileFullName = downloadPath + fileName; String filePath = "/cordys/download/" + datePath + "/" + fileName; String fileUploader = (String) gridFSDBFile.get("fileUploader"); File file = new File(downloadPath); if (!file.exists()) { file.mkdirs(); } file = new File(fileFullName); if (!file.exists()) { file.createNewFile(); } else { file.delete(); file.createNewFile(); } OutputStream outputStream = new FileOutputStream(file); int byteCount = 0; while ((byteCount = inputStream.read()) != -1) { outputStream.write(byteCount); } outputStream.flush(); inputStream.close(); outputStream.close(); fileDetail.setFILE_ID(fileId); fileDetail.setFILE_NAME(fileName); fileDetail.setFILE_TYPE(fileType); fileDetail.setFILE_SIZE(fileSize); fileDetail.setFILE_CONTENT(filePath); fileDetail.setFILE_PATH(filePath); fileDetail.setFILE_UPLOADER(fileUploader); return fileDetail; } else { return null; } } catch (UnknownHostException e) { return null; } catch (IOException e) { return null; } finally { } }

在使用过程中出现如下图性能问题,对于大附件,容易出现下载失败的问题(实质为超时)。


[原]优化文件下载性能,缓存MongoDB GRIDFS文件(实践讨论稿)
分析原因

在负载均衡集群环境中,并发量大或文件体积大的时候,NFS系统可能存在瓶颈问题,特别是下载操作时,多出一步从MongoDB读取文件写入NFS的过程。如果写入时间过长,则将造成Web服务端请求超时。

上传附件过程,一般体现不出来。主要是上传附件到缓存NFS后,再写入MongoDB,而此时已经是异步操作,上传的响应已经反馈了。

解决方案

1、临时解决方案,延长Webservice超时时长;

2、优化NFS缓存文件管理,减少“从MongoDB读取文件写入NFS”的次数。优化方案设计图如下:


[原]优化文件下载性能,缓存MongoDB GRIDFS文件(实践讨论稿)

3、每台服务器上都生成可下载的缓存文件,抛弃文件共享盘。

设计思路

按方案2的设计如下,首先创建个附件缓存表,记录上传、下载过程中的缓存文件,方便多次重复使用文件。

1、附件缓存表结构

字段名称 类型 说明 文件ID 字符 上传时间 时间 为了与上传附件复用 初次下载时间 时间 文件名称 字符 显示出的中文名称,方便维护 文件缓存路径 字符 文件相对路径和名称 组织DN 字符 为了区分租户

第一次下载失败(超时),但是在异步情况下,缓存文件已经产生,下次下载时,就不必再从MongoDB中读取写到缓存中,提高了系统性能。

2、缓存使用过程。

3、生成缓存并下载过程

欢迎讨论分享。

参考:

集群环境下文件上传方法与运维(Uploading a File to a Service) 肖永威 2016.08

本文数据库(综合)相关术语:系统安全软件

分页:12
转载请注明
本文标题:[原]优化文件下载性能,缓存MongoDB GRIDFS文件(实践讨论稿)
本站链接:http://www.codesec.net/view/482885.html
分享请点击:


1.凡CodeSecTeam转载的文章,均出自其它媒体或其他官网介绍,目的在于传递更多的信息,并不代表本站赞同其观点和其真实性负责;
2.转载的文章仅代表原创作者观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,本站对该文以及其中全部或者部分内容、文字的真实性、完整性、及时性,不作出任何保证或承若;
3.如本站转载稿涉及版权等问题,请作者及时联系本站,我们会及时处理。
登录后可拥有收藏文章、关注作者等权限...
技术大类 技术大类 | 数据库(综合) | 评论(0) | 阅读(32)