🔖

Momento Storage (Private Alpha)

2024/07/27に公開

https://jp.gomomento.com/blog/no-more-tradeoff-with-momento-storage/
Momento Storage は Momento Cache に加えてデータの耐久性、永続性を備えたデータストアです。Storageと言っても、CIFSやNASなどのようにマウントして利用する物ではなくMomento Cache と同様にAPI経由で操作を行うことになります。

例えばAmazon DynamoDBやAmazon S3はデータ永続性を持つキーバリュー型ストアですが、当然レイテンシ、スループットはキャッシュほどの高速性を実現できません。Momento Storageを用いることでCacheの高速性にデータ永続性を持たせることが可能となります。

こちらからプライベートアクセスに申し込むことが出来ます。また8月1日に開催が予定されているもめんと会でも、デモだけではなく特別にアーリーアクセスが可能となるようです。
https://momentocommunity.connpass.com/event/321676/
現在Private Alphaであり、まだまだ進化中ですしアクセスも限定されていますので、是非もめんと会に参加してみてください。

現在StorageはCacheがサポートしている4つのデータ型Disctionary,List,Sets,Sorted Setsには対応しておらず単純Key-Value型をサポートしています。

さっそくやってみる

まずは以下のハンズオンを完了させMomento へのアクセスができる環境を作成します。
https://zenn.dev/momentobigfun/articles/aa24ff7817e06c
過去にMomento環境を構築した方はこのステップは省略可能ですが以下のコマンドを実行し最新版のライブラリをインストールしておきます。

npm install momnento
npm install @gomomento/sdk

次に以下のスクリプトをnode test.jsと入力して実行します。

test.js
// Declare the Momento SDK library
const {
    PreviewStorageClient, StorageConfigurations, CredentialProvider, CreateStoreResponse,
    DeleteStoreResponse, ListStoresResponse, StoragePutResponse
} = require('@gomomento/sdk');

// Declate the dotenv library
const dotenv = require('dotenv');

// Run the config function to bring in the .env file
dotenv.config();

// A simple function that calls all functions in order. You probably want more error handling.
async function run() {
    const storeName = 'test';

    const storageClient = new PreviewStorageClient({
        configuration: StorageConfigurations.Laptop.latest(),
        credentialProvider: CredentialProvider.fromString({
            apiKey: "xxxxxxx"
        }),
    });


    const result = await storageClient.createStore(storeName);
    switch (result.type) {
        case CreateStoreResponse.AlreadyExists:
            console.log(`Store '${storeName}' already exists`);
            break;
        case CreateStoreResponse.Success:
            console.log(`Store '${storeName}' created`);
            break;
        case CreateStoreResponse.Error:
            throw new Error(
                `An error occurred while attempting to create store '${storeName}': ${result.errorCode()}: ${result.toString()}`
            );
    }

    const resultallstore = await storageClient.listStores();
    switch (resultallstore.type) {
        case ListStoresResponse.Success:
            console.log(
                `Stores:\n${resultallstore
                    .stores()
                    .map(c => c.getName())
                    .join('\n')}\n\n`
            );
            break;
        case ListStoresResponse.Error:
            throw new Error(`An error occurred while attempting to list stores: ${result.errorCode()}: ${result.toString()}`);
    }
    const resultdelete = await storageClient.deleteStore(storeName);
    switch (resultdelete.type) {
        case DeleteStoreResponse.Success:
            console.log(`Store '${storeName}' deleted`);
            break;
        case DeleteStoreResponse.Error:
            throw new Error(
                `An error occurred while attempting to delete store '${storeName}': ${result.errorCode()}: ${result.toString()}`
            );
    }
}

run();

apiKeyの部分は皆さんの値に置き換えておいてください。

Store 'test' created
Stores:
test


Store 'test' deleted

と表示されれば、
1. ストレージの作成
2. ストレージのリスト
3. ストレージの削除
が完了です。
API Referenceはこちらです。
https://docs.momentohq.com/storage/develop/api-reference
ただこちらのAPI ReferenceはTypeScriptを用いている部分が一部あるため、JavaScriptにダウングレードして作業を進めています。

次にデータの書き込み、読み込み部分を加えます。

test.js
// Declare the Momento SDK library
const {
    PreviewStorageClient, StorageConfigurations, CredentialProvider, CreateStoreResponse,
    DeleteStoreResponse, ListStoresResponse, StoragePutResponse
} = require('@gomomento/sdk');

// Declate the dotenv library
const dotenv = require('dotenv');

// Run the config function to bring in the .env file
dotenv.config();

// A simple function that calls all functions in order. You probably want more error handling.
async function run() {
    const storeName = 'test';

    const storageClient = new PreviewStorageClient({
        configuration: StorageConfigurations.Laptop.latest(),
        credentialProvider: CredentialProvider.fromString({
            apiKey: "xxxxx"
        }),
    });


    const result = await storageClient.createStore(storeName);
    switch (result.type) {
        case CreateStoreResponse.AlreadyExists:
            console.log(`Store '${storeName}' already exists`);
            break;
        case CreateStoreResponse.Success:
            console.log(`Store '${storeName}' created`);
            break;
        case CreateStoreResponse.Error:
            throw new Error(
                `An error occurred while attempting to create store '${storeName}': ${result.errorCode()}: ${result.toString()}`
            );
    }

    const resultallstore = await storageClient.listStores();
    switch (resultallstore.type) {
        case ListStoresResponse.Success:
            console.log(
                `Stores:\n${resultallstore
                    .stores()
                    .map(c => c.getName())
                    .join('\n')}\n\n`
            );
            break;
        case ListStoresResponse.Error:
            throw new Error(`An error occurred while attempting to list stores: ${result.errorCode()}: ${result.toString()}`);
    }

    // to store a string value:
    const resultput = await storageClient.putString(storeName, 'test-key', 'test-value');
    switch (resultput.type) {
        case StoragePutResponse.Success:
            console.log("Key 'test-key' stored successfully");
            break;
        case StoragePutResponse.Error:
            throw new Error(
                `An error occurred while attempting to store key 'test-key' in store '${storeName}': ${result.errorCode()}: ${result.toString()}`
            );
    }

    // Momento storage also supports these other data types:
    await storageClient.putInt(storeName, 'test-keyint', 42);
    await storageClient.putDouble(storeName, 'test-keydouble', 3.14);
    await storageClient.putBytes(storeName, 'test-keybytes', Buffer.from('test-value'));

    const getResponse = await storageClient.get(storeName, 'test-key');
    // simplified style; assume the value was found, and that it was a string
    console.log(`string hit: ${getResponse.value().string()}`)

    // if the value was an integer:
    const integerGetResponse = await storageClient.get(storeName, 'test-keyint');
    console.log(`integer hit: ${integerGetResponse.value().int()}`);

    const resultdelete = await storageClient.deleteStore(storeName);
    switch (resultdelete.type) {
        case DeleteStoreResponse.Success:
            console.log(`Store '${storeName}' deleted`);
            break;
        case DeleteStoreResponse.Error:
            throw new Error(
                `An error occurred while attempting to delete store '${storeName}': ${result.errorCode()}: ${result.toString()}`
            );
    }
}

run();

node test.jsで実行すると以下が表示されます。

Store 'test' created
Stores:
test


Key 'test-key' stored successfully
string hit: test-value
integer hit: 42
Store 'test' deleted

現時点ではまだマネージメントコンソールにStorageの機能は存在せずAPIのみで操作可能なようです。

簡単な解説

    const storeName = 'test';

    const storageClient = new PreviewStorageClient({
        configuration: StorageConfigurations.Laptop.latest(),
        credentialProvider: CredentialProvider.fromString({
            apiKey: "xxxxx"
        }),
    });

このパートでtestというストレージのクライアントを作成しています。PreviewStorageClientを用いていますが将来的に名前は変るはずです。
その後

const result = await storageClient.createStore(storeName);

でStorageを作成します。StorageではなくStoreとAPIでは定義されていますので少し混乱するかもしれませんが慣れれば大丈夫です!

 const resultput = await storageClient.putString(storeName, 'test-key', 'test-value');

値を書き込む部分です。この辺りはほぼCacheと一緒ですね。Momentoに慣れていれば使いやすいと思います。

   await storageClient.putInt(storeName, 'test-keyint', 42);
   await storageClient.putDouble(storeName, 'test-keydouble', 3.14);
   await storageClient.putBytes(storeName, 'test-keybytes', Buffer.from('test-value'));

Int,Double,Bytes専用のPutAPIが定義されています。現時点でサポートされているAPIコマンドはまだ限定されており(Private Previewですしね!)使い分けの記載がありませんでしたが、パフォーマンスなどが変わるのかもしれません。これは今後Publicになった時点で検証していきたいと思います。

const getResponse = await storageClient.get(storeName, 'test-key');

この箇所で値を取り出すことが出来ます。Storageは結果整合性で動作しますので、注意が必要です。
最後に作成されたStoreの削除が以下です。

const resultdelete = await storageClient.deleteStore(storeName);

いかがでしたでしょうか。簡単ですね。早くオープンに使えるようになってほしいですね。

Discussion