minio update meta info 更新minio S3对象存储meta的实现方法

minio update meta info 更新minio S3对象存储meta的实现方法

应用场景

对象存储就不多作介绍了

亚马逊,阿里云,金山云,都有相应的对象存储服务

常见的方案有ceph,minio等

amazon S3 是事实上的标准,金山云,minio都支持S3协议

通常对象存储,存一些小文件,又以互联网的媒体文件为主,例如图片,视频等等

现将大数据中的部分媒体文件迁至minio,该工作基本已全部做完

要对媒体文件,附加深度学习/机器学习算法应用ocr,语音识别等算法结果

通过sql/nosql外部存储,保存映射关系的方案就不提了,各有优缺点

缺点主要是又引入了一重依赖,复杂度相对较高,考虑在直接在meta上附加信息

因为要应用各种算法,所以为了方便对接,直接相关项目,也部分采用了python实现,以下示例全部为python,其他语言也类似

首先 minio上传文件时可以附加meta信息

https://docs.min.io/cn/python-client-api-reference.html#put_object

# Put an object 'myobject' with contents from '/tmp/otherobject', upon success prints the etag identifier computed by server.
try:
print(minioClient.fput_object('mybucket', 'myobject', '/tmp/otherobject'))
except ResponseError as err:
print(err)

# Put on object 'myobject.csv' with contents from
# '/tmp/otherobject.csv' as 'application/csv'.
try:
print(minioClient.fput_object('mybucket', 'myobject.csv',
'/tmp/otherobject.csv',
content_type='application/csv'))
except ResponseError as err:
print(err)

在metadata中存储附加信息,但是这只是文件上传时可以附加,而大数据和各种数据挖掘算法的应用较为耗时,通常是异步,延后更新的

需要找到update object metadata的方法

遗憾的是 https://docs.min.io/cn/python-client-api-reference.html 查官方各语言的api文档,都不提供update方法

所以就只能用外部存储了?看官方文档没有update方法,通常就放弃了,有精力去官方提issue,或改代码提merget,精力有限,这个先跳过

只是总觉得不应该这样,个人评判一个技术产品和一个功能需求时,大概会考虑这个需求是否普遍,再考虑技术产品的生态成熟度

update object metadata 是较为普遍的功能需求,minio是较为成熟优秀的对象存储方案,这种功能,在未看文档前,我预期的是会支持才对

---

没有找到原生的update object metadata sdk/api 看能不能在其他sdk/api上想办法实现

put_res = client.put_object(bucket_name, object_name, BytesIO(
msg), len(msg), content_type=content_type, metadata={})
('f124631fb276876f23e0c8d81f3649ae', None)

调用put_object的返回值put_res 包含上传对象的md5值

minio 实现put_object会不会检查客户端和服务器同名object的md5?如果完全一致,就免去该次put_object的网络io呢?(百度云的秒传,大概就是这种思路)


来作测试

def test_bif_file_multi_put_same_file():
MINIO_ACCESS_KEY = "AKIAIOSFODNN7EXAMPLE"
MINIO_SECRET_KEY = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
ENDPOINT = "192.168.5.196:9000"
start_time = time.time()
fileBytes = readFileBytes("./NVIDIA-Linux-x86_64-450.51.06.run")
minioClient = Minio(ENDPOINT, access_key=MINIO_ACCESS_KEY,
secret_key=MINIO_SECRET_KEY, secure=False)
put_res = putObject(minioClient, "testbucketname",
"objectest2.jpeg", fileBytes, 'image/jpeg', None)
first_finish_time = time.time()
print("第一次上传时间时间开销", first_finish_time-start_time)
put_res = putObject(minioClient, "testbucketname",
"objectest2.jpeg", fileBytes, 'image/jpeg', None)
secend_finish_time = time.time()
print("第二次上传时间时间开销", secend_finish_time-first_finish_time)


# 第一次上传时间时间开销 19.879034519195557
# 第二次上传时间时间开销 22.13285183906555

很遗憾并不是期望中的那样,大文件的第二次上传,依然会花费同样的时间,很失望


另外又看到一个api

import os
# Put a file with default content-type, upon success prints the etag identifier computed by server.
try:
with open('my-testfile', 'rb') as file_data:
file_stat = os.stat('my-testfile')
print(minioClient.put_object('mybucket', 'myobject',
file_data, file_stat.st_size))
except ResponseError as err:
print(err)

https://docs.min.io/cn/javascript-client-api-reference.html#copyObject

var conds = new Minio.CopyConditions()
conds.setMatchETag('bd891862ea3e22c93ed53a098218791d')
minioClient.copyObject('mybucket', 'newobject', '/mybucket/srcobject', conds, function(e, data) {
if (e) {
return console.log(e)
}
console.log("Successfully copied the object:")
console.log("etag = " + data.etag + ", lastModified = " + data.lastModified)
})


上传从客户端到服务端,要上传完整的文件流

但copy总不会也这样,对象存付,底层二进制,上层只是一个引用,copy一般是加一个引用信息,不会把文件io再跑一次

但是copy_object(bucket_name, object_name, object_source, copy_conditions=None, metadata=None)

copy_object 又是可以附加文件信息的

stat_object(bucket_name, object_name)


而旧文档的metadata是可以拿到的

已知这些信息,就有了一个实现方案,是否可执行还需验证

有经验的开发人员应该都也想到了

1 stat_object 获取old object meta
2 old object meta 附加新的值,生成new object meta
3 copy old object -> other ojbect

其实这一步对一些场景已经可以满足了
原始文件放在 /old/object1
附加meta的文件放在 /new/object1 新地址的object1已经有附加的meta信息

4 对要修改old object meta值的 再执行 copy other ojbect -> old ojbect

5 完成更改后 remove other ojbect


已验证可行,具体代码如下,代码比较粗略,主要是提供一种思路


def updateObjectMeta(client=minioClient, bucket_name=None, object_name=None, metadata=None, is_merge=True):
"""
更新meta
!注意,官方不提供该功能,目前通过多次copy实现,网络io较多
"""
if not metadata:
raise Exception("未定义待更新meta")
new_metadata = metadata
# merge meta
if is_merge:
exist_res = client.stat_object(bucket_name, object_name)
old_metadata = exist_res.metadata
for key in metadata:
old_metadata[key] = metadata[key]
new_metadata = old_metadata
tmp_object_name = object_name+"_update_metadata_tmp"
# source obj -> tmp-obj
tmp_obj_res = client.copy_object(
bucket_name, tmp_object_name, bucket_name+"/"+object_name)
print("copy to tmp", bucket_name, tmp_object_name,
bucket_name+"/"+object_name, tmp_obj_res)
# tmp-obj -> source obj with new metadata
print("new_metadata", new_metadata)
org_obj_res = client.copy_object(
bucket_name, object_name, bucket_name+"/"+tmp_object_name, metadata=new_metadata)
print("copy to back", bucket_name, object_name,
bucket_name+"/"+tmp_object_name, org_obj_res)
# remove tmp-obj
client.remove_object(bucket_name, tmp_object_name)


缺点也很明显,会有多次的网络io,单机本地测试,每次io在300ms左右,需根据项目评估性能

原文地址:https://www.cnblogs.com/zihunqingxin/p/13551671.html