【IIJ GIOの裏側を語る#7】オブジェクトストレージ設計上のポイント

カテゴリー: ストレージ, 技術情報, 裏側を語る   パーマリンク
このエントリーをはてなブックマークに追加

『IIJ GIOの裏側を語る』連載企画の第7回です。

今回は、IIJクラウド本部の飯田が「オブジェクトストレージ設計上のポイント」をテーマに解説します。

執筆者の紹介

株式会社インターネットイニシアティブ
クラウド本部 クラウドサービス2部
飯田 拓哉

「第7回:オブジェクトストレージ設計上のポイント」

はじめに

近年SDS(Software Defined Storage)という言葉が注目されています。SDSと呼ばれる製品/サービスには様々な種類のものがありますが、弊社でも「ストレージ&アナリシスサービス」(以下、本サービスとします)という名称でオブジェクトストレージサービスを提供しています。本稿では本サービスの設計やアーキテクチャについて紹介します。

自社での設計/実装

本サービスのシステムは、多くの構成要素が自社内で設計/実装されています。具体的には、サービスとして公開しているAPIや内部のメタデータ管理機能などについて、弊社のエンジニアがスクラッチから設計/実装を行っています。これは、サービス仕様と実装に対して自社でのコントロールを手放さないことで、万一の問題発生時や将来的な機能拡張などに際して対応手段の選択肢を増やすことを狙ったもので、これまでのところ期待通りの運用となっています。

設計コンセプト

システムの形容として「スケーラブルで柔軟な」という表現を見掛けますが、本サービスシステムでも同様の課題について幾つかの角度から検討を行いました。ここでは、スケーラビリティについて一点、柔軟性について一点、どのようにアプローチしたのかという点について紹介します。

スケーラビリティ:「数」への対処

大規模ストレージの現実的なデータ利用場面を考えると、単体で数TBを超えるような巨大なデータが大量に発生するケースは多くはありません。つまり、大規模ストレージを設計/実装する上でスケーラビリティを考慮する際には、いかに巨大な「数」(「容量」ではなく)を捌くか?という課題について検討することになります。たとえば普通のファイルシステムであれば、数十万件から数百万件程度のファイル数でもlsコマンドの結果取得に長時間掛かるなど、事実上の使用不能状態に陥る場合がありますが、弊社のオブジェクトストレージが想定したスケールは数百TBから数PB規模であり、件数ベースでは数億から数十億件となります。

そこで本サービスの設計では、物理データのファイル名など各種情報を高速なNoSQL系のDBへ格納して別管理とし、ストレージシステムには単純に「データを保存する」機能のみを担当させることで、stat系の操作による負荷を可能な限りストレージシステムからオフロードしました。

上記内容について、実際に本サービスで格納されているデータの1億件程度のサンプリングを行った結果としても99パーセンタイルが10MB辺り(最大値は数TB程度)になっており、前提となる想定(小さなデータが大量)は間違っていなかったと思います。なお、ここで述べた考え方を前提とした場合に、仮に「大きなストレージを少数用意」してしまうと結局個々のストレージが数をさばき切れなくなり、結果的に「性質の異なる『数の問題』を複数同時に抱える」ことになります。反対に「小規模なストレージを沢山用意」すると性能的には有利になりますが、設備規模に比例するコストが上昇するため提供価格の上昇を招きます。

以上のことから、実際のサイジングや設備設計においてはコストを勘案しながら「落とし所を探る」作業がもう一つのポイントとなりました。

柔軟性:抽象化層による機能の分離

元々オブジェクトストレージは一般的なファイルシステムと異なる概念で構成されているため、何らかのマッピング機構を用意することが適切と思われました。また、このシステムはサービス提供を目的としたシステムで、市場ニーズやテクノロジーの変化などに応じて機能や規模を変化させられる必要がありました。

そこで、NoSQLに格納したメタ情報とその管理系コンポーネントを抽象化層とし、物理的なストレージ上にあるデータの状態と外部から論理的に参照されるオブジェクトの状態が、メタ情報管理系を介してマッピングされる構造としました。この構造により、データストアは外部に公開するAPI仕様から分離して可換性を持ち、同時にフロントAPIではデータストアの機能や制限に影響されることの無い設計自由度を確保しました。

比較的良く見掛ける「抽象化層を挟むことで疎結合な系を実現しようとするアプローチ」で、それをコンポーネント単位のレベルで適用しています。当初の意図は基本的に実現できていますが、公開APIの機能が「データのIO」でありストレージへの直接アクセスが論理的に不可避であるため、この点について対策が必要でした。性能維持や信頼性など他の要件とのトレードオフを検討した上で、最終的に公開APIの中に抽象化層を設けることで回避することになりました。

具体的には公開APIのロジックが操作するデータ入出力部分を抽象化層とし、ロジックから分離したIOの実装系にストレージへの依存性を封入しました。これはこれで上手く機能し、抽象化層を挟み込んだことでフィルタ系の機能拡張等も可能になるなど副次的な効果も得られました。

システムアーキテクチャ

上で述べたような考え方は分散システムとしての構成を暗黙的に示唆しており、実際本システムは分散システムとして設計されました。全体としては垂直分散型のシステムで各コンポーネントは原則的にREST APIで連携するものとしました。分散システムの設計では一貫性維持や可用性確保など、いわゆるCAP定理としてまとめられるような課題から、ロック問題のような比較的実装に近いレベルの課題まで、様々な課題について検討することになります。本項では、それらの検討内容から二つの要素について紹介します。

コンポーネント/API粒度

分散システムで各コンポーネントやコンポーネントが提供するAPIの粒度の設計を誤ると、一貫性の維持が極端に複雑になったり、予見し難い設計レベルでの不具合を作り込んだりするリスクがあります。前述の通りコンポーネント間はREST APIで連携する想定としたため、システム全体を従来型の(RDBMSが実装しているような)同期的なトランザクションで実装することはできませんでした。

そこで一貫性については結果整合性を前提とし、大きなトランザクション単位の検討からスタートし、非同期的なロールバック処理や排他制御などが簡便に実現可能な箇所でトランザクションを分割した上で、分割後の各単位は従来型の同期的なトランザクションで扱うこととしました。つまり、同期的なトランザクションを非同期的な結果整合性維持の仕組みで結合する戦略です。

これにより、同期的且つシンプルな実装と局所化された(分割箇所に集中させた)結果整合性ロジックから成る「系全体としての結果整合性」を実現しました。

コンポーネント/APIの粒度設計の考え方を端的に言うと「結果整合性の考え方で行くけど、野放図にやると破綻するから局所化した」ということになります。この件に関しては、前提として「結果整合性の考え方を導入することで実現される柔軟性はシステム全体として実現されるべきものであって、必ずしも構成要素の何もかもが非同期化/疎結合化されている必要は無い」という考え方がありました。

結局「何のために、どこを柔軟にしたいのか?」という問に答えながら、堅くする部分と柔らかくする部分を決めて行くことが設計作業の重要なポイントの一つ、ということかと思います。

追記型データ操作

そもそもの考え方として、同期的なロック操作自体を極力減らそう(できればゼロに)という考え方から、システムで扱うデータ全般について原則的に追記型の操作のみを行うものとしました。つまり、論理的に同じデータの更新が生じた際には、更新後データを追加して更新前データを無効化することで論理的な更新とする考え方です。正データの判定はタイムスタンプで行い、常に最新のものを正と判断します。主だった入出力系には可能な限り(処理が複雑化し過ぎない限り)適用していますが、全ての操作に100%適用できた訳では無く、単純な形での追記型操作が適用できなかった処理については非同期化で回避しました。

具体的には、操作自体を従来型の同期的な上書き更新操作とした上で、処理自体を非同期バッチで実行するなどの対応であり、無効となった過去データの永続的な削除処理などがこれに該当しました。

場合によりロック操作を伴うトランザクション管理は必要なものですが、大規模にスケールさせる必要があるシステムでは遅効性の劇薬になり得ます。ロックにまつわる問題が厄介な理由の一つは「修正が困難なタイミングで初めて顕在化する傾向がある」ことです。それらの問題は、規模が大きくなったり利用が増加したりしたタイミングで競合待ちの遅延やデッドロックなどの形で表出し、気付いた時には抜本的な対策を行い難いという事態になりがちです。そこで「対処が困難なら無くしてしまえ!」と取り組んだのが追記型の考え方でした。

今回のの設計では結果的に完全撲滅には至りませんでしたが、少なくとも問題を局所化し非常に限定的なものへ追い込むことができたと思います。

終わりに

今回はサービスシステム設計の比較的初期段階で行われたコンセプトやアーキテクチャの検討をご紹介しました。本稿で述べたような内容は抽象的で、実装上の細かなテクニックなどに比べると意義が判り難い面があるかも知れませんが、或る程度以上の規模のソフトウェアをチームで開発する際には大変重要なものであると考え、今回ご紹介させて頂きました。お読み下さった方の何かのご参考になれば幸いです。

今後の連載予定

コメントは受け付けていません。