当前位置: 首页 > 后端技术 > Java

分布式文件上传导致服务卡顿?

时间:2023-04-01 23:54:59 Java

介绍记得刚开始学习web项目的时候,经常会涉及到上传图片。当时把图片上传到当前项目文件夹,每次重启项目,图片都丢失了。虽然可以通过修改/tomcat/conf/server.xml配置文件配置上传图片的本地文件夹,即配置项目配置虚拟路径,这样可以避免项目重启时图片丢失。参加工作以来,基本没遇到过使用这种方式存储图片。通常,您要么构建自己的文件服务器,要么使用付费文件服务。比如七牛云、阿里云、腾讯云等。今天我们就来说说如何使用阿里云OSS文件上传。oss文件上传使用OSS文件上传,阿里云提供了以下几种方式,您可以选择适合自己的方式。Web上传Web上常见的上传方式是用户通过浏览器或App将文件上传到应用服务器,应用服务器再将文件上传到OSS。具体过程如下图所示。这种方法绝对不可取。缺点如下:上传慢:用户数据需要先上传到应用服务器,再上传到OSS,网络传输时间是直接上传到OSS的两倍。如果用户数据不通过应用服务器中转,而是直接传输到OSS,速度会大大提高。而且OSS采用BGP带宽,可以保证各地不同运营商之间的传输速度。扩展性差:如果后续用户逐渐增多,应用服务器就会成为瓶颈。已经用OSS上传了,以后还要占用自己的服务器。成本高:需要准备多台应用服务器。由于OSS上行流量是免费的,如果直接将数据传输到OSS,将节省多台应用服务器的成本。JavaScript客户端签名直传方式采用的是纯前端直接上传,不经过应用服务器,但是阿里云在这种方式下提供了OSS上传的一些核心参数(AccessKeyID和AccessKeySecret相当于我们的账号和旁边申请的密码)也需要写在前端代码中,这样很容易导致我们的核心参数泄露。存在安全隐患。这种方法也不推荐。如果将服务端签名直接上传到前端,会存在安全隐患和参数泄露。我们可以把参数放在服务器端,然后服务器端跟阿里云交互,这样就不会泄露核心参数。如何接入和引入依赖因为我是搞java开发的,直接导入官方提供的最新的maven依赖。com.aliyun.ossaliyun-sdk-oss3.14.0为什么要引入最新的依赖。因为如果你遇到什么问题需要找阿里云的人帮忙解决,一般人会问你SDK是什么版本,遇到短时间内很难解决的问题,他们会建议你升级到最新版本试试。因为你遇到的bug可能会在最新版本中得到修复。可能有人会说,推出最新版本不就是为了帮助别人入坑吗?如果解决一个错误会引入两个错误列怎么办?这种情况并非不可能。上图是官网提供的介绍示例。代码很多。我们可以看一下稍微优化一下的代码:创建一个ossClient的单实例,可以复用线程,不需要去newossClient().Stringhost=String.format("https://%s.%s",ossPropertoooies.getBucketName(),ossPropertoooies.getEndpoint());longexpiredTime=System.currentTimeMillis()+fileOssProperties.getUploadSignatureTtl();日期到期=新日期(过期时间);//根据文件名和文件类型设置存储路径,可以根据文件类型+日期格式+UUID文件名来划分Stringfilepath=getFilePath(request.getCategory(),request.getFilename());PolicyConditionspolicyConditions=newPolicyConditions();policyConditions.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE,0,fileOssProperties.getUploadSizeLimit());policyConditions.addConditionItem(MatchMode.StartWith,PolicyConditions.COND_KEY,filepath);StringpostPolicy=ossClient.generatePostPolicy(expiration,policyConditions);byte[]binaryData=postPolicy.getBytes(StandardCharsets.UTF_8);字符串encodedPolicy=BinaryUtil.toBase64String(binaryData);StringpostSignature=ossClient.calculatePostSignature(postPolicy);SignatureDTO签名=newSignatureDTO();signature.setAccessId(ossPropertoooies.getAccessKeyId());signature.setPolicy(encodedPolicy););signature.setFilepath(文件路径);signature.setHost(主机);signature.setExpire(fileOssProperties.getUploadSignatureTtl()/1000);signature.setReqFilename(request.getFilename());连接起来很简单,前端一个Signature之后,前端上传前后的文件上传就完成了。这里我们使用postman来模拟前端上传。当然也可以改成在前端使用ajax,也可以使用其他方式。上传的url由我们自己申请的bucketname和endpoint组成,但其实里面有很多坑,还是需要注意一下。带宽限制上传和下载都会有带宽限制。如果我们使用外网直接上传到阿里云oss,需要注意我们的外网带宽是否足够,上传大文件会不会把带宽占满。如果带宽满了,我们上传,就gg了。同样下载也有带宽限制,要避免下载大文件。如果遇到这么大的文件下载,我们可以使用其他方法,比如使用oss客户端。所以我们需要合理的考虑我们服务器的带宽。如果我们的应用直接部署在阿里云上,我们可以使用内网上传下载。这样就没有带宽限制。API使用需要注意。我们在使用OSSclient提供的一些API的时候,需要仔细看看它是如何实现的,或者看看它的文档中有没有特别的说明。比如使用OSSclient提供的processObject方法,我们需要在最后关闭输入流。如果流没有关闭,连接将不会被释放。应用链接会立刻被占满,然后服务就会变成假死状态。我们在生产环境遇到过一次这个问题。如下图,线程还没有被释放。为什么要这样手动关闭流,为什么不直接帮我们关闭API,阿里云的回复是因为这里返回的流可能需要业务方复制或者读取。因此,调用者需要主动关闭它。我们也在这份非常机密的文件中找到了答案。最后,由于自己的无知和知识的匮乏,难免有错误。如果您发现错误,请留言指出给我,我会改正。如果您觉得文章还不错,您的转发、分享、欣赏、点赞、评论就是对我最大的鼓励。感谢您的阅读,非常欢迎并感谢您的关注。站在巨人的肩膀上摘苹果:https://help.aliyun.com/docum...https://gosspublic.alicdn.com...