文盘Rust —— rust连接oss | 京东云技术团队
作者:京东科技 贾世闻
对象存储是云的基础组件之一,各大云厂商都有相关产品。这里跟大家介绍一下rust与对象存储交到的基本套路和其中的一些技巧。
基本连接
我们以 [S3 sdk](
https://github.com/awslabs/aws-sdk-rust)为例来说说基本的连接与操作,作者验证过aws、京东云、阿里云。主要的增删改查功能没有什么差别。
- 建立客户端
let shared_config = SdkConfig::builder()
.credentials_provider(SharedCredentialsProvider::new(Credentials::new(
"LTAI5t7NPuPKsXm6UeSa1",
"DGHuK03ESXQYqQ83buKMHs9NAwz",
None,
None,
"Static",
)))
.endpoint_url("http://oss-cn-beijing.aliyuncs.com")
.region(Region::new("oss-cn-beijing"))
.build();
let s3_config_builder = aws_sdk_s3::config::Builder::from(&shared_config);
let client = aws_sdk_s3::Client::from_conf(s3_config_builder.build());
建立Client所需要的参数主要有你需要访问的oss的AK、SK,endpoint url 以及服务所在的区域。以上信息都可以在服务商的帮助文档查询到。
- 对象列表
let mut obj_list = client
.list_objects_v2()
.bucket(bucket)
.max_keys(max_keys)
.prefix(prefix_str)
.continuation_token(token_str);
let list = obj_list.send().await.unwrap();
println!("{:?}",list.contents());
println!("{:?}",list.next_continuation_token());
使用list_objects_v2函数返回对象列表,相比list_objects函数,list_objects_v2可以通过continuation_token和max_keys控制返回列表的长度。list.contents()返回对象列表数组,
list.next_continuation_token()返回继续查询的token。
- 上传文件
let content = ByteStream::from("content in file".as_bytes());
let exp = aws_smithy_types::DateTime::from_secs(100);
let upload = client
.put_object()
.bucket("bucket")
.key("/test/key")
.expires(exp)
.body(content);
upload.send().await.unwrap();
指定bucket及对象路径,body接受ByteStream类型作为文件内容,最后设置过期时间expires,无过期时间时不指定该配置即可。
- 下载文件
let key = "/tmp/test/key".to_string();
let resp = client
.get_object()
.bucket("bucket")
.key(&key)
.send()
.await.unwrap();
let data = resp.body.collect().await.unwrap();
let bytes = data.into_bytes();
let path = std::path::Path::new("/tmp/key")
if let Some(p) = path.parent() {
std::fs::create_dir_all(p).unwrap();
}
let mut file = OpenOptions::new()
.write(true)
.truncate(true)
.create(true)
.open(path).unwrap();
let _ = file.write(&*bytes);
file.flush().unwrap();
通过get_object()函数获取GetObjectOutput。返回值的body 就是文件内容,将 body 转换为 bytes,最后打开文件写入即可。
- 删除文件
let mut keys = vec![];
let key1 = ObjectIdentifier::builder()
.set_key(Some("/tmp/key1".to_string()))
.build();
let key2 = ObjectIdentifier::builder()
.set_key(Some("/tmp/key2".to_string()))
.build()
keys.push(key1);
keys.push(key2)
client
.delete_objects()
.bucket(bucket)
.delete(Delete::builder().set_objects(Some(keys)).build())
.send()
.await
.unwrap();
delete_objects 批量删除对象。首先构建keys vector,定义要删除的对象,然后通过Delete::builder(),构建 Delete model。
大文件上传
let mut file = fs::File::open("/tmp/file_name").unwrap();
let chunk_size = 1024*1024;
let mut part_number = 0;
let mut upload_parts: Vec = Vec::new();
//获取上传id
let multipart_upload_res: CreateMultipartUploadOutput = self
.client
.create_multipart_upload()
.bucket("bucket")
.key("/tmp/key")
.send()
.await.unwrap();
let upload_id = match multipart_upload_res.upload_id() {
Some(id) => id,
None => {
return Err(anyhow!("upload id is None"));
}
};
//分段上传文件并记录completer_part
loop {
let mut buf = vec![0; chuck_size];
let read_count = file.read(&mut buf)?;
part_number += 1;
if read_count == 0 {
break;
}
let body = &buf[..read_count];
let stream = ByteStream::from(body.to_vec());
let upload_part_res = self
.client
.upload_part()
.key(key)
.bucket(bucket)
.upload_id(upload_id)
.body(stream)
.part_number(part_number)
.send()
.await.unwrap();
let completer_part = CompletedPart::builder()
.e_tag(upload_part_res.e_tag.unwrap_or_default())
.part_number(part_number)
.build();
upload_parts.push(completer_part);
if read_count != chuck_size {
break;
}
}
// 完成上传文件合并
let completed_multipart_upload: CompletedMultipartUpload =
CompletedMultipartUpload::builder()
.set_parts(Some(upload_parts))
.build();
let _complete_multipart_upload_res = self
.client
.complete_multipart_upload()
.bucket("bucket")
.key(key)
.multipart_upload(completed_multipart_upload)
.upload_id(upload_id)
.send()
.await.unwrap();
有时候面对大文件,比如几百兆甚至几个G的文件,为了节约带宽和内存,我才采取分段上传的方案,然后在对象存储的服务端做合并。基本流程是:指定bucket和key,获取一个上传id;按流读取文件,分段上传字节流,并记录CompletedPart;通知服务器按照CompletedPart 集合来合并文件。具体过程代码已加注释,这里不再累述。
大文件下载
let mut file = match OpenOptions::new()
.truncate(true)
.create(true)
.write(true)
.open("/tmp/target_file");
let key = "/tmp/test/key".to_string();
let resp = client
.get_object()
.bucket("bucket")
.key(&key)
.send()
.await.unwrap();
let content_len = resp.content_length();
let mut byte_stream_async_reader = resp.body.into_async_read();
let mut content_len_usize: usize = content_len.try_into().unwrap();
loop {
if content_len_usize > chunk_size {
let mut buffer = vec![0; chunk_size];
let _ = byte_stream_async_reader.read_exact(&mut buffer).await.unwrap();
file.write_all(&buffer).unwrap();
content_len_usize -= chunk_size;
continue;
} else {
let mut buffer = vec![0; content_len_usize];
let _ = byte_stream_async_reader.read_exact(&mut buffer).await.unwrap();
file.write_all(&buffer).unwrap();
break;
}
}
file.flush().unwrap();
在从对象存储服务端下载文件的过程中也会遇到大文件问题。为了节约带宽和内存,我们采取读取字节流的方式分段写入文件。首先get_object()函数获取ByteStream,通过async_reader流式读取对象字节,分段写入文件。
对象存储的相关话题今天先聊到这儿,下期见。
文盘Rust —— rust连接oss | 京东云技术团队的更多相关文章
- springboot升级过程中踩坑定位分析记录 | 京东云技术团队
作者:京东零售 李文龙 1.背景 " 俗话说:为了修复一个小bug而引入了一个更大bug " 因所负责的系统使用的spring框架版本5.1.5.RELEASE在线上出过一个偶发的 ...
- 文盘Rust -- rust 连接云上数仓 starwift
作者:京东云 贾世闻 最近想看看 rust 如何集成 clickhouse,又犯了好吃懒做的心理(不想自己建环境),刚好京东云发布了兼容ck 的云原生数仓 Starwfit,于是搞了个实例折腾一番. ...
- JAE京东云引擎Git上传管理代码教程和京东云数据库导入导出管理
文章目录 Git管理准备工作 Git工具上传代码 发布代码装程序 mywebsql管理 京东云引擎小结 JAE京东云引擎是京东推出的支持Java.Ruby.Python.PHP.Node.js多语 ...
- 从单个系统到云翼一体化支撑,京东云DevOps推进中的一波三折
作者:王利莹 采访嘉宾:京东云DevOps团队负责人 郑永宽 今年,IDC 特别针对中国地区发布了<IDC MarketScape:中国 DevOps 云市场2019,厂商评估>研究报告, ...
- 京东云携手Mellanox,设计最先进SDN硬件加速功能并开源
京东云携手Mellanox,设计最先进SDN硬件加速功能并开源 最新技术播报 京东云开发者社区 导语新一代 SDN.NFV 和云原生计算技术正在推动应用实例的极限,这些实例可以在虚拟化和容器化的服务 ...
- 京东云开发者|京东云RDS数据迁移常见场景攻略
云时代已经来临,云上很多场景下都需要数据的迁移.备份和流转,各大云厂商也大都提供了自己的迁移工具.本文主要介绍京东云数据库为解决用户数据迁移的常见场景所提供的解决方案. 场景一:数据迁移上云 数据迁移 ...
- 融云技术分享:融云安卓端IM产品的网络链路保活技术实践
本文来自融云技术团队原创分享,原文发布于“ 融云全球互联网通信云”公众号,原题<IM 即时通讯之链路保活>,即时通讯网收录时有部分改动. 1.引言 众所周知,IM 即时通讯是一项对即时性要 ...
- 融云技术分享:解密融云IM产品的聊天消息ID生成策略
本文来自融云技术团队原创分享,原文发布于“融云全球互联网通信云”公众号,原题<如何实现分布式场景下唯一 ID 生成?>,即时通讯网收录时有部分改动. 1.引言 对于IM应用来说,消息ID( ...
- RUST actix-web连接有密码的Redis数据库
RUST actix-web连接有密码的Redis数据库 actix-web的example里面,使用了自己的actix-redis,但是我尝试了一下,并不好用 替换成另一连接池,deadpool-r ...
- 干货 | 基于Go SDK操作京东云对象存储OSS的入门指南
前言 本文介绍如何使用Go语言对京东云对象存储OSS进行基本的操作,帮助客户快速通过Go SDK接入京东云对象存储,提高应用开发的效率. 在实际操作之前,我们先看一下京东云OSS的API接口支持范围和 ...
随机推荐
- IDEA快键键设置为Eclipse快捷键
一.基础修改,参考这个就可以了 https://jingyan.baidu.com/article/6dad5075a5f7b4e122e36e4b.html 二.其他需要手动配置的快捷键修改(主要是 ...
- 在教学中常被问到的几个vue3.x与typescript的问题,统一解答
在教学当中,学生在学习vue3.x时,常常会问到typescript和vue3.x之间的关系,感觉这两个技术总是绑在一起的,下面老赵来统一解答一下: 那学vue3.x,为什么要求也要掌握typescr ...
- 利用SpringBoot实现数据库的增删改查(具体实现)
前言 本次主要是想利用SpringBoot的框架实现一下数据库的增删改查,所以只有一个较为简单的表作为案例 具体实现 1.在配置文件中配置一下相关内容 2.在pom.xml文件中导入相关坐标 3.编写 ...
- 使用Vue脚手架
关于不同版本的Vue: vue.js与vue.runtime.xxx.js的区别: (1) vue.js是完整版的Vue,包含: 核心功能+模板解析器 (2) vue.runtime.xxx.js是运 ...
- Django笔记九之model查询filter、exclude、annotate、order_by
在接下来四五篇笔记中,将介绍 model 查询方法的各个细节,为我们的查询操作提供各种便利. 本篇笔记将介绍惰性查找.filter.exclude.annotate等方法,目录如下: 惰性查找 fil ...
- JSTL标签fmt:formatDate格式化日期出错
现象&背景: 异常: "org.apache.jasper.JasperException: 在 [115] 行处理 [/WEB-INF/jsp/modules/receivedya ...
- # SpringBoot使用Validation校验参数 ##
SpringBoot使用Validation校验参数 一.简介 参考 (14条消息) 1. 不吹不擂,第一篇就能提升你对Bean Validation数据校验的认知_@decimalmax和@max_ ...
- 各类电商平台批量获取商品信息 API 详细操作说明
前言获取商品信息可以更加快捷的查看商品的详请参数,同理批量获取商品信息的话就可以查看多个商品的信息参数,便于我们查看整个店铺的数据情况方便运营管理.具体操作如下:先获取一个key和secret,登入测 ...
- mumpy常用函数
numpy.array(list(1,2,3,4)) #将一个list类型/tupe类型数据转换为一个array数组对象 #默认所有的数据类型都是相同,若传进来的参数类型不同,则遵循以下优先级: st ...
- ChatGPT 与 Midjourney 强强联手,让先秦阿房宫重现辉煌!
Midjourney 是一款非常特殊的 AI 绘画聊天机器人,它并不是软件,也不用安装,而是直接搭载在 Discord 平台之上,所有的功能都是通过调用 Discord 的聊天机器人程序实现的.要想使 ...