原则

  1. 业务和业务之间的文件交互使用接口处理;
  2. 业务内部各服务之间的文件交互使用对象存储,例如MinIO;
  3. 每个业务使用自己的对象存储账号、对象存储桶,不同业务间的账号及桶不互通;
  4. 业务负责自己的文件数据管理,例如从其它业务拿到的数据是否缓存、是否定期清理;

文件接口设计规范

  1. 每个业务必须有一个文件服务file;
  2. GET请求方式;
  3. 接口路径由 /file/file_address 组成,file_address可以是文件ID(例如UUID),也可以是随机码(临时路径,隐藏真实文件信息,控制访问时效),但不可以是对象存储桶路径;
  4. 接口路径使用小写字母;
  5. 单词间使用下划线分割;
  6. 文件接口应有时效控制机制;

MinIO开发文档

MinIO管理页面

太养业务,MinIO对象存储访问信息
endpoint: 192.168.10.136:9000
bucket_name: taiyang
access_key: taiyang
secret_key: Ty123456

太财业务,MinIO对象存储访问信息
endpoint: 192.168.10.136:9000
bucket_name: taicai
access_key: taicai
secret_key: Tc123456

算法业务,MinIO对象存储访问信息
endpoint: 192.168.10.136:9000
bucket_name: alg
access_key: alg
secret_key: Aa123456

MinIO文档
https://docs.min.io/docs/

MinIO Java SDK
https://docs.min.io/docs/java-client-quickstart-guide.html
MinIO Java SDK Examples
https://github.com/minio/minio-java/tree/release/examples

MinIO Python SDK
https://docs.min.io/docs/python-client-quickstart-guide.html
MinIO Python SDK Examples
https://github.com/minio/minio-py/tree/release/examples

MinIO对象存储客户端设计规范

客户端封装成一个class;
客户端class包含函数read,需要参数path(对象存储桶内的路径),返回字节数据流;
客户端class包含函数write,需要参数path(对象存储桶内的路径)、data(需要写入的数据,Java可以根据data数据类型实现多个write重载函数,Python可以根据data数据类型实现不同的逻辑分支);

代码示例

from minio import Minio
from typing import Union
import io
import json
import numpy as np
from PIL import Image

from ..config import settings


class KVIO:

    def __init__(self):
        self.client = Minio(
            endpoint=settings.MINIO_ENDPOINT,
            access_key=settings.MINIO_ACCESS_KEY,
            secret_key=settings.MINIO_SECRET_KEY,
            secure=False,
        )
        self.bucket_name = settings.MINIO_BUCKET_NAME

    def read(self, path: str) -> bytes:
        path = path.rstrip("/")
        data = self.client.get_object(self.bucket_name, path).read()
        return data

    def read_as_str(self, path: str) -> str:
        data = self.read(path)
        return data.decode()

    def read_as_json(self, path: str) -> Union[dict, list]:
        data = self.read(path)
        return json.loads(data)

    def read_as_numpy(self, path: str) -> np.ndarray:
        data = self.read(path)
        return np.frombuffer(data)

    def read_as_image(self, path: str) -> Image.Image:
        data = self.read(path)
        return Image.open(io.BytesIO(data))

    def write(self, path: str, data: Union[bytes, str, dict, list, tuple, np.ndarray, Image.Image]):
        path = path.rstrip("/")
        if isinstance(data, bytes):
            with io.BytesIO(data) as fo:
                self.client.put_object(self.bucket_name, path, fo, fo.getbuffer().nbytes)
        elif isinstance(data, str):
            with io.BytesIO(data.encode()) as fo:
                self.client.put_object(self.bucket_name, path, fo, fo.getbuffer().nbytes)
        elif isinstance(data, (dict, list, tuple)):
            with io.BytesIO(json.dumps(data, ensure_ascii=False).encode()) as fo:
                self.client.put_object(self.bucket_name, path, fo, fo.getbuffer().nbytes)
        elif isinstance(data, np.ndarray):
            with io.BytesIO(data.tobytes()) as fo:
                self.client.put_object(self.bucket_name, path, fo, fo.getbuffer().nbytes)
        elif isinstance(data, Image.Image):
            with io.BytesIO() as fo:
                data.save(fo, 'png')
                fo.seek(0)
                self.client.put_object(self.bucket_name, path, fo, fo.getbuffer().nbytes)
        else:
            raise Exception(f'不支持的数据类型 [{type(data)}]')

最后编辑:2022年01月25日 ©著作权归作者所有

评论已关闭