はじめに
Cloud上で非常に安価で大量のデータを格納できるストレージとしてICOSがよく利用されます。ICOSの課金の仕組みは2つの要素で決まります。
1つ目は月次保管データ・ボリュームの平均、2つ目はシステムによって処理される操作要求の総数です。
今回は2つ目の操作要求を対象として、ICOSのデータのアップロード、ダウンロード、リストなどを実行する際に発生するAPI Callがどのようにカウントされるのか確認することを目標に検証を行いました。
検証結果として APIコマンド1回に対して、class Aもしくはclass Bのカウント1回。API 1回で複合的にclass A, class Bがカウントされることはありませんでした。 詳細な検証結果は本記事の後半で記載してあります。
API Callの課金について
API Callは要求内容によってClass AとClass Bの2種類が存在します。
Class Aの要求には、変更またはリスト作成が関係します。
Class Aの要求に該当する例としてはバケットの作成、オブジェクトのアップロードまたはコピー、バケットのリスト、バケットの内容のリスト、ACLの設定、およびCORS 構成の設定などが挙げられます。
Class Bの要求は、システムからのオブジェクトなどの取得に関連する要求です。
Class Bの要求に該当する例としてはオブジェクトおよびメタデータの取得が挙げられます。
また、バケットまたはオブジェクトをシステムから削除する場合はClass A・Bどちらにも該当せず、料金は発生しません。
クラス要求の金額はストレージクラスによって異なりますが、Smart Tierの場合はClass Aは1000回あたり¥0.774、Class Bは10,000回当たり¥0.774となっています。
また、Class AとClass Bの量に応じてSmart TierのデータプランがHot・Cool・Coldの3段階に分かれます。storage
(具体的には保管されたデータの合計量(GB))とretrievals
(取得されたデータの合計ボリューム(GB))、requests
(クラス A (書き込み) 要求の数に、クラス B (読み取り) 要求の数の 1/10 を加算した合計)の関係値によって以下の通りに分類されます。
Hot : requests > 1000 x (storage - retrievals)
Cold : requests < (storage - retrievals)
Cool : その他
より詳細な料金はポータルの製品情報からご確認ください。
https://cloud.ibm.com/objectstorage/create#pricing
手順
本記事で実施した検証内容は以下の通りです。
- curlを使用した際のAPI Callの確認
- Pythonを使用した際のAPI Callの確認
- バケット内に大量のファイルが存在する場合のリスト取得で発生するAPI Callの確認
また、本記事の構成図は以下のようになっています。
使用する環境
本記事で使用する環境は以下のとおりです
-
IBM Cloud Object Storage(ICOS)の東京リージョンのBucket
-
東京リージョンのIBM Cloud Activity Tracker
また、pythonの環境としてGoogleのcolaboratoryを利用しています。
1. curlを使用した際のAPI Callの確認
まずはじめにcurlを使用してICOSの操作を実施し、API Callの発生を確認します。
作業内容はこちらのdocsを参考に進めています。
また、外部からICOSへのアクセスのためのトークン取得はこちらのQiita記事を参考にしています。
手順は以下の通りです。
- ICOSアクセスのためのtokenの取得
- curlを使用したICOSのバケットへファイルのアップロード・リスト・ダウンロード
- Billing APIからAPI Callの確認
1-1. ICOSアクセスのためのtokenの取得
まずはじめにICOSへアクセスするためのbearer tokenを取得します。tokenの取得コマンドは以下の通りです。[apikey]
には事前に取得したapikeyを代入します。apikeyの取得方法についてはこちらの記事を参考にしてください。
$ curl -k -X POST --header "Content-Type: application/x-www-form-urlencoded" --header "Accept: application/json" --data-urlencode "grant_type=urn:ibm:params:oauth:grant-type:apikey" --data-urlencode "apikey=[apikey]" "https://iam.cloud.ibm.com/identity/token"
{"access_token":"bearertoken","refresh_token":"not_supported","ims_user_id":9985776,"token_type":"Bearer","expires_in":3600,"expiration":1709474315,"scope":"ibm openid"}%
コマンドを打つと、access_tokenの後ろにbearer tokenが出力されます(上の"bearetoken"
に当たる部分)。
注意点として生成したtokenは有効期限が1時間となっているため、期限切れの場合再び作成し直す必要があります。
1-2. curlを使用したICOSのバケットへファイルのアップロード・リスト・ダウンロード
次に先ほど取得したbearer tokenを使用してcurlからICOSを操作を実施します。
以下、バケットの操作コマンドとなります。
$ curl -X PUT “https://s3.jp-tok.cloud-object-storage.appdomain.cloud/[バケット名]/[登録ファイル名]” -H “Authorization: bearer [bearer token]” -T “[送付したいファイル]”
$ curl "https://s3.jp-tok.cloud-object-storage.appdomain.cloud/[バケット名]/[ダウンロードファイル]" -H "Authorization: bearer [bearer token]" --output [ダウンロードファイル保存名]
curl "https://s3.jp-tok.cloud-object-storage.appdomain.cloud/[バケット名]" -H "Authorization: bearer [bearer token]"
今回は東京リージョンのバケットのためエンドポイントがs3.jp-tok.cloud-object-storage.appdomain.cloud
となっており、別リージョンの場合は対応したエンドポイントに変更してください。また、[bearer token]・[バケット名]などの中身は対応したものを代入してください。
1-3. Activity Tracker(or API Billing)からAPI Callの確認
ICOSの操作後にAPI Callがどのくらい発生しているか2通りの手段で確認します。
1-3-1. Activity Trackerを使用した確認方法
Activity Trackerに流れるログを確認することでAPI Callがどれくらい発生しているか確認することができます。
今回は以下の操作を実施してログを確認します。
- sample1.txtファイルをICOSのバケット上にアップロード
- sample1.txtファイルをICOSのバケットからダウンロード
- ICOSのバケット内のファイルのリストアップ
これらの操作を先ほど記載したcurlを利用して実施した後、Activity Trackerで確認したものが以下の画像となります。
それぞれ詳細を確認すると以下の様になっています。
これらを確認するとファイルのアップロードではputコマンド(Class A)、ファイルのダウンロードではgetコマンド(Class B)、バケット内ファイルのリストではバケットリストのためのgetコマンド(Class B)が呼び出されていることが確認できます。
1-3-2. Billing APIからの確認方法
Billing APIを見ることでAPI Callがどのくらい発生したのかを確認できます。API Billingを入手するためにはresouce_incetance_id
、account_id
が必要なのでこれらを確認します。
resouce_incetance_idの確認
ポータルのICOS画面からサービス資格情報→新規資格情報を選択します。
任意の名前をつけ、ロールを管理者、HMAC資格情報を含めるをオンにして作成します。
作成後、サービス資格情報の画面から先ほど作成した資格情報が確認できるのでその中のresource_instance_idをコピーしておきます。
account_idの確認
次にaccount_id
を確認します。
ポータルの右上にある管理→アカウントを選択します。
続いて左側のメニューからアカウント設定を選択するとアカウントIDが表示されるのでコピーしておきます。
billing APIの取得
取得した情報をもとにbilling APIを入手します。
curl -X "GET" "https://billing.cloud.ibm.com/v4/accounts/[ACCOUNT_ID]/resource_instances//usage/[BILLING_MONTH]?resource_instance_id=[resource_instance_id]®ion=[region]" \
-H "Authorization: Bearer [bearer token]" --output billingbefore_2402.json
[]で括られてるものは入手した情報を代入します。[region]は対象となるリージョン(今回ならjp-tok)、[BILLING_MONTH]は取得したいbilling APIの月(2024年2月なら2024-02)を指定します。
コマンド実行後、billing APIがjsonファイルとして出力されます。
2. pythonを使用した際のAPI Callの確認
続いてpythonを使用した際にAPI Callの量が変化するのかを確認します。
手順は以下の通りです。
- ICOSのバケットへファイルのアップロード・リスト・ダウンロード
- Activity Tracker(or API Billing)からAPI Callの確認
2-1. ICOSのバケットへファイルのアップロード・リスト・ダウンロード
pythonを使用してICOSバケットの操作を実施します。
まず、pythonで使用するライブラリーをインポートします。
import ibm_boto3
from ibm_botocore.client import Config, ClientError
次にpythonからICOSへアクセスするためにはICOS資格情報が必要なので、curlからアクセスする際に作成したICOS資格情報をコピーします。
credencials = {
#資格情報を貼り付ける
}
続いて入手した資格情報をもとに接続を作成します。Endpointは今回東京リージョンのICOSのため、東京リージョンのパブリックエンドポイントを使用しています。他のリージョンを使用する際はポータルのICOSのページ左側のエンドポイントから使用するリージョンのエンドポイントを確認してください。
COS_ENDPOINT = "https://s3.jp-tok.cloud-object-storage.appdomain.cloud"
COS_API_KEY_ID = credencials["apikey"]
COS_INSTANCE_CRN = credencials["resource_instance_id"]
# Create resource
cos = ibm_boto3.resource("s3",
ibm_api_key_id=COS_API_KEY_ID,
ibm_service_instance_id=COS_INSTANCE_CRN,
config=Config(signature_version="oauth"),
endpoint_url=COS_ENDPOINT
)
ICOSのバケットを操作する関数を作成する
ICOSとの接続が可能になったのでICOSのバケットを操作する関数を作成します。基本的なものに関してはICOSのdocs : pythonの使用を参考に作成しています。
def create_text_file(bucket_name, item_name, file_text):
print("Creating new item: {0}".format(item_name))
try:
cos.Object(bucket_name, item_name).put(
Body=file_text
)
print("Item: {0} created!".format(item_name))
except ClientError as be:
print("CLIENT ERROR: {0}\n".format(be))
except Exception as e:
print("Unable to create text file: {0}".format(e))
def get_item(bucket_name, item_name):
print("Retrieving item from bucket: {0}, key: {1}".format(bucket_name, item_name))
try:
file = cos.Object(bucket_name, item_name).get()
print("File Contents: {0}".format(file["Body"].read()))
except ClientError as be:
print("CLIENT ERROR: {0}\n".format(be))
except Exception as e:
print("Unable to retrieve file contents: {0}".format(e))
def get_bucket_contents(bucket_name):
print("Retrieving bucket contents from: {0}".format(bucket_name))
try:
files = cos.Bucket(bucket_name).objects.all()
for file in files:
print("Item: {0} ({1} bytes).".format(file.key, file.size))
except ClientError as be:
print("CLIENT ERROR: {0}\n".format(be))
except Exception as e:
print("Unable to retrieve bucket contents: {0}".format(e))
def get_bucket_contents_prefix(bucket_name, search_prefix):
print("Retrieving bucket contents from: {0}".format(bucket_name))
try:
files = cos.Bucket(bucket_name).objects.filter(Prefix=search_prefix)
for file in files:
print("Item: {0} ({1} bytes).".format(file.key, file.size))
except ClientError as be:
print("CLIENT ERROR: {0}\n".format(be))
except Exception as e:
print("Unable to retrieve bucket contents: {0}".format(e))
それぞれの関数を実行するとICOSの操作が可能です。
2-2. Activity TrackerからAPI Callの確認
先ほど作成した関数を使用してICOSを操作し、Activity TrackerからでAPI Callが送られているかを確認します。
まずはcreate_text_file
関数を使用してファイルのアップロードをおこないます。
create_text_file("test-request","test.txt", "hoge")
ポータルで確認すると先ほど作成したファイルが追加されています。
また、Activity Trackerで確認するとbucket.get
のAPIが呼び出されています。
同様にリストとファイル取得も試してみます。
リスト取得
get_bucket_contents("test-request")
出力:
Retrieving bucket contents from: test-request
Item: test.txt (4 bytes).
ファイル取得
get_item("test-request", "test.txt")
出力:
Retrieving item from bucket: test-request, key: test.txt
File Contents: b'hoge'
3. バケット内に大量のファイルが存在する場合のリスト取得で発生するAPI Callの確認
基本的にバケットからファイルのリストを取得する際に発生するクラス要求はClass AのGet要求1回ですが、docsによるとバケット内に1000以上のファイルが存在する場合は1000ファイル毎に要求が発生すると記載がありましたので、検証してみます。
まずはバケット内に大量のファイルをアップロードします。
def mult_object_upload(bucket_name, num, prefix):
for i in range(num):
item_name = "{0}/testfile{1}".format(prefix, i)
file_text = "{0}/testfile{1}".format(prefix, i)
print("Creating new item: {0}".format(item_name))
try:
cos.Object(bucket_name, item_name).put(
Body=file_text
)
print("Item: {0} created!".format(item_name))
except ClientError as be:
print("CLIENT ERROR: {0}\n".format(be))
except Exception as e:
print("Unable to create text file: {0}".format(e))
試しにprefixを変更したファイルを1000個ずつ合計4000個アップロードします。
mult_object_upload("test-request", 1000, "test-1")
mult_object_upload("test-request", 1000, "test-2")
mult_object_upload("test-request", 1000, "test-3")
上記コマンド実施後、バケット内にはtest-1/testfilexxx・test-2/testfilexxx・test-3/testfilexxxがそれぞれ1000ファイルの3000ファイル+元々バケットにあったファイル3個の合計3003ファイルが存在しています。
3-1. pythonでlist取得する場合
get_bucket_contents("test-request")
Activity Trackerを見ると、1回のリスト取得で4回分のクラス要求が発生していることが確認できます。
今度はprefixを指定してバケット内の1000個だけをリスト化してみます。
以前作成した関数を使用してファイル名の頭が"test-1"(test-1/testfile0~test1/testfile999までの1000ファイル)のみを指定してリストを取得します。
get_bucket_contents_prefix("test-request", "test-1")
今回は1000個だけをリスト化しているのでActivity Trackerを見ると、1回のリスト取得で1回だけクラス要求が発生していることが確認できます。
3-2. curlでlist取得する場合
curlでも同様にlist取得してみるとActivity Trackerでは1行分のログしか追加されません。
そこでlistをtextファイルとして出力して確認してみます。
curl "https://s3.jp-tok.cloud-object-storage.appdomain.cloud/test-request" -H "Authorization: bearer [bearer token]" --output list.txt
出力したtextファイルを確認してみると1000ファイルのみしか出力されていませんでした。
このことから、curlでは1000ファイルを超えたリスト要求があった場合1000ファイルまでしか出力されないことがわかります。
本記事の検証内容は以上となります。
結論
本記事で検証した結果は以下の通りとなりました。
- curlからICOSを操作した場合、ダウンロードではClass Bが、アップロード・リスト取得(ファイル1000以下)ではClass Aがそれぞれ1回の操作に対して1回発生した
- pythonからICOSを操作した場合、ダウンロードではClass BのAPI Call、アップロード・リスト取得(ファイル1000以下)ではClass AのAPI Callがそれぞれ1回の操作に対して1回発生した
- 1000を超えるファイルのリストを実行した場合、pythonは分割されて複数回のAPI Callが発生したのに対し、curlでは1000個のファイルのみリストされたため、1回だけAPI Callが発生した
以上の結果から基本的にはdocsに記載があった通りにICOS操作に対して対応したClass AもしくはClass BのAPI Callが発生していることが確認できました。
ちなみにポータルで操作すると、ポータル上でバケットやファイルを確認するだけでAPI Callが発生します。
また、ポータルやバックアップソフトなどAPI Callが隠蔽されているアプリケーションやソフトウェアなどを利用する場合はICOS操作で想定される以上のAPI Callが発生する可能性があるのでご注意ください。
例として、下の記事ではs3cmdを利用していますが、大容量のファイルを転送する際にファイルが分割されるため、一回のアップロードに複数回のAPI Callが発生しています。