OSS与业务场景学习
9.1 Oss学习、Oss文件直传前端、耗时任务异步处理方式
- Oss搭建
- Oss文件传输直接与前端交互
- taskService线程轮询机制
- 重任务的异步处理
一、Oss
阿里云存储Oss,将文件图片等资源存储在云端。
应用场景:存储项目中文件、图片、音频等不易在数据库和服务器中存储的资源
解决问题:文件不经过Api服务器,减轻APi服务器压力。重数据不存在数据库中,减少数据库压力,提高读写性能
1.1 创建Bucket
- 注册阿里云账号
- 开通Oss
- 创键一个Bucket
1.2 权限设置
- 跨域设置
- RAM设置
首先,添加用户分配权限
,创建AccessKey密钥,拿到key和secret
接着,创建角色分配权限(跟用户一样),拿到
1.3 项目引用
写配置:
oss.endpoint=对应红框第一个
oss.key=获取的key
oss.secret=获取的secret
oss.bucket=自定义bucket名
oss.internalEndpoint=https://+你的oss.endpoint
oss.canonicalDomain=红框第二个
oss.cdnDomain=红框第二个
oss.region=cn-主机的地址(比如shanghai、beijing)
oss.putArn=创建角色获取的那个
oss.namespace=java07(可以自定义,也就是bucket的一级目录)
1.4 搭建与使用Oss业务框架
引入文件:
- common > file
二、OSS文件上传
fileService.upload():该方法提供了上传到OSS的接口。
参数:
- file:文件名
- options:上传的配置
public String upload(final File file, final UploadOptions options) throws Exception{// 通过配置项来配置上传的元数据。final ObjectMetadata metadata = new ObjectMetadata();String contentType = options.getContentType();if (contentType == null){contentType = Files.probeContentType(file.toPath());}if (contentType != null){metadata.setContentType(contentType);}if (options.getPermission() != null){switch (options.getPermission()){case PRIVATE:metadata.setObjectAcl(CannedAccessControlList.Private);break;case PUBLIC_READ:metadata.setObjectAcl(CannedAccessControlList.PublicReadWrite);break;default:break;}}// 如果配置中有文件名,则采取配置中的文件名,否则使用文件本身的名子final String fileName = options.getFileName() != null ? options.getFileName() : file.getName();// 生成不重复的key作为上传的文件路径+文件名(这样可以防止重名出错)。路径为:// namespace/year/month/day/(一位小写随机英文)/一个加密随机数+文件后缀final String objectKey = generateObjectKey(options.getNamespace(), fileName, options.getRandomLength());// 上传OSSossClient.putObject(ossConfig.getBucket(), objectKey, file, metadata);// 返回上传到云端后文件url路径return new StringBuilder("https://").append(ossConfig.getCanonicalDomain()).append("/").append(objectKey).toString();}
uploadToken():不参与上传,而是返回一张token表,前端拿到这张token表可以上传oss
download(url,file):通过url获取oss文件,并将文件写入到指定file中
…
三、Oss与前端直传
Oss与前端直传,能够减轻Api服务器压力,是提高Api服务器性能的一种方式
3.1 整体思想
前端调用接口,fileService.uploadToken通过前端传递过来的需求与Oss交互达成共识,再生成一张token表(携带oss直传地址等配置信息),前端即可通过发送http请求直接与oss进行交互。
四、轮询模式的线程引擎
对于一些我们想要异步处理的任务(往往这些任务的处理结果并不影响我们进行下一步操作),可以通过使用定制化任务来封装我们的特定任务,再通过线程任务执行服务,将我们的任务放入线程队列中通过线程池引擎轮询处理任务队列中进行等待处理。
4.1 TaskService(线程任务服务)
TaskService内部维护了一个TaskEngine(线程任务队列引擎)
TaskService通过在bean初始化的时候,初始化了TaskEngine来开启线程引擎,提供线程功能。
初始化动作
@PostConstructpublic void init(){if (maxPoolSize <= 0){throw new IllegalArgumentException("Bad maxPoolSize");}if (threshold <= 0){throw new IllegalArgumentException("Bad threshold");}engine = new TaskEngine("taskservice", maxPoolSize);}
我们可以看到,传递了两个参数
- 工作线程组名称
- 线程池的最大数量
提供的服务
- addTask():添加一个线程任务到线程队列中
- scheduleTask(Runnable task, long delay):添加一个延期执行的线程任务到Timer线程队列中
- scheduleTask(Runnable task, long delay, long period):添加一个延期且有周期性的执行的线程任务到Timer线程队列中,连续执行任务之间的周期,从上一个任务开始执行时计算延迟多少开始执行下一个任务,但是还会等上一个任务结束之后。
4.2 TaskEngine(线程任务队列执行引擎)
TaskEngine内部维护了:
- LinkedList taskList:线程任务队列
- Timer taskTimer:定时线程任务队列管理器(内部有一个定时线程任务队列)
- Thread[] workers:工作线程组
初始化动作
public TaskEngine(String groupName, int workerNum) {this.taskTimer = new Timer(true);this.workers = new Thread[workerNum];for(int i = 0; i < this.workers.length; ++i) {this.workers[i] = this.newTaskEngineWorker();this.workers[i].setName(groupName + "-" + (i + 1));this.workers[i].setDaemon(true);this.workers[i].start();}}
- 初始化taskTimer,开启定时任务队列轮询
- 初始化workers数组(线程池),大小为传递过来的参数
- 迭代所有工作线程并完成初始化(创建内部类TaskEngineWorker作为工作线程,起名字组名-序号,开启守护线程)
- 执行所有工作线程,开启任务队列轮询
4.3 TaskEngineWorker(工作线程)
工作线程开启之后,将以轮询的方式一直询问当前任务线程队列是否有未处理的线程任务,如果有就处理
public void run() {// 设置死循环while(true) {// 如果TaskEngine没有停止工作,就一直轮询任务队列)if (!TaskEngine.this.stopped) {// 尝试获取任务队列中的下一个任务Runnable task = TaskEngine.this.nextTask();// 如果当前任务不为空,则执行这个任务if (task != null) {try {task.run();} catch (Throwable var3) {TaskEngine.LOGGER.error((String)null, var3);}continue;}}return;}}
4.4 Timer(周期任务管理器)
Timer 内部定义了一个任务队列和一个周期任务的工作线程。该工作线程会在Timer被创建的时候创建,同时也会开启任务,对任务队列的任务根据轮询执行。
他就一个工作线程,来进行周期任务的执行
初始化动作
public Timer(String name, boolean isDaemon) {thread.setName(name);thread.setDaemon(isDaemon);thread.start();}
TaskQueue(线程队列)
private TimerTask[] queue = new TimerTask[128];
TimerTask(线程任务)
周期线程任务,内部定义了执行的状态,用于周期工作线程的调度
TimerThread(工作线程)
public void run() {mainLoop();
}
mainLoop():当队列中有任务的时候,该方法采取轮询的方式询问任务队列,会根据周期和延期规则,执行线程任务。
五、耗时任务异步线程处理方案(Excel文件导出为例)
对于耗时任务,我们可以另外开启一个异步线程去执行。这里我么要用到TaskService来执行异步任务
比如Excel文件导入Oss
5.1 类结构
- Heavy:任务表
- HeavyWorkService:提供了监控任务的一些方法,比如更改任务进度,获取任务进度,改变任务状态。
- ProgressAwareTask:任务进度调整类。内部维护了一个HeavyWorkService和当前任务heavy,提供了任务进度的改变的一些方法。
- ExportExcelTask:导出excel任务,继承了ProgressAwareTask,具备调整任务进度的能力,内部会自动生成xlsx文件,并将写入的内容写进去。
- ExportUsersTask:导出UserExcel表,继承了ExportExcelTask,具备导出内容到Excel表的能力,这里通过poi,从数据库中获取user信息,将其写入sheet中,最终转化为xlsx文件。并实时更新进度。
5.2 poi用法
创建一个book,定义每次写入数据
SXSSFWorkbook wb = new SXSSFWorkbook(batchNum);
创建一个sheet(也就是一页)
SXSSFSheet sheet = wb.createSheet(name);
创建行
Row row = sheet.createRow(从0开始的索引);
创建一个表格,并赋值
row.createCell(index).setCellValue(value);
写入文件
wb.write(file);
5.3 导出UserExcel业务流程
// 每次传输30条数据int batchNum = 30;SXSSFWorkbook wb = new SXSSFWorkbook(batchNum);SXSSFSheet sheet = wb.createSheet("用户");int rowIndex = 0;{int cellIndex = -1;Row row = sheet.createRow(rowIndex++);row.createCell(++cellIndex).setCellValue("姓名");row.createCell(++cellIndex).setCellValue("手机号");}qo.setPageSize(batchNum);while (true){// 每次获取30条数据Page<User> page = users(qo);if (page.isEmpty()){break;}for (User item : page.getContent()){int cellIndex = -1;Row row = sheet.createRow(rowIndex++);row.createCell(++cellIndex).setCellValue(item.getName());row.createCell(++cellIndex).setCellValue(item.getMobile());}if (page.getContent().size() < batchNum){break;}// 进入下一页qo.setPageNumber(qo.getPageNumber() + 2);// 更新当前任务状态进度doUpdateProgress(getProgress() + 90 / page.getTotalPages());}file = localFileHelper.createTmpFile("xlsx");// 写入文件{FileOutputStream out = new FileOutputStream(file);wb.write(out);out.flush();out.close();}// 上传前先报告一下状态doUpdateProgress(95);// 上传OssString exportUrl = fileService.upload(file, new UploadOptions().setPrivat(true));// 报告成功reportSuccess(exportUrl);
5.4 监控Excel导出进度
class ProgressDisplayTask implements Runnable{String secret;HeavyWorkService heavyWorkService;Integer progress = 0;public ProgressDisplayTask(String secret){this.secret = secret;heavyWorkService = UserServiceImpl.this.heavyWorkService;}@Overridepublic void run(){while (true){int curPress = progress;progress = heavyWorkService.getProgress(secret);if (progress != curPress){System.out.println("当前任务进度: " + progress + "%");}if (progress == 100){System.out.println("上传成功!!!");break;}try{Thread.sleep(5);} catch (InterruptedException e){e.printStackTrace();}}}}
5.5 将这两个线程任务放入taskService的工作队列中,进行异步访问
@Overridepublic HeavyWork exportUsers(UserQo qo){HeavyWork work = heavyWorkService.create(String.valueOf(UserContexts.getUserId()));taskService.addTask(new ProgressDisplayTask(work.getSecret()));taskService.addTask(new ExportUsersTask(work, qo));return work;}
这里直接返回当前任务表,并实时更新进度打印进度。
OSS与业务场景学习相关推荐
- 两亿多用户,六大业务场景,知乎AI用户模型服务性能如何优化?
作者 | 王政英 来源 | 知乎技术专栏 用户模型简介 知乎 AI 用户模型服务于知乎两亿多用户,主要为首页.推荐.广告.知识服务.想法.关注页等业务场景提供数据和服务,例如首页个性化 Feed 的召 ...
- rocketmq python 一个进程订阅多个topic_玩转不同业务场景,这些RabbitMQ特性会是得力助攻...
原标题:玩转不同业务场景,这些RabbitMQ特性会是得力助攻 我是在解决分布式事务的一致性问题时了解到的RabbitMQ,当时主要是要基于RabbitMQ来实现我们分布式系统之间对有事务可靠性要求的 ...
- 玩转不同业务场景,这些RabbitMQ特性会是得力助攻
来自:DBAplus社群 我是在解决分布式事务的一致性问题时了解到的RabbitMQ,当时主要是要基于RabbitMQ来实现我们分布式系统之间对有事务可靠性要求的系统间通信. 提到RabbitMQ,不 ...
- POLARDB产品特性和通用业务场景
2017云栖大会POLARDB专场,阿里云高级技术专家贺军带来POLARDB产品特性和通用业务场景的演讲.本文主要从POLARDB产品架构开始谈起,接着介绍了产品特性,最后着重分享了POLARDB通用 ...
- 神策数据成林松:数据智能在业务场景下的应用(附 PPT 下载)
在神策 2020 数据驱动用户大会「上海站」现场,神策数据业务咨询师成林松分享了<数据智能在业务场景下的应用>的演讲.(文末附 PPT 下载地址) 本文根据其演讲内容整理,数据均为虚拟. ...
- 结合业务场景案例实践分析,倾囊相授美团BERT的探索经验
Google 在 2018 年公布 BERT 的工作之后,引起了 NLP 学术圈以及工业界的极大关注.无论是在各个公司的应用场景中,还是在一些公开的 Benchmark 上,BERT 的效果都得到了验 ...
- 解读:在什么业务场景适合使用Redis?
Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言 ...
- 阿里开发者们的第15个感悟:做一款优秀大数据引擎,要找准重点解决的业务场景
2015年12月20日,云栖社区上线.2018年12月20日,云栖社区3岁. 阿里巴巴常说"晴天修屋顶". 在我们看来,寒冬中,最值得投资的是学习,是增厚的知识储备. 所以社区特别 ...
- bpmn2.0业务过程模型和符号_IT帮业务架构学习小组学习内容
关于学习内容,担心大家学完的可能不多,所以考虑是先选择一小部分来学.但考虑到业务架构属于组织级学科,本身就要求体系全面,所以还是决定把全套内容放入到本期学习.下面我列举一下我们这8个月在业务架构自主学 ...
最新文章
- java 自动封装_自动补全的java封装
- 和plc哪个简单点_怎么看PLC梯形图
- 数学建模学习笔记——相关性分析
- SAP CRM RDS快速部署解决方案
- andengine游戏引擎总结基础篇
- webgis 行政图报错_WebGIS 地图 示例源码下载
- RPC(一)[概述]
- 多校 HDU 6313 Hack It——构造
- BZOJ【1609】 麻烦的聚餐
- struts2学到屎挫死-深入Struts2(2)--Action
- 最新游戏帐号交易平台源码+支持游戏币交易
- 2019年中国研究生数学建模大赛的经验分享
- bootice 修改ubuntu win10 系统引导在一个硬盘上时的系统启动顺序
- du -c 单位 linux,Linux命令 du
- Vue入门 computer计算属性
- 代码没问题但运行不出来
- 语言模型及RNN模型
- rpa对json的支持
- [题解][Codeforces 1139A~1139F]Codeforces Round #548 (Div. 2) 简要题解
- 裁判文书网爬虫Docid解密思路