オブジェクトストレージとは?

tiledbの使い方の基本

まず、知っておきたいのは、TileDBはmariadbやmysqlののようにサーバクライアント方式のデータベースではないということ。どちらかというと、sqliteやhdf5のように、ライブラリとして提供されているものだと思ってほしい。しかし、なんとデータの実態はリモートに置いておいて、httpでそのデータを取ってくるってこともできる。この時に、オブジェクトストレージってのが使われます。

で、c++とpythonの二つがあるけど、使いやすいし、今回はpythonでやろうと思う。環境構築はいたって簡単。condaとかで新しい環境を作って、

pip install tiledb

をするだけです。 非常に簡単!で、ここからは使い方ですね。

import

import tiledb

空間とスキーマを定義し、

# Don't forget to 'import numpy as np'
dom = tiledb.Domain(tiledb.Dim(name="rows", domain=(1, 4), tile=4, dtype=np.int32),
                    tiledb.Dim(name="cols", domain=(1, 4), tile=4, dtype=np.int32))

schema = tiledb.ArraySchema(domain=dom, sparse=False,
                            attrs=[tiledb.Attr(name="a", dtype=np.int32)])

データベースの名前を定義

array_name = "quickstart_dense"
tiledb.DenseArray.create(array_name, schema)

重要事項

上のarray_nameっていうので、データのディレクトリが指定されます。ただ、ここには、次のような形式でパスを指定することもできるし、 リモートにあるオブジェクトストレージにアクセスすることだって可能です。こんな感じです。

array_name = 'file:///home/usrname/my_array
array_name = 's3://bucket-name/array-name'

みたいな感じですね。ここで出てきたs3っていうのが、僕にとっては初耳の知識でした。結構web業界では使われてるみたいですね。 amason simple storege service (amazon s3)とは、オブジェクトストレージサービスです。 ブロックストレージというのがいつも使っているハードディスクとかssdとか、あの辺のやつね。 じゃあオブジェクトストレージとは何か?って話なんだけど、 まあ簡単に言うと、ファイルシステムが入っていななくて、データ単体をオブジェクトとして保存している、というかんじ。

Object storage systems typically do not have a traditional file system hierarchy within them. Instead, they store data as objects, each with its own unique identifier (often called a key) and associated metadata. These objects are typically organized in a flat namespace rather than a hierarchical directory structure.

In a traditional file system, you have directories (folders) that contain files, and you navigate through the hierarchy to access your data. In contrast, object storage relies on a flat namespace where each object is stored independently and accessed by its unique key. This approach simplifies data management and makes it well-suited for storing large volumes of unstructured data, such as images, videos, documents, and backups.

オブジェクトストレージはファイルシステムを持っていなくて、フラットなデータストレージ上にキーとそのデータを保管しているんだね。key-valueストアだね。その構造についてだけど、実際にハードディスクへの書き込みをするコンポーネントが合って、メタデータを管理するコンポーネントがあって、httpでのアクセスに対して処理をするコンポーネントがある。

オブジェクトストレージはどうやって作るのか?

so tell me boy. When I want to mount a new hdd or ssd on my linux pc I usually use fdisk to make partition and after that I format the partition with specific filesystem and we call it object storage right?
But when I want to create an object storage, how to do that?
Creating an object storage system is a bit different from the process of adding a new hard drive or SSD to your Linux PC and setting up traditional block storage with partitions and file systems. Object storage is designed for different use cases and doesn't involve creating partitions or file systems like you would with block storage.

Here are the general steps to create and set up an object storage system:

Select Object Storage Software: Choose an object storage software or service. Some popular open-source object storage solutions include Ceph, MinIO, and OpenStack Swift. Alternatively, you can use cloud-based object storage services like Amazon S3, Google Cloud Storage, or Azure Blob Storage.

Install and Configure Object Storage Software:

If you're using open-source object storage software, you'll need to install and configure it on your servers or cloud infrastructure. Configuration typically involves specifying storage devices or storage pools to use and setting up network and security settings.
Create Buckets/Containers: In object storage, data is organized into containers or buckets (depending on the terminology used by the software or service). Buckets are logical containers for objects. You'll need to create buckets to store your objects. These buckets are often accessed via a unique URL or identifier.

Upload Objects: You can upload objects to your object storage system using its API, command-line tools, or a web interface. Each object will have a unique identifier or key that you specify, along with any associated metadata.

Access Objects: Objects in an object storage system are accessed via their unique keys or URLs. You can use HTTP(S) requests to retrieve, update, or delete objects. Object storage APIs provide methods for managing and accessing objects programmatically.

Set Data Policies: Configure data policies for redundancy, access control, and versioning. Many object storage systems offer features like data replication across multiple locations for high availability and durability.

Manage Metadata: You can manage metadata associated with objects to add context and categorize your data. Metadata can be used for search and organization.

Monitor and Maintain: Regularly monitor the health and performance of your object storage system. This includes monitoring storage capacity, network bandwidth, and the overall status of your storage infrastructure.

Scale as Needed: Object storage systems are designed to be highly scalable. If you need more storage capacity or performance, you can add additional storage nodes or devices to your cluster.

In summary, object storage is a different paradigm from traditional block storage with partitions and file systems. It's designed for storing large volumes of unstructured data and is accessed via unique object keys. The setup and management of object storage involve configuring software or services, creating containers or buckets, and working with objects and metadata. It's a suitable choice for scenarios where scalability, durability, and simplicity in managing large datasets are important.

s3とminioについて

amason simple storege service (amazon s3)とは、アマゾンが提供するオブジェクトストレージサービスです。 で、オブジェクトストレージって言いうのはhttpでデータのやりとりをするストレージですね。はい。tiledbはs3をバックエンドにすることができるらしいのですが、awsを契約するのも面倒ということなので、s3と完全に互換性があるオープンソフトであるminioを使うことにしました。

tiledb on minio backend

minioのセットアップ

  1. バイナリのダウンロード (githubを見ればわかります。)
  2. bucketとして使われるディレクトリの作成。 (mkdir /path/to/bucket)
  3. サーバの起動。以下のコマンドで起動できる。
./minio server /bucket/direcory/ --console-address :9090
  1. これで、サーバが走っている9090ポートにブラウザでアクセスするとminioのダッシュボードに入れます。(注意:ダッシュボードは9090で動いているけど、オブジェクトストレージのエンドポイントは9000で動いているから、気を付けてくださいね。)

手のが出てきますね。いいですねー。

  1. ダッシュボードからbucketを作る。 まあ任意の名前でbucketを作ってください。
MinIO uses buckets to organize objects. A bucket is similar to a folder or directory in a filesystem, where each bucket can hold an arbitrary number of objects.

今回は、tiledbってなまえで作りました。

config[“vfs.s3.aws_access_key_id”] = “16LhDAkDBaILJPXiqEJL” config[“vfs.s3.aws_secret_access_key”] = “mbOwcKU2foJMnwXEOs0yLYYKKKOCTMhN4pcwlu5p”

tiledbでminioを使う設定をする

import tiledb
import numpy as np

# Create a TileDB config
config = tiledb.Config()

# Set Minio-specific configuration options
 

config["vfs.s3.scheme"] = "http"
config["vfs.s3.region"] = ""
config["vfs.s3.endpoint_override"] = "172.20.2.253:9000"
config["vfs.s3.use_virtual_addressing"] = "false"
config["vfs.s3.aws_access_key_id"] = "16LhDAkDBaILJPXiqEJL"
config["vfs.s3.aws_secret_access_key"] = "mbOwcKU2foJMnwXEOs0yLYYKKKOCTMhN4pcwlu5p"

# Create contex
ctx = tiledb.Ctx(config)

array_name = "s3://tiledb/test2"
timestep=256
x=1024
y=1024
z=1024
tiles = timestep*x*y*z

dom = tiledb.Domain(tiledb.Dim(name="dim1", domain=(timestep,x,y,z), tile=tiles, dtype="int32"))
attr = tiledb.Attr(name="data", dtype="float32")
schema = tiledb.ArraySchema(domain=dom, attrs=(attr,))

# Create the TileDB array
tiledb.Array.create(array_name, schema,ctx=ctx)

# Write data to the array
with tiledb.open(array_name, "w",ctx=ctx) as array:
    data = {
        "dim1": [1, 2, 3],
        "data": [1.1, 2.2, 3.3],
    }
    array[1:4] = data

ちゅうことで、実験するための準備をする

## step1 : サーバ上でtiledbをpythonのプロセスを通して動かして、データを全部読み込ませる。
この時に、lz4とか、その他の圧縮方式を使って保存するのもいいかもしれないね。てかそうしてください。

## step2 : tiledbのスライスのインターフェースを確認してください。で、実際に1回くらいスライスしてみてください。

## step3 : 上で説明した方法でminioをバックエンドに、tiledbを動かしてください。

## step4 : 25%刻みでランダムなリクエストシーケンスを作れるようにしてください。

## step5 : 上のインターフェースに合わせて、リクエストシーケンスを作ってください。で、メイクスパンを測定してください。よろしくお願いします。

## step6 :  俺の提案手法とたたかわせてください!!よろしくお願いします。

step1 .npyファイルを読み込んで、tiledbに書き込む

# スキームの定義
ctx = tiledb.Ctx()
array_name = f"array_{num_time_steps}"
array_uri = f"/home2/naoyami/tiledb_data/{array_name}"
array_schema = tiledb.ArraySchema(
    domain=tiledb.Domain(
        tiledb.Dim(name="timestep", domain=(0, num_time_steps - 1), tile=1, dtype=np.uint64),
        tiledb.Dim(name="x", domain=(0, 1023), tile=256, dtype=np.uint64),
        tiledb.Dim(name="y", domain=(0, 1023), tile=256, dtype=np.uint64),
        tiledb.Dim(name="z", domain=(0, 1023), tile=256, dtype=np.uint64),
    ),
    attrs=[tiledb.Attr(name="data", dtype=np.float32)],
    # filters=tiledb.FilterList([tiledb.LZ4Filter()]),  # Enable LZ4 compression
    # filters=tiledb.FilterList([gzip_filter])
    # filters=tiledb.FilterList([zstd_filter])
    # filters=tiledb.FilterList([blosc_filter])
    # 圧縮をしたいときはうえのライブラリを使ってみてください。自動で圧縮と解凍をやってくれるみたいですよ。
)

if not tiledb.object_type(array_uri, ctx=ctx):
    tiledb.Array.create(array_uri, array_schema)

# .npyから読み出し、tiledbに書き込む
for timestep in range(1, num_time_steps):
    file_path = f'/home2/aoyagir/isotropic1024coarse/pressure2_time_steps/t_{timestep:04}.npy'
    if os.path.exists(file_path):
        # Load the .npy file
        data_3d = np.load(file_path).astype(np.float32)

        # Open the TileDB array for writing
        with tiledb.DenseArray(array_uri, mode="w", ctx=ctx) as array:
            # Define the coordinates for this timestep
            coords = (timestep-1, slice(0, 1024), slice(0, 1024), slice(0, 1024))
            # Write the 3D data to the TileDB array
            array[coords] = data_3d
        print(f"timestep{timestep} is done")
    else:
        print(f"File doesn't exist for timestep {timestep}")

説明

tiledb.Dim: Each tiledb.Dim represents a dimension in the array. In this case, you have four dimensions: dim0, dim1, dim2, and dim3.

name: The name parameter specifies the name of the dimension.

domain: The domain parameter specifies the minimum and maximum values that a dimension can take. For example, domain=(0, 1023) means that each of the first three dimensions (dim0, dim1, dim2) can have values between 0 and 1023.

tile: The tile parameter specifies the tile size for each dimension. Tiles are used to divide the domain into smaller chunks for efficient storage and retrieval. For example, tile=256 means that each dimension will be divided into tiles of size 256.

dtype: The dtype parameter specifies the data type for the dimension values. In this case, dtype=np.uint64 indicates that the dimensions will store 64-bit unsigned integers.

step2 : tiledbのスライスのインターフェースを確認してください。で、実際に1回くらいスライスしてみてください。

# read the file
with tiledb.DenseArray(array_uri, mode="r", ctx=ctx) as array:
    # Read data for a specific timestep, x, y, z
    timestep = 1
    x = 1000
    y = 1000
    z = 1000
    data = array[timestep, x, y, z]
    print(data)

# slice the array
with tiledb.DenseArray(array_uri, mode="r", ctx=ctx) as array:
    # Read the sliced data from the TileDB array using 'from' and 'to' expressions
    data = array[1, 0:256, 0:256, 0:256]
    print(data)

普通にいけそうだね。array_uriとctxをしてすれば、いけるね。

step3 : 今作ったデータにminioをバックエンドにしてアクセスする。