zoukankan      html  css  js  c++  java
  • 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左右,需根据项目评估性能

  • 相关阅读:
    8.1.3 CSS3选择器 —— 伪类
    8.1.2 CSS3选择器 —— 结构性伪类
    VI打开和编辑多个文件的命令
    vi全局替换方法
    更改Ubuntu 12.04默认的shel
    如何区分直连串口线和交叉串口线?
    [转]OpenWrt的dl下载地址
    关闭 ubuntu System program problem detected
    linuxC学习
    aa
  • 原文地址:https://www.cnblogs.com/zihunqingxin/p/13551671.html
Copyright © 2011-2022 走看看