TECH PLAY

電通総研

電通総研 の技術ブログ

822

みなさんこんにちは!  電通 総研 金融ソリューション事業部の松崎です。 前回の記事 では、Mesh to Metahumanの元となるメッシュを作成する手順を紹介しました。 この記事は後編になりまして、 前編 で準備したメッシュを用いてMetahumanを作成していく手順を紹介します。 もしまだご覧になっていない方は、是非 前編 からご覧ください! 目次 使用機材紹介 撮影方法 1.頭部メッシュ&テクスチャ作成(フォトグラメトリ) 2.頭部メッシュのリ トポロジー (3Dメッシュ編集) 3.Metahumanの作成と編集(Mesh to Metahuman) 4.Metahumanにフォトグラメトリテクスチャを合成(3D テクスチャマッピング ) 後編では3,4章をご紹介します。 3.Metahumanの作成と編集(Mesh to Metahuman) 2.にて作成したメッシュを用いて、Metahumanの作成を行います。 Metahumanの作成には、UnrealEngine5(以下、UE5)を使用します。 もしまだUE5をインストールしていない場合は、 こちらのサイト の案内に沿ってインストールしましょう。 UE5のインストールが完了しましたら、UE5にMetahuman プラグイン をインストールします。 Epic Games Launcherを開き、マーケットプライスタブで「Metahuman」と検索すると出てきますので、そちらをインストールしましょう。 UE5にて、インストールしたMetahuman プラグイン を有効化します。 UE5を起動し、適当なBlankプロジェクトを作成します。 UE5プロジェクトが開きましたら、「編集 → プラグイン 」で プラグイン ブラウザタブを開きます。 Metahuman プラグイン を選択し、チェックを入れて有効化します。 UEの再起動を求められた場合は、指示通りに再起動しましょう。 続いて、Quixel Bridgeにサインインします。 Quixel Brigeは、作成したMetahumanをUE5へインポートする際に使用するサービスです。また、Metahuman以外でもMegascansのアセット等をインポートする際に用いるサービスです。 「ウィンドウ → Quixel Bridge」からQuixel Brigeを起動します。 サインインが求められますので、UE5にログインしているアカウントでQuixel Brigeにもサインインします。 事前準備が完了しましたので、Metahumanを作成していきます。 コンテンツブラウザの「追加 → 新規フォルダ」を選択し、コンテンツ配下にフォルダを作成します。 作成したフォルダに、2.で出力したメッシュ(OBJ形式)とテクスチャを ドラッグ&ドロップ します。 インポート時の設定にて「Combine Static Meshes」のチェックを外します。 これはメッシュを一塊でインポートする為です。 インポートが完了したら、このメッシュ用のマテリアルを追加します。 コンテンツブラウザの「追加 → マテリアル」から追加します。 追加したマテリアルをダブルクリックして編集画面を開き、テクスチャを ドラッグ&ドロップ します。 テクスチャのRGBノードをマテリアルのベー スカラー に結合し、保存します。 インポートしたメッシュをダブルクリックして編集画面を開き、マテリアルスロットに先ほど追加したマテリアルを設定して保存します。 試しにメッシュをフィールドへ ドラッグ&ドロップ すると、メッシュにテクスチャが貼られていることを確認できます。 メッシュとテクスチャのインポートが完了したので、Metahuman identityでMetahumanを作成します。 「追加 → Metahuman Animator → Metahuman Identity」でMetahuman Identityを追加します。 追加したMetahuman Identityをダブルクリックして編集画面を開き、「Create Components → From Mesh」でインポートしたメッシュを選択します。 コンポーネント (フレーム0)が作成されましたら、ライティングを「ライティングなし」にします。 「Track Markers」を押下すると、選択しているフレームにおける顔の主要部位をト ラッキング してくれます。 無事にト ラッキング されたら、「Metahuman Identityの解決」を押下してMetahumanを作成します。 「B」を押すと作成されたMetahumanを確認できます。 画面左にある「ボディ」から、Metahumanの胴体部分の調整を行うことができます。 必要に応じて、Metahumanの微調整を行っていきます。 再度フレーム0を選択し、画面右上部の「表示(visible)」「使用(used)」を押下して全て有効化します。 目や耳、眉などのト ラッキング 状態を調整します。 各々の輪郭に沿うように、緑色の丸と線を移動させます。 ※修正は、軽い位置移動に留めましょう。線の長さを変えるような大きな修正は控えます。 再度「Metahuman Identityの解決」を押下してMetahumanを作成します。 もう一つMetahumanの調整方法を紹介します。 上記のフレーム0でト ラッキング する際、正面からのト ラッキング になるため耳の形状を正確に捉えることができません。 そこで、耳のト ラッキング 用に別のフレームを追加します。 「フレームのプロモート」を押下し、フレーム1(右耳用)を追加しました。 フレーム1では、右耳だけが使われるように「耳(R)」だけ「使用(used)」チェックを入れます。 フレーム0にて、耳が使われないように「耳(R)」「耳(L)」の「使用(used)」チェックを外します。 フレーム1と同様に、フレーム2(左耳用)を追加します。 「Metahuman Identityの解決」を押下して調整内容をMetahumanに反映します。 「Mesh to Metahuman → Auto-rig Identity(Skeltal Mesh + Full Metahuman)」を押下して作成完了です。 メッシュからMetahumanの作成が完成しましたら、Metahuman Creator を使ってテクスチャ・体形等の調整を行います。 Metahuman Creator は、ヘアスタイル・顔の特徴・身長・ボディプロ ポーション ・衣服などを編集できるツールです。 Metahuman Creator はブラウザ上で使用します。 こちらのリンク からアクセスし、上記を編集していきます。 自分が使用しているUEのバージョンを選択し、「Metahuman Creator を起動」を押下します。 先ほどMetahuman Identityで作成したMetahumanを選択し、「選択したものを編集」を押下します。 肌のスキンを編集します。 後にフォトグラメトリで作成したテクスチャと合成しますので、最低限だけ編集します。 「テクスチャ」は数値を上げるとシワが増え老けているように見えますので、0に設定しました。 「カラー」や「ラフネス」はお好みで設定しましょう。 目を編集します。 「 虹彩 サイズ」や「 虹彩 彩度」は見た目の印象に大きく影響しますので、モデルの写真を見ながら調整しました。 また、「ベー スカラー 」「詳細カラー」も、モデルの写真を見ながら軽く調整しました。 髪の毛はお好みで設定します。 今回は元の写真と比較しやすいように、短髪に設定しています。 眉毛は「なし」に設定します。 これは、後にフォトグラメトリで作成したテクスチャから眉毛を持ってくるためです。 まつげもお好みで設定します。 体の調整もお好みで行います。 今回はモデルの方と近くなるよう、以下のように体型や頭の大きさを設定しました。 「上半身」「下半身」「靴」では身に着ける衣服を変更できます。 Metahuman Creator でのテクスチャ設定が完了しましたら、UE5に戻ります。 ※Metahuman Creator では常に自動保存がされていますので、「保存」ボタンなどを押す必要はありません。 「ウィンドウ → Quixcel Bridge」でQuixcel Bridgeを開きます。 「MetaHumans → My MetaHumans」から先ほど編集したMetahumanを選択し、「Download」を押下します。 20分ほど待つとダウンロードが完了しますので、「Add」を押下します。 コンテンツブラウザのMetaHumansフォルダ配下に、Metahumanが追加されていることを確認できます。 「BP_(Metahuman名)」のファイルを ドラッグ&ドロップ し、画面上に配置します。 Metahuman Creator で設定したままのMetahumanを配置できました。 モデル写真との比較になります。 「全く似ていない」というわけではないですが、目や肌の質感で違いを感じてしまいます。 4.Metahumanにフォトグラメトリテクスチャを合成(3D テクスチャマッピング ) Metahumanの顔をよりモデルに似せるために、フォトグラメトリで作成したテクスチャを合成します。 まず初めに、MetahumanのメッシュとテクスチャをUE5からエクスポートします。 Metahumanが格納されているフォルダ内で「facemesh」と検索します。 フェイスメッシュを右クリックし、「アセットアクション → エクスポート」を押下します。 以下のように設定し、エクスポートを実行します。 フェイスメッシュと同様に、「FaceColor_MAIN」と検索してテクスチャをエクスポートします。 次に、 Blender を用いてフェイスメッシュの余分な部位を取り除きます。 Blender で新規ファイルを開き、デフォルトで配置されるオブジェクトを全て削除します。 「ファイル → インポート → FBX」を押下します。 先ほどUE5からエクスポートしたフェイスメッシュを選択し、「FBXをインポート」を押下します。 フェイスメッシュがインポートされました。 画面右のフェイスメッシュ内訳を開き、「root」の右にある目玉を押下してメッシュモデルだけを表示します。 画面上でメッシュモデルを選択後、「オブジェクトモード → 編集モード」を選択します。 一度メッシュモデルの外側を押下して選択状態を解除した後、モデルの頭頂部を押下します。 その後キーボードのLキーを押下すると、下記のように頭部メッシュが選択されます。 キーボードのHキーを押下して頭部メッシュを非表示にすると、目と歯のメッシュが残ります。 Aキーで残ったメッシュを全選択し、Xキーを押下後に「頂点」を選択し、これらのメッシュを削除します。 Alt + Hキーで頭部メッシュを再表示します。これにて余分なメッシュを取り除くことができました。 「ファイル → エクスポート → Wavefront(.obj)」を押下し、上記をOBJファイルとして出力します。 次に、Wrapを用いてフォトグラメトリで作成したテクスチャをMetahuman用に転写します。 Wrapの新規ファイルを開き、2.の最後に出力した(3.にてUE5にインポートした)メッシュ(OBJ形式)とテクスチャを ドラッグ&ドロップ でインポートします。 インポートしたメッシュとテクスチャのノードを結合します。 先ほど Blender でエクスポートしたフェイスメッシュと、UE5からエクスポートしたFaceColor_MAINのテクスチャをインポートします。 インポートしたフェイスメッシュとテクスチャのノードを結合します。 ※フェイスメッシュは非常に小さくインポートされますので、見えやすいように「Scale」を調整しましょう。 インポートした2つのメッシュを両方とも表示します。 表示と非表示はメッシュノードの電球マークを押下して制御できます。 2.でのWrap手順と同様に、「RigidAlignment」「SelectPointPairs」を用いて2つのメッシュに対して位置合わせを行います。 右クリックから「RigidAlignment」「SelectPointPairs」ノードを追加し、以下のように結合します。 「SelectPointPairs」ノードを選択した状態でVisualEditorエリアを表示し、「Sync Views」をチェックした上で以下のように位置合わせの基準点を追加しました。 Viewport3Dエリアに戻り、「RigidAlignment」ノードを選択して「Fit Scale」にチェックを入れます。 これにて位置合わせが完了しました。 「Wrapping」ノードを追加し、以下のように結合して「Compute」を実行します。 Wrappingが完了しました。 ベースメッシュの表示をオフにすると、綺麗にWrappingされていることが確認できます。 「TransferTexture」「ExtrapolateImage」ノードを用いてフォトグラメトリで作成したテクスチャをMetahumanのメッシュに転写し、「SaveImage」で保存します。 「TransferTexture」ノードは特定のジオメトリ(メッシュ)から別のジオメトリへテクスチャを転写する機能です。 また、「ExtrapolateImage」ノードはテクスチャの色がある部分から外挿してテクスチャの透明な部分を塗りつぶしてくれる機能です。 以下のようにノードを結合します。 「ExtrapolateImage」ノードを選択してViewport2Dエリアを表示すると、処理されたテクスチャが現れます。 テクスチャ内の透明だった部分がいい感じに埋められていることを確認できます。 「SaveImage」ノードで出力先を指定し、「Compute Curent Frame」からテクスチャを出力します。 これにて、フォトグラメトリで作成したテクスチャをMetahumanで使えるように転写することができました。 最後に、PhotoShpopを用いて「MetahumanのFaceColor_MAINテクスチャ」と「Wrapからで出力した転写テクスチャ」を合成していきます。これは、フォトグラメトリで作成したテクスチャを違和感なくMetahumanに馴染ませるためです。 合成は以下のようなイメージで行います。 Photoshop を起動し、「ファイル → スクリプト → ファイルをレイヤーとして読み込み」を押下します。 先ほどWrapしたテクスチャ(フォトグラメトリで作成したテクスチャを転写したテクスチャ)と、UE5から出力したMetahumanのFaceColor_MAINテクスチャを選択します。 ※Wrapにて出力する際に4096×4096で出力しましたが、FaceColor_MAINテクスチャのサイズが2048×2048であった為、こちらも2048×2048にサイズダウンしたものを選択しています。 選択したファイルがインポート対象一覧に表示されていることを確認し、「OK」でインポートします。 2つのテクスチャがレイヤーとしてインポートされたら、それぞれを分かりやすい名前に変更します。 今回は、Wrapで出力したテクスチャは「Photogrametry」、UE5から出力したテクスチャは「Metahuman」と 命名 しました。 インポートが完了したので、合成作業に入っていきます。 左端のツール一覧から「スポイトツール」を選択しましょう。 このツールを使用して、それぞれのテクスチャにおける肌の色をサンプリングします。 サンプル範囲は「5 ピクセル 四方の平均」とします。 「Metahuman」レイヤーを選択し、顔の眉間あたりを左クリックして肌色をサンプリングします。 サンプリングが完了したら、画面右下の「レイヤー」から新規レイヤーを作成します。 このレイヤーは、2つのテクスチャの肌色を比較する用途で利用します。 レイヤー名は「色比較」としました。 ※下記画像では、「Photogrametry」「Metahuman」レイヤーを非表示にしています。表示/非表示はレイヤー一覧左の「目のマーク」を押下して制御できます。 左端のツール一覧から「ブラシツール」を選択し、ブラシの種類・直径・不透明度・流量・滑らかさを設定します。 今回は下記のように設定しました。 「色比較」レイヤーを選択し、 ドラッグ&ドロップ でレイヤー一覧の最上段に移動させます。 すべてのレイヤーを表示状態にした上で再度「色比較」レイヤーを選択し、画像左上部分にブラシで色を塗ります。 この時、先ほどサンプリングした「Metahuman」レイヤーの肌色で色が塗られます。 「Photogrametry」レイヤーを選択し、上記同様にスポイトツールで肌の色をサンプリングします。 「色比較」レイヤーを選択し、画像右上部分にブラシで色を塗ります。 左端のツール一覧で「スポイトツール」を右クリックし、「カラー サンプラー ツール」を選択します。 先ほどブラシツールで塗った色の部分を、「左 → 右」の順で選択します。 これにより、それぞれの肌色のRGB値をサンプリングできました。 (「Metahuman」レイヤーの肌色が#1、「Photogrametry」レイヤーの肌色が#2となっていれば問題ありません) 「Photogrametry」レイヤーを選択した状態で、左端のツール一覧から「なげなわツール」を選択します。 なげなわツールにて、下記画像のように顔の周辺を囲います。 画面右下の「追加」を左クリックし、「 トーンカーブ 」を選択します。 「 トーンカーブ 1」レイヤーが作成されたら、その中の白黒レイヤーマスクではない、レイヤー本体部分を選択します。 下記画像の赤い部分になります。 画面右中央部の手指マークを押下し、Ctrl+Shiftを押しながら「Photogrametry」レイヤーの肌色(#2)を選択します。 トーンカーブ 設定の「RGB」を 「レッド」 に変更します。 入力・出力ともに#2のR値となっていることが確認できましたら、出力を#1のR値に変更します。 今回の場合は、「187(#2のR値)→ 220(#1のR値)」と変更しました。 「グリーン」、「ブルー」に対しても同様に出力を変更します。 グリーンではG値、ブルーではB値を使います。 すべてのRGB出力値を変更したら、Ctrlを押しながら「 トーンカーブ 1」レイヤーの白黒レイヤーマスクを選択します。 「Photogrametry」レイヤーを選択し、画面右下の「レイヤーマスク」を押下します。 「Photogrametry」レイヤーの白黒レイヤーマスクが作成されました。 顔の肌色と外側の肌色を比較し、おおよそ色が近くなっていることを確認します。 「 トーンカーブ 1」レイヤーと「Photogrametry」レイヤーだけを表示状態にし、Ctrl+Shift+Alt+Eを押します。 これにより、表示レイヤーだけを結合した新しいレイヤーが作成されます。 このレイヤーは「肌調整後」レイヤーとしました。 「Photogrametry」レイヤーの白黒レイヤーマスクを、 ドラッグ&ドロップ で「肌調整後」レイヤーへ移動させます。 その後、「肌調整後」レイヤーと「Metahuman」レイヤーだけを表示状態にします。 「肌調整後」レイヤーの白黒レイヤーマスクを選択した状態で、「ブラシツール」を選択します。 黒色の「ソフト円ブラシ」を用いて、頭や髪の毛の黒い部分、肌の境界部分を慣らします。 全体的に慣らし、下記のような仕上がりになりました。 ブラシの直径を短くした上で、同様に口と鼻も慣らします。 目の上部を修正する際は、「肌調整後」レイヤーのレイヤー本体を選択した状態で、「コピースタンプツール」を使用します。 コピースタンプツールは、Alt+左クリックで画像の特定位置をコピーし、他の場所にコピーした位置周辺の色を反映させることができる機能です。 目の上部で色が崩壊していない部分をコピーし、その色を用いて他部分の修正を行いましょう。 以下のように修正できました。 最後に、目を修正しましょう。 再度「肌調整後」レイヤーの白黒レイヤーマスクを選択した状態で、「ブラシツール」を選択します。 鼻や口を修正したときと同様に、黒色「ソフト円ブラシ」を用いて慣らします。 以下のように修正できました。 テクスチャ全体を確認してみます。 髪の毛の黒色が少し目立っていたので、再度レイヤーマスクを慣らして調整しました。 これにてテクスチャの合成が完了です。 完成したテクスチャを PNG 形式で出力します。 「ファイル → 書き出し → 書き出し形式」を選択します。 ファイル形式を「 PNG 」に設定して出力します。 UE5に戻り、 Photoshop で出力した合成テクスチャをMetahumanに適応しましょう。 コンテンツブラウザの「コンテンツ」フォルダを右クリックし、「新規フォルダ」を押下します。 新規フォルダに移り、先ほど出力した合成テクスチャを ドラッグ&ドロップ します。 「Metahumans」フォルダにて「MI_HeadSynthesized_Baked」とファイル検索を行い、該当ファイルをダブルクリックします。 編集画面が開いたら、先ほど ドラッグ&ドロップ した合成テクスチャを選択します。 右上のパラメータ検索欄で「base」と検索し、「BaseColor」にある「←」ボタンを押下して合成テクスチャを適用させましょう。 残りのテクスチャにも適用させます。 画面左上から保存して編集画面を閉じると、合成テクスチャが反映されたMetahumanを見ることができます。 元のモデル写真との比較になります。 目や眉毛、肌の質感を含めモデルとかなり似ているMetahumanを作成することができました。 おわりに 前後編を通し、フォトグラメトリで作成したメッシュ・テクスチャを用いてMetahumanを作成する手法を紹介してきました。使用する機材・ソフトウェアがなかなか多くなりましたが、その分かなりモデルと似ているMetahumanを作成できました。 今後、様々な メタバース 領域のサービスでMetahumanが利用されていくと思いますが、今回作成したように 「本人そっくりな」 Metahumanを活かしたサービスが増えていくことが楽しみです。 記事をご覧いただきまして、ありがとうございました! 現在、 電通 総研は web3領域のグループ横断組織 を立ち上げ、Web3および メタバース 領域のR&Dを行っております(カテゴリー「3DCG」の記事は こちら )。 もし本領域にご興味のある方や、一緒にチャレンジしていきたい方は、ぜひお気軽にご連絡ください! 私たちと同じチームで働いてくれる仲間を、是非お待ちしております! 電通総研採用ページ 参考文献 ・ 回転台とグリーンバックによる本格フォトグラメトリ撮影(Adobe Photoshop × RealityCapture) ・ フォトグラメトリによる3Dモデル作成ワークフロー(前編) ・ フォトグラメトリによる3Dモデル作成ワークフロー(後編) ・ 初歩からのフォトグラメトリ~人物フォトグラメトリを活用してUnreal EngineでMetahumanを作成する方法〜【写真からゲームで使える3Dキャラを作ってみよう! vol.11】 ・ 初歩からのフォトグラメトリ~Wrapの使いかた(初級編)RealityCaptureで作ったモデルを綺麗にリトポロジーしよう!~【写真からゲームで使える3Dキャラを作ってみよう! vol.8】 ・ Pushing the MetaHuman Likeness Limits via Scan-based Textures | Unreal Fest 2022(YouTube) ・ Easy Trick To Match SKIN TONES in Photoshop Fast!(YouTube) ・ UNREAL ENGINE download ・ RealityCapture ・ Wrap ・ MetaHuman Creator ・ 顔の周りのテクスチャを馴染ませる(YouTube) ・ 目のまわりを調整(YouTube) 執筆: @matsuzaki.shota 、レビュー: @sato.taichi ( Shodo で執筆されました )
アバター
みなさんこんにちは!  電通 総研 金融ソリューション事業部の松崎です。 前回の記事 では、回転台やグリーンバックを用いたフォトグラメトリ手法について紹介しました。 この手法は今回のMetahuman作成の中でも使用しておりますので、まだご覧になっていない方は是非ご一読ください。 今回から、2回に分けてフォトグラメトリを活かしたMetahuman作成のワークフローを紹介していきます。 この記事は前編です、読み終わりましたら是非 後編 もご覧ください。 はじめに 本記事ではフォトグラメトリにて人物頭部のメッシュ・テクスチャを作成し、それを用いてMetahumanを作成する手法を紹介します。 ※フォトグラメトリに関しては、 以前の記事 をご参照ください。 MetahumanとはEpic社が提供しているデジタルヒューマン作成用の フレームワーク であり、UnrealEngine上で簡単に使用できることが特徴です。 今回はMesh to Metahumanを用いてMetahumanを作成します。Mesh to Metahumanとは、3DメッシュからMetahumanを作成するUnrealEngineの機能です。 Mesh to MetahumanではMetahumanのメッシュ・テクスチャが作成されますが、現段階ではテクスチャのクオリティがそこまで高くない為、そのまま使用するとそっくりと言えるレベルにはなりません。 そこで今回は、フォトグラメトリで作成した頭部テクスチャを使用してクオリティの向上を図ります。 Mesh to Metahumanで作成されたMetahumanテクスチャにフォトグラメトリで作成したテクスチャを合成することで、 「人物そっくりな」 Metahumanを作成できました。 次章より、以下の目次に沿ってMetahuman作成方法を紹介していきます。 目次 使用機材紹介 撮影方法 1.頭部メッシュ&テクスチャ作成(フォトグラメトリ) 2.頭部メッシュのリ トポロジー (3Dメッシュ編集) 3.Metahumanの作成と編集(Mesh to Metahuman) 4.Metahumanにフォトグラメトリテクスチャを合成(3D テクスチャマッピング ) 前編では2章までご紹介します。 使用機材 PC PCはスペックの高いものを使用しております。これは、フォトグラメトリにおける処理時間を短縮させる為です。 PCの具体的なスペック、並びにフォトグラメトリを行う際に必要なスペックを記載します。 使用PCスペック OS: Windows 11 Pro 64bit CPU: Intel Core i9 -13900KF CPUコア数:24 RAM:64GB GPU : NVIDIA GeForce RTX 4090 CUDAコア数:16384 グラフィックメモリ:24GB フォトグラメトリの必要スペック OS:64bit Microsoft Windows version 7 / 8 / 8.1 / 10 / 11 または Windows Server version 2008+ CPU:SSE4.2(Streaming SIMD Extensions 4.2)以降 RAM(メモリ):8GB以上 GPU : NVIDIA graphics card with CUDA 3.0+ capabilities で 、VRAMが1GB以上 DRIVER:CUDA Toolkit 10.2, minimal driver version 441.22. カメラ(2台) カメラは人物の頭部を撮影する用途で、2台使用しました。1台は人物の頭部を正面から撮影し、もう1台は斜め下から撮影しています。 人物を撮影する場合、撮影時間が長くなると動いてしまうリスクが高まりますので、カメラは2台用いて一気に撮影することが望ましいです。(予算が許す場合はカメラを何十台も用意して360度に配置し、1回の撮影で終えられると理想的です) 本来であれば2台とも同じ機種であることが望ましいですが、今回はそろえることができなかった為、以下の機種を1台ずつ使用しました。 Sony α7R IV (Lens: Sony Vario-Tessar T* FE 16-35mm F4 ZA OSS (SEL1635Z)) Sony α7C (Lens: SIGMA 28-70mm F2.8 DG DN | Contemporary ) 三脚(2台) 手振れ防止目的にて三脚を使用しています。 フォトグラメトリでは手振れが天敵となりますので、可能な限り三脚を用いることが推奨されます。 照明(2台) 照明2台を用いて、人物の頭部を照らしました。 照明を当てると人物の輪郭が強調されますので、フォトグラメトリで作成されるテクスチャがより本人らしくなります。 また、定常光による意図しない影を作らない為にも照明を用いています。 回転台 人物本人やカメラを動かさずに360度撮影できるよう、回転台を使用しました。 撮影対象人物を回転台に乗せることで、人物本人に同じ姿勢をキープさせたまま回転させることができます。 ヘアネット 髪の毛を仕舞い込む用途にて使用しました。 Mesh to MetahumanでMetahumanを作成する際に髪の毛は邪魔になりますので、ヘアネットで1ヵ所に纏めます。 撮影方法 人物頭部の撮影風景は以下のようになります。 (画像では正面カメラの位置が低いですが、実際の撮影時は顔の正面に来るよう高さを調整しています) 白い壁を背景にして回転台を置き、撮影対象の人物が乗ります。 カメラは人物頭部の「正面」「斜め下」に1台ずつ配置し、照明は正面から斜め45度の位置に1台ずつ設置しました。 撮影時、撮影対象人物にはなるべく同じ表情・姿勢で静止してもらい、回転台を少しずつ回しながら撮影を進めていきます。 撮影枚数に関して、今回は1周でカメラ1台あたり36枚ほど撮影しました。(回転台は約10度ずつ回す) 回転台を回す度にカメラ2台分のシャッターを切る必要がありますので、撮影側には最低2人用意しておくことが望ましいです。 1.頭部メッシュ&テクスチャ作成(フォトグラメトリ) 人物の頭部を撮影し、フォトグラメトリにてメッシュとテクスチャを作成します。 まず初めに写真撮影です。 上記の撮影方法にて人物頭部の撮影を行い、以下のようになりました。 (今回は先輩社員にモデルをお願いしました) 正面 斜め下 次に、フォトグラメトリにてメッシュとテクスチャを作成します。 詳細な手順は 以前の記事 で紹介しておりますので、そちらをご参照ください。(記事同様、今回も RealityCapture を用いてフォトグラメトリを行いました) フォトグラメトリによって完成したメッシュとテクスチャが以下になります。 頭頂部が崩れていますが、この部分は次章で行うリ トポロジー にて解消されるため問題ありません。(詳細は後述します) 完成したメッシュ/テクスチャをOBJ形式/ PNG 形式にて出力します。 ※出力ファイルサイズ メッシュ(OBJ):約6GB テクスチャ( PNG ):約200MB 2.頭部メッシュのリ トポロジー (3Dメッシュ編集) 1.にて作成した頭部メッシュのリ トポロジー を行います。 リ トポロジー とは、ポリゴンの流れ( トポロジー )を再構築して整える作業のことです。 今回はMetahumanで使うための頭部メッシュを作成しているので、以下の点を意識してリ トポロジー を行う必要があります。 ポリゴン数を減らし、軽くて操作しやすいメッシュにする 自然な表情変化ができるよう、人間本来の表情筋の流れに沿った トポロジー を構築する 上記の1点目だけであればRealityCapture上でも行うことができますが、2点目は不可能です。 そこで今回は、 Wrap という3D モデリング ソフトウェアを使用してリ トポロジー を行いました。 Wrapとは、その名の通り自分の3DメッシュをWrap側のベースメッシュに被せられるソフトウェアです。Wrap側で用意されているデフォルト顔のベースメッシュに自分でスキャンしたメッシュを被せることで、簡単にリ トポロジー を行うことができました。 Wrapのインストールは こちら から行うことができます。有料ソフトウェアですが、初回30日は無料で試用できるので是非お試しください。 それでは、実際にWrapを使ってリ トポロジー を行っていきます。 Wrapを立ち上げ、画面左上の「File → New Project」で新規プロジェクトを作成します。 「Gallary」タブを押下し、Basemeshsから「Head」を選択します。 こちらが、今回のリ トポロジー でベースに使うメッシュです。 Graphエリアに「Head」のノードが追加されました。また、Viewport3Dエリアでは追加した「Head」のメッシュ本体を見ることができます。 次に、フォトグラメトリで作成した頭部メッシュを読み込みます。 Graphエリアで右クリックし、「LoadGeom」を選択します。 Graphエリアに追加された「LoadGeom」ノードを選択すると、Editorエリアに設定項目が表示されます。 File Nameの右にある「...」を押下し、フォトグラメトリで作成したOBJ形式のメッシュを読み込みます。 ※画像のように、ファイルパスに日本語が混ざっていると正常に読み込まれません。パスは英数字のみで指定するようにしましょう。 「Reload」を押下し、読み込みを開始します。 読み込みが完了すると、以下のように真っ黒なメッシュが現れます。 Editorエリアの「Wireframe」のチェックを外すと、メッシュが見やすくなります。 「Head」メッシュと「LoadGeom」で読み込んだメッシュの位置合わせを行います。 今回は「LoadGeom」メッシュの位置と角度を変化させます。 「LoadGeom」を選択し、Editorエリア「Rotation」の値を変えて向きをそろえます。 向きがそろったら、Viewport3Dエリアのギズモ(赤青緑の移動・回転・拡大縮小ツール)を使用して位置合わせを行います。 必要に応じ、ギズモを使って向きの微調整も行いましょう。 下記図のように位置がおおよそ重なっていれば問題ありません。 次に、フォトグラメトリで作成したテクスチャを読み込みます。 対象のテクス チャフ ァイルをGraphエリアに ドラッグ&ドロップ します。 テクスチャのノードが作成されますので、「LoadGeom」ノードと結合します。 これにより、「LoadGeom」で読み込んだメッシュにテクスチャが反映されます。 Graphエリアで右クリックし、「RigidAlignment」ノードを追加します。 このノードを使い、さきほど大まかに位置合わせした2つのメッシュを正確に合わせていきます。 下図のように、各ノードを結合します。(結合する位置を間違えないように注意しましょう) Graphエリアを右クリックして「Selectpointpairs」ノードを追加します。 このノードは、「RigidAlignment」ノードで位置合わせを行う際の基準点を指定するために使用します。 下図のように、各ノードを結合します。 「Selectpointpairs」ノードを選択した状態でVisualEditorエリアを表示させます。 Editorエリアの「Sync Views」にチェックを入れます。これにより、VisualEditorエリアの2つのメッシュが連動して動くようになります。 VisualEditorエリアにて、位置合わせの基準点を設定します。基準点には目や口・鼻・顎先など、顔の特徴的な部分を設定することが望ましいです。今回は下図のように目と顎先の3点を設定しました。 基準点の設定が完了したら、Viewport3Dエリアを表示します。 「RigidAlignment」ノードを選択し、「Fit Scale」にチェックを入れます。これにより、メッシュのサイズを変えながら基準点をより正確に合わせてくれます。 「RigidAlignment」ノードの名前を分かりやすい名前に変更します。 ノードを選択してF2を押すと名前が変更できます。 今回は参考にさせていただいたブログ に習い、「RC_Aligned」としました。 次に「Wrapping」ノードを追加します。名前の通り、このノードではラッピング処理を行います。 下図のように「Head」ノードと「RC_Aligned」ノードを結合し、Editorエリアの「Compute」を押下します。 ラッピング処理完了後のメッシュと、フォトグラメトリで作成したメッシュ(+テクスチャ)の比較画像になります。 顔全体の形はかなり近いものになっている一方、目や鼻・口の形には少し差異が確認できます。 ラッピング処理の精度を上げるために、「Selectpointpairs」ノードを追加します。 新規で「Selectpointpairs1」ノードを追加し、下図のように各ノードと結合します。 先の「Selectpointpairs」ノードと同様に、VisualEditorエリアにて位置合わせの基準点を設定します。 目・鼻・口・耳に対して下図のように基準点を設定しました。 「Selectpointpairs1」ノードを「Wrapping」ノードに結合し、再度「Wrapping」ノードの「Compute」を押下します。 「Selectpointpairs1」ノード追加前と追加後、およびフォトグラメトリで作成したメッシュの比較画像です。 微妙な差ではありますが、目や鼻・口の大きさが元の形に近づいていることが確認できます。 ラッピング処理が満足いく形まで完了したら、最終調整に入ります。 最終調整では「Brush」ノードを使用します。このノードは、各種ブラシを使う要領でメッシュの微調整ができるツールです。 右クリックでノードを追加したら、下図のように結合します。 「Brush」ノードを選択した状態でVisualEditorエリアを表示すると、各種ブラシが選択できます。 今回は頭の形をベースメッシュに寄せていくので、「Clone」ブラシを使います。 「Clone」ブラシは、Geometry Sourceにつないだメッシュ(今回の場合は「Head」ノードのメッシュ)を基準としてメッシュ形状が変化するブラシです。 (対して、「RelaxProj」ブラシはReferenceに繋いだメッシュ(今回の場合は「RC_Aligned」ノードのメッシュ)を基準として変化します) Editorエリアの「 Radius 」ではブラシの半径、「Strength」ではブラシのかかる強度を設定できます。 「Clone」ブラシを用いて、頭部の出っ張りを修正しました。 「Clone」ブラシを使っていると、想定よりベースメッシュに寄ってしまうことがあります。そのような時は、適宜「RelaxProj」ブラシで戻し修正しながら、弱めの「Clone」ブラシで調整しましょう。 修正が完了したら、「Accept」を押下して反映させます。 Brush処理の実施前、実施後、並びにフォトグラメトリで作成したメッシュの比較画像です。 頭部の出っ張りも解消し、最終調整が完了しました。 メッシュが完成しましたので、テクスチャを貼り付けます。 「TransferTexture」ノードを追加し、下図のように結合します。これにより、完成したメッシュにフォトグラメトリで作成したテクスチャを貼ることができました。 「Resolution」は4096×4096にしていますが、ここはお好みで設定して問題ありません。 「TransferTexture」ノードを選択した状態でViewport2Dエリアを表示すると、貼り付けられているテクスチャを見ることができます。 「SaveGeom」ノードを追加し、メッシュを保存します。 File Nameの右にある「...」から保存先とファイル名を選択し、「Compute Current Frame」で保存実行します。 出力されたメッシュ(OBJ)のファイルサイズを確認すると約500KBでした。RealityCaptureで出力したメッシュ(OBJ)は約6GBでしたので、リ トポロジー によりファイルが大きく軽量化されていることを確認できます。 同様に、「SaveImage」ノードを追加し、テクスチャを保存します。 File Nameの右にある「...」から保存先とファイル名を選択し、「Compute Current Frame」で保存実行します。 今回は PNG 形式で、Qualityは劣化なしの100で出力しました。 出力されたテクスチャ( PNG )のファイルサイズは約15MBでした。 これにてリ トポロジー 完了です。 おわりに 前編では、機材紹介や人物頭部をフォトグラメトリするにあたっての撮影方法に加え、フォトグラメトリ後の3Dメッシュ モデリング 方法を紹介しました。私自身もWrapは初めて使うソフトウェアだったのですが、ノードベースで直感的に操作ができて使いやすかったです。また、ラッピング処理の優秀さには驚かされました。 後編 では、Mesh to Metahumanや Photoshop を用いて人物そっくりなMetahumanを作成していきます。 是非こちらもご覧ください! 現在、 電通 総研は web3領域のグループ横断組織 を立ち上げ、Web3および メタバース 領域のR&Dを行っております(カテゴリー「3DCG」の記事は こちら )。 もし本領域にご興味のある方や、一緒にチャレンジしていきたい方は、ぜひお気軽にご連絡ください! 私たちと同じチームで働いてくれる仲間を、是非お待ちしております! 電通総研採用ページ 参考文献 ・ 回転台とグリーンバックによる本格フォトグラメトリ撮影(Adobe Photoshop × RealityCapture) ・ フォトグラメトリによる3Dモデル作成ワークフロー(前編) ・ フォトグラメトリによる3Dモデル作成ワークフロー(後編) ・ 初歩からのフォトグラメトリ~人物フォトグラメトリを活用してUnreal EngineでMetahumanを作成する方法〜【写真からゲームで使える3Dキャラを作ってみよう! vol.11】 ・ 初歩からのフォトグラメトリ~Wrapの使いかた(初級編)RealityCaptureで作ったモデルを綺麗にリトポロジーしよう!~【写真からゲームで使える3Dキャラを作ってみよう! vol.8】 ・ Pushing the MetaHuman Likeness Limits via Scan-based Textures | Unreal Fest 2022(YouTube) ・ Easy Trick To Match SKIN TONES in Photoshop Fast!(YouTube) ・ UNREAL ENGINE download ・ RealityCapture ・ Wrap ・ MetaHuman Creator ・ 顔の周りのテクスチャを馴染ませる(YouTube) ・ 目のまわりを調整(YouTube) 執筆: @matsuzaki.shota 、レビュー: @wakamoto.ryosuke ( Shodo で執筆されました )
アバター
こんにちは。 電通 総研コーポレート本部システム推進部の山下です。 最近はChatGPTなどのLarge Language Model(LLM)を利用したAIが話題ですね。 そのLLMを応用したRetrieval-Augmented Generation(RAG)という技術があります。 これは、LLMに文書検索などを用いて関連する情報を与えて回答させることで、 LLMが知識として持っていない内容を回答させたり誤った情報を答えてしまうハルシネーションを抑止する技術です。 今回はこのRAGをLlamaIndexというライブラリを使ってローカル環境で実装する方法について紹介します。 なぜローカル環境でLLMを利用したいのか 大変便利なツールのLLMですが、利用が難しいこともあります。 例えば、機密情報を取扱いたい、外部インターネットへの接続に制限が掛かっているといった場合です。 最終的にOpenAIなどの外部 API の利用が難しいという判断になる場合もあるかと思います。 こういった場面でローカル環境やオンプレミスのサーバ上でLLMを利用できればこういった問題を回避することが出来ます。 LlamaIndexとは? 今回はLLMを利用したアプリケーションを開発するための フレームワーク として LlamaIndex を利用します。LlamaIndexはどのようなライブラリなのでしょうか。 マニュアル の冒頭に以下のような説明があります。まさにRAGを実現するために作られた フレームワーク です。 LlamaIndex is a data framework for LLM-based applications to ingest, structure, and access private or domain-specific data. It’s available in Python (these docs) and Typescript. LlamaIndexは色々な機能を提供してくれますが、筆者が特に便利だと感じているのは 以下の機能です。 既存のデータの読み込みとインデックス化 各種LLMを利用したインタフェース(チャットインタフェースの実現) これらの機能を組み合わせることで、既存のデータを読み込み、その情報を元にLLMへのクエリを作成してRAGの実現が可能となります。 その他のLlamaIndexの詳細な機能はマニュアルを参照してください。 環境構築 LLMを利用するには GPU を利用した環境が望ましいです。 ここでは、 Windows 上のWSLとdevcontainerを利用した環境構築の方法について説明します。 また利用する GPU は NVIDIA 社製の GPU を想定しています。 ここではRTX 3060を搭載している計算機で実行しました。 nvidia -dockerの環境構築 開発で利用するコンテナで GPU を利用可能にするため、 nvidia-container-toolkit のインストールを実施します。 ここでは WSL上の Ubuntu で以下のコマンドを実行してインストールを実施します。 distribution=$(. /etc/os-release;echo $ID$VERSION_ID) \ && curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \ && curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list | \ sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \ sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list sudo apt-get update sudo apt-get install -y nvidia-container-toolkit Dev Containerの環境 次に、Dev Containerを利用してどこの環境でも手軽に開発が行えるようにします。 まず、ソースツリーのトップ ディレクト リに .devcontainer という ディレクト リを作成します。今回は以下のようなファイル構成で作成します。 .devcontainer ├── Dockerfile ├── devcontainer.json └── requirements.txt まずは、 requirements.txt を以下のような内容で作成します。 torch==2.1.1 llama-index==0.9.13 transformers==4.35.2 llama_cpp_python==0.2.20 次に Dockerfile を以下のような内容で作成します。 llama_cpp_python が GPU を使うために インストール時に=CMAKE ARGS ="-DLLAMA CUBLAS =on"= を設定します。 FROM nvidia/cuda:12.3.0-devel-ubuntu22.04 RUN apt update \ && apt install -y \ wget \ bzip2 \ git \ git-lfs \ curl \ unzip \ file \ xz-utils \ sudo \ python3 \ python3-pip && \ apt-get autoremove -y && \ apt-get clean && \ rm -rf /usr/local/src/* # requirements.txt をコピーして必要なライブラリをインストール COPY requirements.txt /tmp/ RUN pip install --no-cache-dir -U pip setuptools wheel \ && CMAKE_ARGS="-DLLAMA_CUBLAS=on" pip install --no-cache-dir -r /tmp/requirements.txt devcontainer.json の内容は以下のような内容で作成します。 runArgs に --gpus オプションを追加してコンテナ内部から GPU を利用可能にします。 { " name ": " Cuda DevContainer ", " build ": { " dockerfile ": " ./Dockerfile " } , " runArgs ": [ " --gpus ", " all " ] } ここまでで、Dev Containerを利用した開発環境の構築が出来ました。 それでは、さっそくLlamaIndexを利用したRAGの実装を行ってみましょう。 以降の作業は、構築したDev Container環境を起動して実施します。 LlamaIndexを利用したRAGの実装例 実装するシステムの概要 今回実装するRAGのシステムは、以下の仕組みのものを実装します。 data という ディレクト リにあるテキストファイルを読み込む テキストの内容を埋め込みモデルを利用してインデックスを作成する インデックスとLLMモデルを利用して質疑応答を行う また、今回利用するモデルは以下のものを利用します。 埋め込みモデル: multilingual-e5-large LLMモデル: ELYZA-japanese-Llama モデルのダウンロード models という ディレクト リを作成して、その中にモデルをダウンロードします。 git lfs clone https://huggingface.co/mmnga/ELYZA-japanese-Llama-2-7b-instruct-gguf/ --include "ELYZA-japanese-Llama-2-7b-instruct-q8_0.gguf" RAGの実装 ここまででRAGを実装する環境が整いました。 Python を使ってRAGを実装します。 必要なパッケージのimport まずは llama_index などの必要なパッケージをimportします。 import logging import os import sys from llama_index import ( LLMPredictor, PromptTemplate, ServiceContext, SimpleDirectoryReader, VectorStoreIndex, ) from llama_index.callbacks import CallbackManager, LlamaDebugHandler from llama_index.embeddings import HuggingFaceEmbedding from llama_index.llms import LlamaCPP # ログレベルの設定 logging.basicConfig(stream=sys.stdout, level=logging.DEBUG, force= True ) data ディレクト リに含まれるテキストファイルを読み込みます。 # ドキュメントの読み込み documents = SimpleDirectoryReader( "data" ).load_data() LLMのモデル、埋め込みモデルの初期化を行います。ここでは特に設定を変更することなく、multilingual-e5-largeをそのまま利用しています。ただし、 公式サイト の説明に 「query:」の接頭辞を付けて利用する方が良いと注意書きがあります。詳細に能力を確認する場合などは「query: 」を付けるような実装にする必要があります。 n_ctx はLLMモデルのコンテキスト数になります。ELYZAのcontext sizeは4096なので4096を設定しました。 n_gpu_layers は、LlamaCPPはCPUと GPU の両方を利用できるのですが、 GPU でいくつの層を処理するのかを指定するものになります。RTX 3060では32程度を指定しておくのが良さそうだったので32を指定しています。 multilingual-e5-large は実行時にダウンロードされます。 このため初回実行時には時間がかかります。 ServiceContext を作成する時にしている、 chunk_size は分割した文書のサイズとなっています。この大きさはRAGを実施する際に与える文書の量に直接影響があります。 RAGではLLMに対する質問(クエリ)を構築する際に、コンテキスト情報として質問の内容に応じた文書を与える仕組みになっています。 この与えられる文書の大きさが chunk_size で決まります。1つの文書のサイズが大きい場合は前後の文脈を多く含むことになります。コンテキスト情報は多い方が良いので大きくしたくなります。しかし、1つのクエリに対して与えられる文書の量には上限があります。今回は4096が最大になっています(LLMに指定している context_size )。 また、検索でなどでコンテキスト情報を見つけて複数のチャンクを与えるということも可能です。 つまり、ヒットした文書のうち上位10件を与えるというような仕組みです。こちらもたくさん与えたくなります。しかしチャンクサイズと同様にコンテキストサイズには限りがあるためいくつチャンクを与えるのかは試行錯誤が必要となります。 今回は512を chunk_size として設定しました。これは、採用している Multilingual-E5-large モデルのおすすめのシーケンス長が512に 設定されているためです。 # LLMのセットアップ model_path = f "models/ELYZA-japanese-Llama-2-7b-fast-instruct-gguf/ELYZA-japanese-Llama-2-7b-fast-instruct-q8_0.gguf" llm = LlamaCPP( model_path=model_path, temperature= 0.1 , model_kwargs={ "n_ctx" : 4096 , "n_gpu_layers" : 32 }, ) llm_predictor = LLMPredictor(llm=llm) # 埋め込みモデルの初期化 # 埋め込みモデルの計算を実行するデバイスを指定。今回は埋め込みモデルをCPUで実施しないとVRAMに収まりきらないので、CPUで実施する。 # "cpu","cuda","mps"から指定する。 EMBEDDING_DEVICE = "cpu" # 実行するモデルの指定とキャッシュフォルダの指定 embed_model_name = ( "intfloat/multilingual-e5-large" ,) cache_folder = "./sentence_transformers" # 埋め込みモデルの作成 embed_model = HuggingFaceEmbedding( model_name= "intfloat/multilingual-e5-large" , cache_folder=cache_folder, device=EMBEDDING_DEVICE, ) # ServiceContextのセットアップ ## debug用 Callback Managerのセットアップ llama_debug = LlamaDebugHandler(print_trace_on_end= True ) callback_manager = CallbackManager([llama_debug]) service_context = ServiceContext.from_defaults( llm_predictor=llm_predictor, embed_model=embed_model, chunk_size= 500 , chunk_overlap= 20 , callback_manager=callback_manager, ) # インデックスの生成 index = VectorStoreIndex.from_documents( documents, service_context=service_context, ) ここまでで、RAGを実行するための準備は出来ました。 RAGで利用するプロンプトを設定します。 このプロンプトの中に {context_str} と書いてある部分が実行の際にはコンテキスト情報に 置き換えられます。 {query_srt} が質問内容で置き換えられます。 # 質問 temp = """ [INST] <<SYS>> 以下の「コンテキスト情報」を元に「質問」に回答してください。 なお、コンテキスト情報に無い情報は回答に含めないでください。 また、コンテキスト情報から回答が導けない場合は「分かりません」と回答してください。 <</SYS>> # コンテキスト情報 --------------------- {context_str} --------------------- # 質問 {query_str} [/INST] """ いよいよRAGを実行します。 query_engine を設定している箇所で、 similarity_top_k という引数があります。 これは幾つコンテキスト情報を与えるかという設定になります。ここでは5つのコンテキスト情報を与える設定にしてあります。 query_engine = index.as_query_engine( similarity_top_k= 5 , text_qa_template=PromptTemplate(temp) ) while True : req_msg = input ( " \n ## Question: " ) if req_msg == "" : continue res_msg = query_engine.query(req_msg) res_msg.source_nodes[ 0 ].text event_pairs = llama_debug.get_llm_inputs_outputs() print ( " \n ## Answer: \n " , str (res_msg).strip()) これで、RAGを用いて質疑応答ができるチャットが完成しました。 とても簡単に実装できましたね。 実行例 試しに実行してみましょう。今回は、 太宰治 の 走れメロス を 青空文庫 からダウンロードしテキストファイルにして読ませて実行しました。 まずは1つ質問をしてみます。 ## Question: メロスの友人の名前は? ... (デバッグ用の情報が出力されます) ... ## Answer: セリヌンティウス 正解ですね。 さらにもう1つ質問をしてみます。 ## Question: メロス メロスはどんな性格でしたか? ... (デバッグ用の情報が出力されます) ... ## Answer: メロスは内気な性格だと読み取れます。 - メロスは21歳の青年で、村の牧人であった。 - メロスには父も、母も無い。女房も無い。十六の、内気な妹と二人暮しだ。 - メロスは、村の或る律気な一牧人を、近々、花婿はなむことして迎える事になっていた。結婚式も間近かなのである。 - メロスは、それゆえ、花嫁の衣裳やら祝宴の御馳走やらを買いに、はるばる市にやって来たのだ。 これらの事から、内気で控えめな性格だと読み取れます。 ちゃんとコンテキストを使って回答ができてそうですね。 改善出来そうなポイント 今回の実装したシステムでは、1つの質問の回答を得るまでに10-30秒程度の時間が掛かってしまいました。常用するにはちょっと難しいですね。 与えるコンテキスト情報を減らしたりすることで短くすることが出来たりするでしょうが そうすると適切な情報を与えることができず、誤った回答を返してしまう可能性が高くなってしまいます。 回答を行うために必要でかつ十分な情報のみを与えることが出来れば、無駄なく高速に回答を得られるようになるかもしれません。この辺りにチューニングの余地があると考えています。 ソフトウェアだけでなくハードウェアも変更することで改善することが期待できます。 もっと良い性能の GPU 、例えばRTX 4090を搭載しているような計算機で実行したりすることでより高速に回答を得られるようになるかと思います。 また、いかに適切なコンテキストを見つけられるかに回答内容の正確さは依存しています。 与える文書や検索の仕組みを工夫できればもっと良いRAGが構築できるようになるはずです。 まとめ 今回はLlamaIndexを利用してローカル環境でRAGを構築してみました。悩むことなく手軽にRAGが実装できるのは素晴しいですね。一方で実際に実装してみて学ぶことも多くあり便利なRAGを構築するのは難しいということも良くわかりました。 手元にある文書を読み込ませてチャットしてみるだけでもなかなか楽しいと思います。 みなさんも是非実装してみてください。 私たちは一緒に働いてくれる仲間を募集しています! キャリア採用 フルサイクルエンジニア AIサービス開発エンジニア 新卒採用 執筆: @yamashita.tsuyoshi 、レビュー: @wakamoto.ryosuke ( Shodo で執筆されました )
アバター
こんにちは。コーポレート本部サイバーセキュリティ推進部の大西です。 昨年の話になりますが、2023年12月23日に開催された SECCON 2023 電脳会議 で CTF for GIRLS が主催するハンズオンとPetit CTFに参加してきましたので、CTFのWriteUpを書きます! ↓電脳会議およびCTF for GIRLSイベントに参加した際にいただいたパンフレット、ステッカー、ヘ アゴ ム、SECCON公式バッジ ステッカーもヘ アゴ ムも素敵・・・。 のちにこのクリスマスステッカーにCTFの重大なキーワードが隠されていることを知るのでした・・・。 CTFとはCapture The Flagの略で、情報セキュリティに関する様々な技術を競うコンテストです。セキュリティの専門知識や技術を使って隠されたFlagを獲得するとポイントをゲットできます。 CTF for GIRLSは世界的に有名なセキュリティ研究家の中島明日香さんが設立された、情報セキュリティ技術に興味がある女性を対象に、気軽に技術的な質問や何気ない悩みを話し合うことができるコミュニティです。今回、私と同じテーブルには、社会人3年目2人と学生4人、部屋全体では70 ~ 80人ほどが参加していました。23日のイベントでは、午前中にReversing、Crypto、Web、Forensicsのワークショップ、午後からPetit CTFが行われました。 今回、Petit CTFで70人中13位、Web問題上級でFirst Blood賞をいただきました! 出題された問題についてWriteUp(CTF参加後に問題の解き方などを書いたもの)を書いていこうと思います。 Reversing banner4you(初級) Misc この模様はなーんだ?(初級) christmas card(中級) 3keywords(上級) Crypto Do not use the default password!(初級) Forensics Snow covered(初級) Web トナカイ専用(初級) SecretKey(上級) 参加した感想 Reversing banner4you(初級) 拡張子のない謎のバイナリファイルが与えられて、答えとなるキーワードを探すCTFでは定番のタイプの問題です。 ダウンロードしてきた添付ファイルをstringsコマンドの引数に渡してあげればフラグゲットです。 Misc この模様はなーんだ?(初級) 添付ファイルを開いてみると、 このような模様が出てきましたが何の模様か分からず、とりあえず Google レンズに読み込ませると、MaxiCodeという規格の 2次元コード らしいことが分かりました。 こちら のリーダーに読み込ませることでフラグがゲットできました! ちなみにMaxiCodeとは、1987年に宅配業者の UPS 社( アメリ カ)によって、物流の仕分けや追跡のために開発されたマトリクス型の 二次元コード だそうです。読み取り速度が非常に速い一方で、他の 二次元コード と比べて収納できるデータ量はあまり多くないという特徴があるそうです。 参照: https://aimjal.co.jp/gijutu/2jigen/maxicode/maxicode.html christmas card(中級) 添付されていた画像を開くと、 ヒントを見ると StegOnline を使えとあるので、この画像をStegOnlineにアップロードし「Browse Bit Planes」ボタンを押すと、 フラグゲットです。 ちなみに、StegOnlineの「Browse Bit Planes」ボタンで何をしているかChatGPTに聞くと、 画像の視覚的な外観に最小限の影響しか与えない最も重要でないビットプレーンが情報を隠すためによく使用されるため、これらを閲覧することで隠されたメッセージやデータを明らかにできます。 だそうです。8ビットの画像には、最も重要でないビット(LSB)から最も重要なビット(MSB)まで、8つのビットプレーンがあるそうです。「Browse Bit Planes」機能を使用すると、アップロードした画像の各ビットプレーンを検査し、 ステガノグラフィ ーで隠された情報を示す可能性のある異常やパターンを探すことができるらしいです。 3keywords(上級) 個人的にこの問題がいちばん苦労しました・・・笑 解き方は分かるのにしっくりくる解答が出てこない! 解き方としてはこうです。イベントが始まる前に渡されたクリスマスステッカーは、実は3種類ありました。違う種類のステッカーを持つ人を探して、ステッカー内にある3つのキーワードを探し、そこからある場所を導き出す・・・。 3つのキーワードはすぐ分かりました。ステッカーの写真を撮っていなかったのでX( Twitter )上の写真を拝借・・・。 「10th anniversary」と書かれた文字の下に、何やらモールス信号みたいなものと、16進数のようなものと、数字の羅列があります。 モールス信号を解読すると「beads」、16進数をASCII変換すると「sect」、数字をアルファベットに置き換える(1 -> a、2 -> b、3 -> c ・・・)と「encourage」になります。 3つのキーワードは分かりましたが、ここからが長かった。 3つのキーワードをアルファベット(辞書)順に並べたとき、導き出される場所があるらしいのですが、検索しても検索してもここだ!という場所が出てこないのです。 「beads」というキーワードがあるので、ビーズを使ったお店などが出てきて、ここじゃないよなぁと思いながらフラグを入力してもやっぱり弾かれ・・・ 同じテーブルの方が、「最初にもらったヘ アゴ ムのビーズが関係あるかも!」と言ってくれて、その方面も考えましたがいい感じのフラグは見つけられず。 仕方なくヒントを見ました。 「3つのキーワードで特定の場所を示す方法はないでしょうか」 ・・・!!あれやん!と思わず声を出して言ってしまいました笑 そう、3つのキーワードで特定の場所を示す方法といえば、 what3words ですね。 実際に使ったことはなかったのですが、テレビか何かで見て知っていました。 3つのキーワードをwhat3wordsに入力して、無事「ctf4g{santaclausvillage}」(サンタクロース村)というフラグをゲットできました。 時間はかかりましたが、他の方と協力しながら問題を解けてとても楽しかったです!! Crypto Do not use the default password!(初級) 「keystore」で検索すると、 keytoolコマンド というものがありました。keytoolコマンドを使用して、 自己署名証明書 を生成し、キーストアに証明書をインストールして管理できるそうです。 keytool -list -v -keystore (keystoreファイルの場所) コマンドで、 Java のKeyToolユーティリティを使用して、キーストアの中のエントリ( 秘密鍵 や証明書など)をリストできるそうです。試してみると、パスワードを聞かれました。問題文が「Do not use the default password!」なので、keytoolのデフォルトパスワードを検索すると「changeit」とあったのでそれを打ち込みます。所有者と発行者の部分にフラグがありました。 Forensics Snow covered(初級) 画像が重なり合ったPDFファイルが与えられました。邪魔な画像を消してあげれば、下にある答えが見られるはずです。 ワークショップで教わった LibreOffice や foremostコマンド などを使うと、PDF上の画像も扱うことができそうです。 私は、 LibreOffice を使って邪魔になっているフラグの上の画像を動かしてフラグをゲットしました。 Web トナカイ専用(初級) トナカイ専用サイトにアクセスするとこんな画面が出てきます。 トナカイ 専用ブラウザ でしか閲覧できないということなので、UserAgentに「ReindeerBrowser」と入力してリク エス トすればフラグゲットです。 UserAgentの値を編集してリク エス トするには、PostmanやBurp Suiteなど何でも使えます。 SecretKey(上級) 問題文中のURLにアクセスすると、5つのポストが見られました。 2023/12/23のポストにアクセスすると、 「シークレットセール」の話が出ているので、このポストが怪しいです。 問題文にIDとパスワードがあり、どこからかログインできる匂いがするのでそれを探します。 すると、他のポストを見るとURLが連番になっていることに気づきます。 2023/12/21のポスト↓ 2023/12/22のポスト↓ なので、セール情報の載ったポストは10458.htmlにありそうなのでアクセスしてみます。 当たり!問題文中のID、パスワードでログインすると、 セールのエントリーは締め切ったというメッセージが出てきました。 「logout」ボタンをクリックする以外にできることはなさそうなので、開発者ツールを開いて中を見てみます。 Cookie にJWTのtokenが入っているので、一応こちらの jwtのデコーダー で中身を見てみます。 PAYLOAD内のroleが「user」になっているので、ここを「admin」にすると管理者権限でアクセスできるかもしれません。 また、algがHS256(HMAC using SHA-256 hash)なのでsecretが署名に使われていそうです。添付ファイル内の文字列がsecretの候補のようです。ひとつずつ試して、「reindeer」にしてアクセスするとフラグをゲットできました! そして、この問題でFirstBlood賞をいただきました! 参加した感想 業務では 脆弱性 検査を担当しているのでWeb問題はぜひ全問解きたかったですが、Web問上級でFirstBlood賞をいただけて良かったです! またCTF for GIRLSのイベントがあれば参加させていただきたいです。 今回のイベントを通じて、セキュリティ業務に関わる他社の方のお話を聞けたのもとても良かったです。 自分の周りでForensicsをゴリゴリやっている人はいなかったのですが、Forensicsをずっとやってきた方が同じ島にいらっしゃって、いろいろお話を聞けました。その方のWriteUpも掲載させていただきます(今回のCTFで1位受賞!✨)。 https://kcfromsmallpotatoes.hatenablog.com/entry/2023/12/29/233545 最後にCTF for GIRLSの中島さんと記念写真をパチリ✨ お読みいただきありがとうございました! 執筆: @onishi.mayu 、レビュー: 石沢 健人 (@kent) ( Shodo で執筆されました )
アバター
みなさんこんにちは、 電通 総研コーポレート本部システム推進部の佐藤太一です。 この記事では、 Maven を使って Java EE 向けに作られた既存のアプリケーションのコードに一切手を加えることなくJakara EE対応のアプリケーションに変換する方法を説明します。 はじめに レガシーアプリケーションの実装 モダンアプリケーションの実装 マイグレーションプロジェクトの実装 UberJarの中身を確認する マイグレーションプロジェクトの参照 まとめ はじめに 2017年に Java EE が Jakarta EEになってから7年が経つわけですが、皆さんの手元にあるシステムは Jakarta EEに対応できていますか? Java EE を選択するようなアプリケーションの保守運用では、 名前空間 だけの変更とは言ってもリスクを取りたくないと考えるようなシステムは多いでしょう。もしかしたら、 Java EE どころか J2EE のまま動かしているかもしれませんね。 ここで紹介する手法は、 maven -shade-pluginのrelocationを使ってjarファイルの中に格納されたclassが参照するパッケージ名を置換するというやり方です。 この記事のサンプルコードを動かすにあたって、 Java 21と Maven 3.5以上をあらかじめインストールしておいてください。 レガシーアプリケーションの実装 まずは、 javax.servlet を使って簡単なアプリケーションを実装してみましょう。 作業用の ディレクト リに legacy という名前で新しい ディレクト リを作成します。その後、以下の内容でpom. xml を保存しましょう。 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>legacy</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.3</version> <type>jar</type> <scope>provided</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.mvnsearch</groupId> <artifactId>toolchains-maven-plugin</artifactId> <version>4.5.0</version> <executions> <execution> <goals> <goal>toolchain</goal> </goals> </execution> </executions> <configuration> <toolchains> <jdk> <version>1.8</version> </jdk> </toolchains> </configuration> </plugin> </plugins> </build> </project> 使っている Servlet が2.3と大分古いですが、これくらい古くてもきちんと動く Java は本当に素晴らしいですね。 org.mvnsearch:toolchains-maven-plugin は、指定した JDK を自動的にダウンロードして、 コンパイル や実行時に使えるようにしてくれる プラグイン です。ここでは、 Java 1.8を指定しています。 正直言って、事前に Java を二種類入れておいてくださいと言われたら、僕なら記事を読むのを諦めますね。 Maven でプロジェクトを定義したので、さらに /legacy/src/main/java/com/example/legacy/ と ディレクト リを作成します。作成した ディレクト リの中に MyServlet.java というファイル名で以下の内容を保存します。 package com.example.legacy; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.*; public class MyServlet extends HttpServlet { private static final long serialVersionUID = 1L; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.getWriter().append("Hello World!").flush(); } } 15年ぶりくらいにHttpServletを継承するクラスを書いたように思います。 importしている 名前空間 が javax.servlet であることに注目してください。 ファイルを保存したら以下のコマンドを実行して、ローカル リポジトリ にこのアプリケーションをインストールしておきます。 mvn install モダンアプリケーションの実装 次は、最新のアプリケーションを実装します。 作業用の ディレクト リに、 modern という名前で新しい ディレクト リを作成します。その後、以下の内容でpom. xml を保存しましょう。 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>modern</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.2.1</version> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>21</java.version> <start-class>com.example.modern.Main</start-class> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.example</groupId> <artifactId>legacy</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> 最新のSpring Boot Webを使ったアプリケーションのプロジェクト定義です。 先ほどローカルにインストールした com.example:legacy:1.0-SNAPSHOT を依存ライブラリに追加してあります。 Maven でプロジェクトを定義したので、さらに /modern/src/main/java/com/example/modern/ と ディレクト リを作成します。作成した ディレクト リの中に Main.java というファイル名で以下の内容を保存します。 package com.example.modern; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.servlet.ServletContextInitializer; import org.springframework.context.annotation.Bean; import com.example.legacy.MyServlet; import jakarta.servlet.ServletContext; import jakarta.servlet.ServletException; @SpringBootApplication public class Main { @Bean public ServletContextInitializer myServlets() { return new ServletContextInitializer() { @Override public void onStartup(ServletContext servletContext) throws ServletException { servletContext.addServlet("myServlet", MyServlet.class).addMapping("/"); } }; } public static void main(String[] args) { SpringApplication.run(Main.class, args); } } Spring BootのServletContextInitializerを使って Servlet をデプロイしています。 ここで参照している 名前空間 は jakarta.servlet ですね。 つまり、以下のコマンドを使ってアプリケーションを コンパイル しようとするとエラーになります。 mvn package 出力されるエラーは、 名前空間 がずれているため以下のようなものになるでしょう。 [ERROR] /C:/work/java/legacy-replacement/modern/src/main/java/com/example/modern/Main.java:[22,47] javax.servlet.http.HttpServletにアクセスできません javax.servlet.http.HttpServletのクラス・ファイルが見つかりません 今回例示しているレガシーアプリケーションは、ファイル1つだけなのでファイルを直接変更してしまっても大した手間ではありません。しかし、2024年現在も生き残っているレガシーアプリケーションは、 名前空間 の一括置換ですらはばかられるものが多いでしょう。 無用なリスクは取りたくないと考える人がいても非難しがたいものです。 マイグレーション プロジェクトの実装 ここからは、ビルド済みのレガシーアプリケーションを最新の環境に対応できるようにする マイグレーション プロジェクトを定義します。 作業用の ディレクト リに、 legacy-uber という名前で新しい ディレクト リを作成します。その後、以下の内容でpom. xml を保存しましょう。 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>legacy-uber</artifactId> <version>1.0-SNAPSHOT</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>com.example</groupId> <!-- 1. --> <artifactId>legacy</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <!-- 2. --> <version>3.5.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <useBaseVersion>true</useBaseVersion> <createDependencyReducedPom>false</createDependencyReducedPom> <artifactSet> <excludes> <!-- 3. --> <exclude>junit:junit</exclude> <exclude>commons-logging:commons-logging</exclude> </excludes> </artifactSet> <transformers> <!-- 4. --> <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" /> </transformers> <relocations> <!-- 5. --> <relocation> <pattern>javax.servlet</pattern> <shadedPattern>jakarta.servlet</shadedPattern> </relocation> <relocation> <pattern>javax.transaction</pattern> <shadedPattern>jakarta.transaction</shadedPattern> </relocation> </relocations> <filters> <!-- 6. --> <filter> <artifact>*:*</artifact> <excludes> <exclude>META-INF/*.MF</exclude> <exclude>META-INF/*.SF</exclude> <exclude>META-INF/*.DSA</exclude> <exclude>META-INF/*.RSA</exclude> <exclude>META-INF/*.txt</exclude> </excludes> </filter> </filters> </configuration> </execution> </executions> </plugin> </plugins> </build> </project> このプロジェクトについて説明していきましょう。pom. xml の中にコメントした数字に沿って説明します。 依存ライブラリとして、 com.example:legacy:1.0-SNAPSHOT を指定しています。今回はありませんが、ここから推移的に依存するライブラリも多数あることでしょう。例えば、commons-fileupload などは色んな場所で使われていますが、 Jakarta EEに対応したバージョンはリリースされていません。 maven-shade-plugin を使ったパッケージング実施しています。これを使うと依存ライブラリも含めて全て単一のjarファイルにまとめるUberJarを作成できます。 com.example:legacy:1.0-SNAPSHOT が依存するライブラリは基本的に全てUbeJarの中に取込むのですが、取込んでしまう必要のないものや、取込んでしまうと不都合のあるものを除外しています。特に、 commons-loggingは単一のクラスパス上に複数バージョン存在していると正しく動作しない可能性が高いので除外しています。 近年の Java では META-INF/services 以下に所定のルールでファイルを配置する事で拡張できる フレームワーク が非常に多いので、それらのファイルが誤って失われてしまわないように、ServicesResourceTransformerを指定しています。他にも トランスフォーマー は色々定義されているので一度見てみると良いでしょう。 Resource Transformers を参照してください。 このrelocationsタグで定義されている内容が今回の主題です。一つ目のrelocationタグでは javax.servlet を jakarta.servlet に置換しています。二つ目のタグでは、 javax.transaction を jakarta.transaction に置換しています。これは単なる文字列置換ではないのでサブパッケージについては、それぞれ指定しましょう。 これは、おまけです。META-INF ディレクト リの中によく格納されているものを取り除いています。MANIFEST.MFについては、取り除くと問題のある場合がある一方で、取り除かずに内容をマージしないといけない場合もありますので注意してください。 ファイルを保存したら以下のコマンドを実行して、ローカル リポジトリ にこのUberJarをインストールしておきます。 mvn install UberJarの中身を確認する UberJarの中身を念のため確認しておきましょう。 ビルドが正常に終了しているなら、 /legacy-uber/target ディレクト リの中に二つのjarファイルが格納されているはずです。 プレフィックス として、 original- が付いているのはshadingする前のjarファイルです。ファイルサイズが少しだけ小さいですね。 shadingされている方のjarファイルを展開して中身を確認しましょう。ここでは、 legacy-uber-1.0-SNAPSHOT.jar です。jarファイルはZIP圧縮されているファイルなので中からMainServlet.classを取り出します。 バイナリエディタ で開くと javax.servlet が jakarta.servlet へ置換されていることが分かりますね。 マイグレーション プロジェクトの参照 レガシーアプリケーションを マイグレーション したUberJarをローカルにインストールしたので、最新のアプリケーションからは、そのライブラリを参照するように依存性を変更します。 その結果、以下のようになります。 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>modern</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.2.1</version> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>21</java.version> <start-class>com.example.modern.Main</start-class> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.example</groupId> <artifactId>legacy-uber</artifactId> <version>1.0-SNAPSHOT</version> <exclusions> <exclusion> <groupId>*</groupId> <artifactId>*</artifactId> </exclusion> </exclusions> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> 変更点は。 com.example:legacy:1.0-SNAPSHOT に対する依存性を com.example:legacy-uber:1.0-SNAPSHOT に対する依存性に変更している部分です。 legacy- uber は、依存ライブラリも含めて単一のjarファイルの中に格納されていますので、推移的な依存性は必要ありません。よって、exclusionsタグを使って推移的な依存性を全て無視するようにしてあります。 では、以下のコマンドを使って再度アプリケーションをビルドしてみましょう。 mvn clean package 今度はエラー出力なくビルドが完了します。 動作を確認したければ、以下のコマンドを実行して Tomcat が起動したら、ブラウザで http://localhost:8080 にアクセスします。 mvn spring-boot:run Servlet で レンダリング した Hello World! が表示されますね。 まとめ この記事では、古いアプリケーションの ソースコード やビルド済みバイナリには手を加えることなく、新しい環境で既存資産を流用する方法を説明しました。 長期間メンテナンスされているアプリケーションは価値ある資産です。とはいえ、古い事そのものが原因で新しい取り組みを行えないなら、それは技術的な解決があるという事を示しました。 この記事を読んだ皆さんが、希望を持ってレガシーアプリケーションの現代化に取り組めることを祈って記事の結びとします。 執筆: @sato.taichi 、レビュー: @yamashita.tsuyoshi ( Shodo で執筆されました )
アバター
こんにちは! 電通 総研新卒入社7年目の植田です。 現在はHCM事業部に所属しており、自社製品である統合人事給与システムPOSITIVEの導入を担当しています。 この記事では私の仕事内容や職場の雰囲気についてお話しします! 自己紹介 1. 年次 新卒で2017年に 電通 総研に入社し、2023年4月で7年目になりました。 2. 電通 総研入社の決め手 東京で働きたかったのとなにか技術を身につけたいという思いで、当時は SIer に絞って就活をしていたのですが、面接でお話する方々の印象がとてもよく、最終的には人が決め手となりました。 ( 電通 総研あるあるですね) 入社してからもこの印象は特に変わっておらず、個性があって感じのよい人が多いなと感じます。 3. 大学の専攻 大学は国際文化学部という学部で完全な文系学部で犬の研究をしていました。 なので、当然プログラミング経験もほぼありませんでした。 (教養科目でちょっとやったかなレベル。。) 4. 電通 総研内の経歴 最初からHCM事業部配属でしたが、部署は導入ではなく、製品開発の部署でした。 もともと導入がやりたかったので、2年ちょっと経って導入の部署に異動してきました。 これは、HCM事業部独自の教育体制によるものなのですが、新卒でHCM事業部に配属されると、基本的には全員製品開発の部署に配属されます。 製品開発の部署で1-2年製品や開発について働きながら学んだあと、導入等の他部署に異動するか製品開発の部署に残ることになります。 仕事内容等 1. なんの仕事をしているの? HCM事業部はPOSITIVEの開発、販売、導入を行っている部署で、私はPOSITIVEの導入を行っています。 2. 導入って何するの? 導入プロジェクトでは、POSITIVEをお客様にご利用いただくためのシステム導入作業として、要件定義や実装(パラメータ設定・アドオン)、各種テスト等を実施します。 要件定義のフェーズではお客様から業務内容を ヒアリ ングし、必要な機能や設定内容の検討、また、標準機能ではカバーできない要件に対してアドオン機能の検討を行います。 実装フェーズでは、要件定義フェーズで決定した内容に基づいて実際にPOSITIVEを設定します。また、アドオン機能の開発を行います。 アドオンを除き、POSITIVEは導入時にコーディングの必要がなく、画面操作によってパラメータ設定を行うことができます。 テストフェーズでは、設定内容を確認するためのテストケースを作成し、テストを実施します。 3. POSITIVEってなに? 電通 総研が開発しているパッケージ製品で人事・給与・就業を一括で管理できるシステムです。 POSITIVE紹介サイト( 電通 総研)は、 こちら 4. 周りの人たち 私が所属する部は12名いて、20代から50代まで、年齢も幅広く、新卒or中途も半々くらいです。 5. 1日の仕事の流れ プロジェクトのフェーズによって打合せが多かったり少なかったり変化がありますが、だいたいこんな感じです。 6. 在宅/出社 私は基本在宅勤務ですが、2週間に1度部会があり、その日だけは出社しています。 その日はそのまま飲みに行くことも多いです! 7. やりがい 自分が担当しているお客様の導入プロジェクトが無事稼働したときです。 年次が上がるにつれてプロジェクト内での立場もより上になり責任も重く感じますが、その分うまくいったときはとてもやりがいを感じます。 また、導入に来た当初はメンバーやリーダーの役割でしたが、今はPMの役割を任せてもらえているので視点も上がり、自分のやり方で進めることができるので楽しいなと感じています。 8. 電通 総研に入って良かったことは?悪かったことは? 良かったことは周りの人にも恵まれていますし、やりがいを感じられる仕事もあり、今とても楽しく仕事をできていることです。 あとは、同期に出会えたことです。同期は宝物です。 悪かったことは特にないのですが、大変だなと思うことは、POSITIVEという製品はいろいろな機能を含んだシステムなので、例えば人事だけでも製品に詳しくなるのに時間がかかることでしょうか。 ( 電通 総研というより製品導入という点での大変さですね) さいごに 電通 総研は新卒・中途関わらず一緒に働く仲間を募集しています。 私の所属する部は、中途社員と新卒社員が半々で年齢も幅広いです。 もしこの記事を読んで 電通 総研に少しでも興味を持っていただけたら、ぜひ 電通 総研の採用ページを見てみてください! 一緒に働きましょう! 私たちは一緒に働いてくれる仲間を募集しています! 新卒採用ページ 執筆: @ueda.saya 、レビュー: @wakamoto.ryosuke ( Shodo で執筆されました )
アバター
はじめに こんにちは。X(クロス) イノベーション 本部 エンタープライズ プラットフォームの宇佐美です。 普段は「aiuola(アイウォーラ)」という エンタープライズ アプリケーションプラットフォームの デベロッパ ーとして、既存機能のエンハンスや新規機能の開発等を行っています。 2022年7月に入社し、そこから約1年半が経過しました。 今回は 電通 総研に入社した経緯と現在の働き方、チーム内で取り組んでいる勉強会についてご紹介します。 転職を考えた経緯 前職は SIer の中小企業で2018年に新卒で入社し、主に製造業や 保険業 、官公庁系のWebアプリケーションの受託開発が中心でした。 前職での業務もやりがいはありましたが、作業が ルーチンワーク 化してきたことやより自分の技術力を高められる環境で仕事がしたいという思いを抱くようになりました。 また、受託開発よりもプロダクトの自社開発に興味が湧いたため、そうした環境での開発ができる環境への転職を決意しました。 電通 総研を選んだ理由 何社か面接を受けさせていただきましたが、 電通 総研に入社したいと考えた理由は以下になります。 自分が転職を決意した理由を一番親身になって聞いていただけたから。 開発するシステムや、使用する技術に魅力を感じたから。 後述する勉強会を定期的に開催している等、技術者同士のコミュニケーションが盛んで技術力を高められると感じたから。 入社から1年半経過して ご縁あって 電通 総研に入社し、そこから1年半経過しました。 結論から言えば、開発者として充実した日々を過ごすことが出来ています。 ここでは、入社前に感じていた不安と、実際どうだったかを書いていこうと思います。 技術力のギャップ 入社前は自分がこれまで培ってきた技術が 電通 総研で通用するか、もしかしたら付いていけないのではないかといった不安を感じていました。 しかし、私が所属するチームでは 毎日の朝会における困りごとの共有 必要に応じて、チームメンバーとの相談(Slackのチャットや通話機能を利用) システムの仕様や技術に関する疑問を気軽に投げかけられるチャンネルがある といった、不明点をすぐに相談・共有できる環境であったため、上記の不安はすぐに解消されました。 ワークライフバランス 前職では案件によって残業時間が多くなり、夜遅くまで作業することもしばしばありました。 電通 総研では標準の労働時間が7時間と一般的な企業の労働時間よりも短いこと、効率的な働き方ができる環境であることなどから、プライベートの時間を確保しやすくなりました。 もちろん残業時間は0ではなく、スプリントのリリース直前のタイミング等で必要に応じて残業することはあります。 それでも前職より残業する時間はかなり減ったと思います。 勉強会について 上述の通り、 電通 総研に入社して以降は開発者として充実した日々を送ることができています。 ここでは 電通 総研に入社して良かったことの一つでもある、勉強会についてご紹介します。 勉強会の内容 基本的には技術書の輪読を行っています。 輪読は隔週で実施し、基本的には章ごとに担当者を指定します。 担当者は事前に該当の章を読んで概要を資料にまとめて発表し、それ以外の参加メンバーは意見や疑問点を話し合う、という形式です。 技術者として、自分の領域である技術分野や興味のある分野に関する書籍を読むことはよくあることかと思います。 そうした中で、読んでいる書籍に疑問が生じた場合、疑問によっては一人で調べて解決することが難しいこともありますよね。 輪読は各々が持つ意見や疑問点を元にディスカッションすることで、書籍に対する理解を深めることができます。 発表資料の作成を通してアウトプットすることで、理解した内容を自分の中に落とし込み、学んだことを積極的に業務に活用していくこともメリットの一つです。 現在は輪読以外での形式も模索しています。 これまで輪読した書籍 参考までに、私が入社して以降に輪読した書籍をご紹介します。 良いコード/悪いコードで学ぶ設計入門 ―保守しやすい 成長し続けるコードの書き方 良いコード/悪いコードで学ぶ設計入門 ―保守しやすい 成長し続けるコードの書き方 作者: 仙塲 大也 技術評論社 Amazon ITエンジニア本大賞2023にも選ばれており、変更に強く保守がしやすいコードを書くための実践的なテクニックが アンチパターン と共に紹介されています。 扱われているテーマも面白く、また内容も分かりやすい書籍です。徐々にプログラミングにも慣れてきて、コードの質を高めたいと考えている若手エンジニアの方々にもおすすめです。 セキュア・ バイ・デザイン 安全なソフトウェア設計 セキュア・バイ・デザイン 安全なソフトウェア設計 作者: Dan Bergh Johnsson , Daniel Deogun , Daniel Sawano マイナビ出版 Amazon ドメイン 駆動設計や デザインパターン などを軸に、表面的なセキュリティ対策ではなく設計や実装から強固なアプリケーションを開発することをテーマにした技術書です。 内容は上述した「良いコード/悪いコードで学ぶ設計入門」の発展といった感じで、 ドメイン 駆動設計の入門にもちょうど良いと思います。 最後に 今回は、 電通 総研に入社した経緯やチーム内で取り組む勉強会についてご紹介いたしました。 転職を考えている方でもしこの記事をきっかけに 電通 総研にご興味を持っていただけましたら、下記のリンクから是非応募してみてください。 私たちは一緒に働いてくれる仲間を募集しています! 次世代会計プロダクト開発ITアーキテクト(Ci*Xシリーズ) 執筆: @usami.tsubasa 、レビュー: @yamashita.tsuyoshi ( Shodo で執筆されました )
アバター
はじめに こんにちは! フレックスタイム制 度制度を存分に活用して、普段色々な時間に業務をしているX イノベーション 本部・ クラウド イノベーション センターの石井大樹です。 今回、社内プロジェクトにて、負荷テストをテスト環境の構築からテストの実施までを担当しました。 このプロジェクトで開発した負荷テストの実行環境の評判がよかったことから、私の経験が皆さんの負荷テストに関する課題を解決する手助けになるのではないかと考え、この記事を書くことにしました。 前提 目的 読者に、 クラウド 上のコンテナ オーケストレーション サービスで負荷テストを実行するメリットと重要性を理解してもらう この記事の対象とする読者の方 負荷テストのテスト実行計画中の方 現状の負荷テスト実行環境を改善したい方 クラウド サービスでの負荷テストに関心がある方 前提知識 クラウド に関する基礎知識 コンテナ化の概念 負荷テストの概念 注意 シナリオの作成の仕方・ウォームアップなど、負荷テスト自体の内容に関する知識を求める方は、期待した情報を得られない可能性があります。 この記事は、テストの実行環境に焦点をおいており、負荷テストの内容自体には焦点をおいていません。 テスト実行環境とは 本稿における負荷テスト実行環境とは以下の要素で構成されているものとします。 テストを実行するインフラスト ラク チャ 負荷テストツール テスト実施者がテストの実行から結果取得までに扱う必要のある全てのツール 従来の課題 このプロジェクトではいままで、EC2 インスタンス を1台立て、その インスタンス から手動でテストの実行からテスト結果の取得までを実施していました。 そのため、以下のような課題がありました。 負荷の大きさがそのEC2 インスタンス の1台の性能に依存し、一定以上の負荷をかけることができない。 テストの前処理・後処理など、一部の処理を直列で行う必要があり、その処理に時間がかかってしまう。 テスト実行からテスト結果の取得までの一連の流れが手動であり、時間がかかり、手順ミスが生じる恐れがある。 起動時間でEC2 インスタンス は課金されるので、手動で起動・停止の課 金管 理を行う必要がある。 上記のような課題を、これから紹介するテスト実行環境でテストを実施することで解決することができました。 負荷テスト環境の概要 テスト実行インフラ 実際にどのようなインフラでテストを実行したのかを紹介いたします。 以下がこの環境の アーキテクチャ 図です。非常に単純な作りとなっています。 テストは ECS on Fargate 上のコンテナで実行され、それが終了するとコンテナはS3 バケット へテスト結果を出力するようになっています。 ECS on Fargateを利用することで以下のようなメリットを得ることができました。 コンテナ数(タスク数)とコンテナごとのメモリ、CPUなどのリソースを定義することで、負荷が柔軟に指定可能に。 コンテナ数を増やして並列度を上げることで、前処理・後処理などの並列化可能な処理の完了時間を短縮 例えば、テスト前のセットアップでは、実際に Selenium をheadless modeで利用してブラウザ上でログインを行い、セッションの情報を取得するという処理を負荷に応じたユーザー数分実行していました。 そのため、非常に多くの時間がセットアップでかかっていました。しかし、コンテナを複数台用意し並列化することで、多くの時間を節約することに成功しています。 コンテナ数を増やし並列度を上げることによる、掛けられる負荷の上限の大幅な引き上げ テストの実行が完了したら自動的にコンテナ(タスク)が終了するため、手動での課 金管 理が不要に 以上で挙げたメリットは主な物であり、それ以外にも様々なメリットがあるかと思います。 負荷テストツール 負荷テストツールは Gatling を利用しています。Gatlingとは、 OSS の 負荷試験 フレームワーク です。テストシナリオを Java , Scala , Kotlinで記述でき、結果レポートを自動生成してくれます。 この結果レポートはテスト時に収集したメトリクスをもとにして生成されています。用途によっては収集したメトリクスの記録されたファイルのみを出力し、レポートを生成しないこともできます。 この特性を利用し、複数のコンテナでテストを実行する際は、メトリクスファイルのみを各コンテナが出力するようにします。それを1つの ディレクト リに収集し、Gatlingのレポートを生成するコマンドを利用することで、メトリクスを結合して1つのテストのレポートを生成してくれます。 参考 Gatlingレポート例: Reports 負荷テストの実行手順 この章では、ECS on Fargateを使用してテスト実施者がどのようにテストを実行し、結果を取得するかについて紹介します。 ECS on Fargateでのテスト実行と複数コンテナを用いた並列実施はメリットが多くある一方、コンテナ管理と結果処理の必要性が生じました。これに対応するためには、テスト実施者が環境に関する深い知識を持ち、多くの複雑なコマンドを含む手順に従う必要がありました。しかし、全てのテスト実施者が、深い知識にキャッチアップし、手順書に沿って多くの複雑なコマンドを実行するために労力を使うことはあるべき姿ではないと考えていました。テスト実施者はテスト結果に集中し、システム改善にリソースを注ぐべきだと考えているためです。 そこで、 make を利用し、コマンドをテスト実施者の関心の単位(テスト実行・テスト結果取得など)にまとめ上げることにしました。これにより、テスト実施者はテストの結果に集中できたことに加えて、従来の方法に比べて時間を節約し、手順ミスを大幅に減らすことができました。 1. 環境構築 テストを実行するために必要な make コマンドでは、様々なツールを利用しています。そのため、 make コマンドを含め、各ツールを利用するために環境構築が必要です。 どのようなツールを利用したかは、この記事の目的から逸れてしまうため扱いません。 2. テストの実行 テスト種別・負荷を指定してテストを実行します。 このプロジェクトではテストケースごとに、どのようにテストを実行するか(テストタイプ)を指定する必要がありました。 実際に利用したコマンドは以下です。 以下のコマンド例では、 XXX というテストケースを、 load というテストタイプで 2 つのコンテナでそれぞれ 50 ユーザー分の負荷を掛けるよう指定して実行しています。 make run-task TEST_NAME=XXX CONTAINER_COUNT=2 USER_COUNT=50 TEST_TYPE=load この例では、2 * 50で、100ユーザー分の負荷を掛けるように指示していることになります。 詳細は省略しますが、このコマンドでは主に以下のような処理を実行しています。 コンテナの起動によるテストの実行 テスト完了まで待機&テスト完了の検知 コンテナから出力されたテスト結果の後処理 参考としてこのプロジェクトを例にすると、以下の3つのテストタイプを指定して実行する必要がありました。 load :通常の負荷テスト。10分間程、指定した負荷をかけ続ける limit :限界テスト。非常に大きな負荷を短時間で掛ける stress :ストレステスト。指定した負荷を長時間かけ続ける。 3. テスト履歴の取得 指定されたテストケース・テストタイプを指定することで、過去の履歴を取得できます。 このステップで出力された日時の情報を利用して、次のステップのテスト結果の取得を行います。 この例では、 XXX というテストケースの、 load というテストタイプの、テスト結果の履歴を取得しています。 make list-logs TEST_NAME=XXX NUM=10 TEST_TYPE=load 実際の出力例 Here are the latest 4 of 4 entries: 1. 2023-11-21-17-52/ 2. 2023-11-21-17-26/ 3. 2023-11-13-23-23/ 4. 2023-11-13-20-54/ 4. テスト結果の取得 テストケース・テストタイプ・時間を指定することで、テスト結果を取得できます。 この例では、 XXX というテストケースの、 load というテストタイプの、 2023年10/08 12:44 に実行されたテスト結果を取得しようとしています。 make generate-report TEST_NAME=XXX TEST_TIME=2023-10-08-12-44 TEST_TYPE=load 詳細は省略しますが、このコマンドでは主に以下のような処理を実行しています。 全コンテナの出力したテスト結果の結合 結合したテスト結果をレポート化し、ローカルへダウンロード 改善できる点 この環境は従来の実行環境と比較して、コスト・性能・安定性・利便性の向上を達成しました。 しかし、この実行環境を利用してテストを実施していった際に、こうしておけば良かった、改善すればもっと良いものになると考えた点もあります。 以下で、それらのうちの大きな2点を紹介したいと思います。 テスト実行元環境のコンテナ化 現在の環境では、テスト実施者はmakeコマンドを実行するために、 make 自体や様々な依存関係のインストールなどの環境構築が必要であり、一定の時間・労力を要しています。 実際、環境構築手順のドキュメントを用意し、他メンバーに環境構築を行っていただきましたが、ある程度の時間を要してしまっていました。 このような状態を解決するためには、テスト実行元環境(テスト実施者がテストを実行・結果の取得などを行う環境)のコンテナ化をすることで解決できます。 テスト実施者にはDocker Desktopを用意していただき、あとは必要に応じて、ローカルでイメージをビルドすればテストを実行可能な環境を作成できます。 これにより、現在と比較して環境構築のステップの労力を大幅に削減できると考えています。 テスト結果の静的web ホスティング 現在の環境では実行したテストの実行結果を確認するには、ローカルにテスト結果を取り込み、テスト結果レポートの生成が必要です。また、この結果を他者と共有するには結果をzip化してフォルダを共有するか、レポートをGit管理して共有する必要がありました。 これは、あまり労力がかからないように感じますが、1日に何度も結果を共有する必要がある場合は非常に手間になります。 テスト結果の静的web ホスティング を実現することで、結果の共有にはURLを共有するのみで良くなり、結果の確認・共有の手間が大きく削減できます。 まとめ 従来のテスト実行環境と比較しながら、今回のプロジェクトで作成した環境を紹介いたしました。 実施者の手順が複雑にならないようにする対応は必要ですが、ECS on Fargateを用いて負荷テストを行うことは、コスト・効率・柔軟性・正確性のどれをとっても非常に従来の環境に比べて強力です。 今回は、実際にプロジェクトで利用したサービスである AWS のECS on Fargateを例にして紹介いたしました。しかし、これは、どの クラウド ベンダーのコンテナ オーケストレーション サービスを利用しても、同様のメリットを享受できます。 例えば、 Google Cloudの Cloud Run があります。また、 Kubernetes 上でテストを実行するために AWS の Amazon EKS や、 Google Cloudの GKE を使ってもよいでしょう。 これから負荷テストの実施を計画している方、現状の負荷テストを改善したい方々など、悩んでいる方々の参考に少しでもなったら幸いです。 おわりに X(クロス) イノベーション 本部 クラウド イノベーション センターでは、新卒・キャリア採用問わず共に働いてくれる仲間を探しています。 本記事で紹介した私の働き方や、 クラウド を中心とした業務にご興味をお持ちの方は、ぜひ採用ページよりご応募ください。 執筆: @taiki_ishii 、レビュー: @kano.nanami ( Shodo で執筆されました )
アバター
こんにちは!HCM事業部のビジネスパートナー コンサルティング 部の山口です。 現在、私は「ビジネスパートナー支援」という、 皆さんが思い描くITのお仕事とは少し毛色の違うお仕事を担当しています。 この記事では、ISIDに興味を持ってくださっている就活生の皆さんに向けて、 新卒6年目(2018年入社)の私のお仕事とやりがい、そしてISIDの好きなところを紹介したいと思います。 なるべく具体的にお伝えできればと思いますので、 就活生の皆さんがISIDでの様々なお仕事を知っていただく上での参考としていただけたら嬉しいです。 自己紹介 事業部について 製品(統合人事システム”POSITIVE”)の特徴 仕事内容について やりがいを感じる瞬間 ISIDの好きなところ 最後に 自己紹介 ・年次: 2018年に新卒採用でISIDに入社し、今年で6年目になります。 ・大学の専攻: 商学部 で交通経済学を専攻していたTHE文系です。 日本の空港の 効率性分析 をテーマに研究をしていました。 ・職務経歴: 新入社員研修後、HCM事業部(統合人事システム"POSITIVE"を扱う事業部)へ配属されました。 最初の2年は製品開発部でPOSITIVEの開発業務を担当し、 その後異動して今所属しているビジネスパートナー コンサルティング 部にて ビジネスパートナーである代理店様の支援を行っています。 代理店支援のお仕事については後ほど説明します。 事業部について 私の働き方をお話しする前に、私が所属しているHCM事業部について簡単にお伝えしたいと思います。 HCM事業部は統合人事システム”POSITIVE”の開発、販売、導入を行っている事業部です。 ( 尾形さんの記事 にも詳細が書いてあるので是非ご覧ください!) 『ヒトを信じ、日本の「はたらく」を変える』をパーパスとして、TEAM POSITIVE一丸となって進んでいます。 個人的には、100名規模の事業部だからこそのアットホームな雰囲気があり、働きやすい環境だと感じています。 製品(統合人事システム”POSITIVE”)の特徴 ①統合人事システム POSITIVEは統合人事システムと呼ばれていまして、人事情報を軸として、 給与計算や勤怠管理、さらにはタレントマネジメントまで統合的に扱える製品です。 ②パッケージ製品 POSITIVEは標準的な業務に合わせて製品化された、パッケージと呼ばれるシステムです。 お客様の要件に合わせて1から組み立てていくス クラッチ システムとは性質が異なります。 パッケージシステムは、会社ごとの業務に合わせるための設定が必要です。 プロジェクトでは要件定義の段階でお客様の業務や運用方法をお伺いして、 フィットするように各種設定を行います。 ③販売経路 この後のお話にも繋がってくるのですが、 POSITIVEは直接販売と間接販売の両方の経路で販売を行っている点が特徴です。 直接販売はISIDが"POSITIVE"のメーカーとして市場調査から販売導入まで担う方法、 間接販売は販売導入の段階を代理店様にご担当いただく方法です。 HCM事業部はISIDで唯一、間接販売を本格的に推進しています。 仕事内容について 私が所属するビジネスパートナー コンサルティング 部では、 間接販売を担当していただいている代理店様の支援がミッションです。 大切なビジネスパートナーである代理店様に向けて、 主に教育を通して代理店様の販売導入を支援するお仕事をしています。 具体的には代理店様がPOSITIVEを販売・導入する上で必要となる知識を伝える教育を提供しています。 POSITIVEは先ほど製品の特徴①でお伝えしたように人事・給与・勤怠・タレントマネジメントなど 広い分野を対象としている製品です。 そのためPOSITIVEを扱う担当者としては、様々な分野の知識が必要となります。 また、お客様毎に運用に沿った設定を行うため、製品独自のノウハウが必要です。 そこで知っておくべき法律まわりの知識や、POSITIVEの操作・設定方法、 お客様の要件を聞く要件定義から設定とテストまでを模擬体験できる教育コンテンツなどを提供しています。 お仕事としては講座の講師のほか、新規講座の企画と作成も行っています。 やりがいを感じる瞬間 ・前例がない仕事に挑戦している時 誰もまだやったことのない仕事を実現すべく奔走している時にやりがいを感じます。 今年はeラーニングサイトを開設すべく、実現方法の検討から実際のサイト公開まで担当しました。 前例がないと予期せぬタスクに時間がかかってしまったり、 関係者の利害調整が発生したりと多くのハードルがありますが、 実現した先のメリットを信じて、乗り越えた時に達成感を感じます。 ・+αの仕事が出来た時 頼まれていた期日より少し早く提供できた、資料が見やすいと言ってもらえた、 これまで候補になかった新たな選択肢を提案できた、など、 些細なことかもしれませんが、+αの仕事が出来たと実感する瞬間にやりがいを感じます。 年次を経るに連れて求められるレベルは高くなっていきますが、 その期待を超える仕事ができるように日々頑張っています。 ISIDの好きなところ ・規模感 社員数2,000名規模の会社であるため、 大企業的要素の安心感と ベンチャー企業 的要素の風通しの良さが両立していると感じます。 ・社風 真面目ながらもカジュアルといった印象です。 社員同士を役職で呼ばず、○○さんと呼び合う文化も個人的には気に入っています。 ・ 従業員満足 度 個人的な所感なのですが、ISIDという会社に満足している社員の多さが 他の会社では中々感じられない魅力だと感じています。 実は働きがいのある会社ランキングでもISIDは上位にランクインしています。 私自身、もう一度就職活動をしたとしても入りたいと思える会社です。 最後に 今回はISIDやPOSITIVEのホームページより少し具体的にお仕事の紹介をいたしました。 こちらの記事を通して、読んでくださった皆様にとって何か持ち帰っていただけるものがあれば嬉しいです。 大変なことも多いかと思いますが、後悔しない就職活動ができるよう応援しています! 少しでも興味が湧いたら、是非新卒採用サイトも覗いてみてください。 https://www.isid.co.jp/ 執筆: @yamaguchi.saki 、レビュー: 寺山 輝 (@terayama.akira) ( Shodo で執筆されました )
アバター
こんにちは!HCM事業部のビジネスパートナー コンサルティング 部の山口です。 現在、私は「ビジネスパートナー支援」という、 皆さんが思い描くITのお仕事とは少し毛色の違うお仕事を担当しています。 この記事では、ISIDに興味を持ってくださっている就活生の皆さんに向けて、 新卒6年目(2018年入社)の私のお仕事とやりがい、そしてISIDの好きなところを紹介したいと思います。 なるべく具体的にお伝えできればと思いますので、 就活生の皆さんがISIDでの様々なお仕事を知っていただく上での参考としていただけたら嬉しいです。 自己紹介 事業部について 製品(統合人事システム”POSITIVE”)の特徴 仕事内容について やりがいを感じる瞬間 ISIDの好きなところ 最後に 自己紹介 ・年次: 2018年に新卒採用でISIDに入社し、今年で6年目になります。 ・大学の専攻: 商学部 で交通経済学を専攻していたTHE文系です。 日本の空港の 効率性分析 をテーマに研究をしていました。 ・職務経歴: 新入社員研修後、HCM事業部(統合人事システム"POSITIVE"を扱う事業部)へ配属されました。 最初の2年は製品開発部でPOSITIVEの開発業務を担当し、 その後異動して今所属しているビジネスパートナー コンサルティング 部にて ビジネスパートナーである代理店様の支援を行っています。 代理店支援のお仕事については後ほど説明します。 事業部について 私の働き方をお話しする前に、私が所属しているHCM事業部について簡単にお伝えしたいと思います。 HCM事業部は統合人事システム”POSITIVE”の開発、販売、導入を行っている事業部です。 ( 尾形さんの記事 にも詳細が書いてあるので是非ご覧ください!) 『ヒトを信じ、日本の「はたらく」を変える』をパーパスとして、TEAM POSITIVE一丸となって進んでいます。 個人的には、100名規模の事業部だからこそのアットホームな雰囲気があり、働きやすい環境だと感じています。 製品(統合人事システム”POSITIVE”)の特徴 ①統合人事システム POSITIVEは統合人事システムと呼ばれていまして、人事情報を軸として、 給与計算や勤怠管理、さらにはタレントマネジメントまで統合的に扱える製品です。 ②パッケージ製品 POSITIVEは標準的な業務に合わせて製品化された、パッケージと呼ばれるシステムです。 お客様の要件に合わせて1から組み立てていくス クラッチ システムとは性質が異なります。 パッケージシステムは、会社ごとの業務に合わせるための設定が必要です。 プロジェクトでは要件定義の段階でお客様の業務や運用方法をお伺いして、 フィットするように各種設定を行います。 ③販売経路 この後のお話にも繋がってくるのですが、 POSITIVEは直接販売と間接販売の両方の経路で販売を行っている点が特徴です。 直接販売はISIDが"POSITIVE"のメーカーとして市場調査から販売導入まで担う方法、 間接販売は販売導入の段階を代理店様にご担当いただく方法です。 HCM事業部はISIDで唯一、間接販売を本格的に推進しています。 仕事内容について 私が所属するビジネスパートナー コンサルティング 部では、 間接販売を担当していただいている代理店様の支援がミッションです。 大切なビジネスパートナーである代理店様に向けて、 主に教育を通して代理店様の販売導入を支援するお仕事をしています。 具体的には代理店様がPOSITIVEを販売・導入する上で必要となる知識を伝える教育を提供しています。 POSITIVEは先ほど製品の特徴①でお伝えしたように人事・給与・勤怠・タレントマネジメントなど 広い分野を対象としている製品です。 そのためPOSITIVEを扱う担当者としては、様々な分野の知識が必要となります。 また、お客様毎に運用に沿った設定を行うため、製品独自のノウハウが必要です。 そこで知っておくべき法律まわりの知識や、POSITIVEの操作・設定方法、 お客様の要件を聞く要件定義から設定とテストまでを模擬体験できる教育コンテンツなどを提供しています。 お仕事としては講座の講師のほか、新規講座の企画と作成も行っています。 やりがいを感じる瞬間 ・前例がない仕事に挑戦している時 誰もまだやったことのない仕事を実現すべく奔走している時にやりがいを感じます。 今年はeラーニングサイトを開設すべく、実現方法の検討から実際のサイト公開まで担当しました。 前例がないと予期せぬタスクに時間がかかってしまったり、 関係者の利害調整が発生したりと多くのハードルがありますが、 実現した先のメリットを信じて、乗り越えた時に達成感を感じます。 ・+αの仕事が出来た時 頼まれていた期日より少し早く提供できた、資料が見やすいと言ってもらえた、 これまで候補になかった新たな選択肢を提案できた、など、 些細なことかもしれませんが、+αの仕事が出来たと実感する瞬間にやりがいを感じます。 年次を経るに連れて求められるレベルは高くなっていきますが、 その期待を超える仕事ができるように日々頑張っています。 ISIDの好きなところ ・規模感 社員数2,000名規模の会社であるため、 大企業的要素の安心感と ベンチャー企業 的要素の風通しの良さが両立していると感じます。 ・社風 真面目ながらもカジュアルといった印象です。 社員同士を役職で呼ばず、○○さんと呼び合う文化も個人的には気に入っています。 ・ 従業員満足 度 個人的な所感なのですが、ISIDという会社に満足している社員の多さが 他の会社では中々感じられない魅力だと感じています。 実は働きがいのある会社ランキングでもISIDは上位にランクインしています。 私自身、もう一度就職活動をしたとしても入りたいと思える会社です。 最後に 今回はISIDやPOSITIVEのホームページより少し具体的にお仕事の紹介をいたしました。 こちらの記事を通して、読んでくださった皆様にとって何か持ち帰っていただけるものがあれば嬉しいです。 大変なことも多いかと思いますが、後悔しない就職活動ができるよう応援しています! 少しでも興味が湧いたら、是非新卒採用サイトも覗いてみてください。 https://www.isid.co.jp/ 執筆: @yamaguchi.saki 、レビュー: 寺山 輝 (@terayama.akira) ( Shodo で執筆されました )
アバター
こんにちは。金融ソリューション事業部の水野です。 本記事は 電通国際情報サービス Advent Calendar 2023 の12月25日の記事です。 今回は、BtoB向け SaaS をマルチテナントで実装した際の検討事項、採用した戦略について記載します。 Kubernetes で クラスタ を構築しており、AzureのPaaSである AKS を利用しました。 テナントとは? 設計方法論 マルチテナントにおける要求 AKSでの分離方針 テナント分離方針 Three Tenancy Models For Kubernetes Namespaces as a Service N/W RBAC コンピューティングリソースのクォータ テナント追加のオペレーションコストの低減 その他 おわりに テナントとは? Kubernetes では、テナントの定義は一つではないと説明されています。 https://kubernetes.io/docs/concepts/security/multi-tenancy/#tenants テナントが「チーム」を指すか「顧客(カスタマー)」を指すかで定義は異なります。 テナントがチームを表しているケース 各チームはサービスの複雑さに応じてスケーリングする少数のワークロードをデプロイ チームは大きな部門であったり、小さなチーム(開発チームなど)に細分されることも テナントがカスタマーを表しているケース カスタマーごとに専用のワークロードを展開する場合、複数顧客モデルとなる テナントは会社全体と大きい場合もあれば、会社の1部署と小さいこともある 概念的には、以下の図のようになります。 multi-team tenancy multi-customer tenancy 今回説明するテナントの定義は、上記 multi-customer tenancyにおけるテナントです。 設計方法論 Azureではなく AWS なのですが・・・ デザインパターン のような モデル化された3つの手法 が提示されています。 まずはこの3つのパターンを整理し、ビジネス上の要求に最もフィットするモデルを選択することにしました。3つの設計モデルの概要及び、大まかなPros./Consは以下です。 モデル 特徴 Pros. Cons. サイロ ・すべてのリソースはテナントごとに専有する ・一つの クラスタ はシングルテナントになる ・テナント境界が強固なためセキュリティ向上 ・リソースの上限に到達する可能性が比較的低い ・アプリケーションの実装難易度が他のモデルより下がる ・ クラウド ランニング費用が増大 ブリッジ ・コンピューティングリソースは共有/データストアは専有 ・アカウント/ インスタンス / スキーマ など、データストアによって分離方法は異なる ・サイロよりはインフラ構築難易度が低い ・リスク影響度の高いデータに関するリスクを一定下げられる ・もっともインフラ的に複雑になりうるDB周りが依然複雑なため、開発・運用コストが増大 プール ・すべてのリソースを各テナントで共有する ・レコードで分離するため、データの取得時はアプリケーションでテナント識別子を指定する必要がある ・ ランニングコスト が低い ・構成がシンプル ・テナント間のデータ保護のほとんどをアプリケーションレイヤで担保 ・リソースのリミットに到達する可能性が比較的高い 3つのモデルを更にブレイクダウンし、いくつかの軸で評価・検討したものは以下(主観あり)です。 凡例 ◎:最も良い ○:良い △:普通 ×:悪い 特筆すべき点です。 セキュリティ サイロはN/W・H/W、リソースが完全に分離しており、テナント間の分離が容易に実現可能 ブリッジ、プールは共有部分に依存してリスクは高まるが、設計でカバー可能なレベル スケーラビリティ(ビジネス面) サイロ→プールに行くにしたがってROIは高まる 実装難度・コスト サイロのアプリ実装はシングルテナントと同様で特に考慮不要 ブリッジ→プールに行くほどテナント間のデータ境界を意識する必要があり、インフラ実装難度が上がる 可用性 全て分離している方が爆心半径が狭い パフォーマンス 専有リソースが多いほどシステムリソースに余裕がある(調整の余地が大きい) デプロイのアジリティ デプロイ対象が多いほど大変。プールならば一度のデプロイで全テナントに反映される マルチテナントにおける要求 今回実装する SaaS におけるビジネス要求は以下でした。 カテゴリ 要求事項 適したモデル セキュリティ 極めてセンシティブな企業の機密情報を扱う サイロ セキュリティ 未許可のデータが他のテナントから参照出来てはならない (アプリケーションのバグやオペミス含め、絶対に別テナントに見せてはならない) サイロ 分離レベル ストレージアカウント・データベースアカウントはテナントごとに物理的に分離し、データの独立性を保つ サイロ テナント数 一桁スタートで徐々に増加し、最大100想定 総合的に検討 ランニングコスト 各テナントの ランニングコスト を可視化したい サイロ ランニングコスト ランニングコスト は可能な限り下げたい プール 可用性 あるテナントの障害を別のテナントの障害に波及させない サイロ コンピューティング リソース テナントごとにワークロードが大きく異なり、テナント間でリソース干渉する事態は避けたい サイロ デプロイ デプロイ対象・回数は少ない方が良い プール デプロイ デプロイのアジリティを高めたい プール 物理的にリソースを分離する/ ランニングコスト をテナントごとに正確に把握するというビジネス要求から、サイロ寄りのブリッジモデルを選択しました。完全なサイロモデルの場合、テナント数から ランニングコスト が莫大になるという事情もありました。 AKS での分離方針 分離方式は、 クラスタ と ノードプール をどのように扱うかで、以下の3つが考えられます。 共有 クラスタ /共有ノードプール 全てのテナントのアプリケーションを一つの クラスタ 、一つのノードプールで共有する方式 共有 クラスタ /専有ノードプール 全てのテナントのアプリケーションを一つの クラスタ で共有するが、アプリケーションが稼働するノードプールはテナントごとに分離する方式 専有 クラスタ テナント共通アプリケーション、テナント固有アプリケーション双方を専用の クラスタ に分離する方式 クラスタ Podがデプロイされる Kubernetes ノードの集合 ノードプール Podがデプロイされる Kubernetes ノードの集合 systemノードプールとuserノードプールから成る 可用性の観点からZONE冗長構成を組むため、1ノードプールあたり3ノード必要=2ノードプールで6ノード必要 主要な検討項目ごとに、重みなしで点数を付けた結果が以下です。 項目 共有 クラスタ / 共有ノードプール 共有 クラスタ / 専有ノードプール 専有 クラスタ ランニングコスト ◎ 〇 × コスト管理の容易性 × △ ◎ N/Wの分離 〇 〇 ◎ IDの分離(アプリケーション) △ △ ◎ IDの分離( クラスタ オペレーション) 〇 〇 〇 コンピューティングリソースの分離 △ 〇 ◎ 運用性( クラスタ 管理) ◎ ◎ × 実装・運用の難易度 △ 〇 ◎ 1テナントあたりの実装・運用コスト ◎ 〇 × 拡張性 ◎ △ 〇 点数 19 21 19 凡例 ◎:3点 ○:2点 △:1点 ×:0点 3つの方式でほぼ同点、つまり各分離方針で大差はなく、どの方式でも最終的に実現される可用性、信頼性、セキュリティでは大きな違いはありません。 違いが出る&大きな要素に関わるのは以下の点のため、こちらに絞って検討しました。 ランニングコスト 実装の難易度 トラブルシューティング の容易性 保守運用業務の効率/生産性 AKS の仕様(提供機能、制約)との要件適合性 検討の結果、 共有クラスタ/共有ノードプール を選択し、ノードプール内のPodは各テナントで占有としました。 決め手になったポイントです。 専有 クラスタ はコストが割高 専有 クラスタ は実装難易度は低いが、テナントの数が増えるに従って運用が煩雑になる 共有クラスタ は、近い将来非推奨になる機能の書き換えが必要だが、実装時点でノックアウトはなく移行も容易 Pod Identity から Azure AD Workload Idenity への移行が必要となる(2023年12月現在既に移行済み) 共有 クラスタ /専有ノードプール は共有ノードプールよりノードプール部分の実装難易度が低い ただし、最大ノードプール数100の上限があるため、100テナントを超えると2つめの クラスタ が必要 共有クラスタ/共有ノードプール は実装・運用の難易度が最も高いが、保守効率が高い 共有クラスタ/共有ノードプール は、 ランニングコスト が最も低い テナントごとのコスト割合を厳密に算出することが難しいというデメリットはあるが、おおよそ正しい値を算出できるため許容する 概念図としては以下になります。 マルチテナントにおける要求 に記載の通り、データベースアカウントとシークレットをテナント毎に保持する必要があるため、占有リソースとしています。なお、データベースはCosmosDBを採用しています。 テナント分離方針 テナントの分離は Three Tenancy Models For Kubernetes から選択しました。 Three Tenancy Models For Kubernetes 分離モデル 特徴 Namespaces as a Service Namespaceで分離し、各テナントが個別のNamespaceを持つ Clusters as a Service クラスタ 単位で分離し、各テナントが個別の クラスタ を持つ Control planes as a Service クラスタ 単位で分離し、各テナントが個別のコン トロール プレーンを持つ 広く採用されており、最もシンプルに構成できる Namespaces as a Service を採用しました。 Namespaces as a Service Namespaceで必要な境界を設けます。 大方針は以下です。 テナントごとにNamespaceを分離 通常のワークロードとデータ監査のワークロードを分離するため、同一テナント内で2つのNamespaceに分離 テナントに依存しない認証などの共通機能は別のNamespaceで管理 分離に伴い、 Kubernetes やAzureのサービス/ コンポーネント は以下を使用しました。 カテゴリ 概要 構成要素 Namespace ・ Kubernetes リソースの分離の基本要素 Namespace N/W ・テナントのルーティング ・ トラフィック 制御 Application Gateway Ingress Controller Network Policy RBAC ・ Kubernetes リソースに対するRBAC ・Azureリソース/外部サービスに対するRBAC ClusterRole / ClusterRoleBindings Role / RoleBindings AAD Pod Identity Azure Key Vault Provider for Secrets Store CSI Driver コンピューティングリソース ・使用するリソースの上限 Resource Quota デプロイ ・運用 Terraform Module Helm Chart 上記を踏まえた、テナント毎に分離する アーキテクチャ の概念図は以下となります。 N/W N/W空間は共有 テナントのルーティング テナントごとに Ingress リソースを作成し、テナントごとのPodへのルーティング テナントごとのアプリケーションはFrontendのみを公開 Egressリソースで外部 SaaS 接続時のNAT IPは、全テナントで共通のIPを共用 トラフィック 制御 Network Policyを使用して トラフィック を制御し、Pod間の通信を制限 自テナントかつ当該Podにアクセスする必要がある送信元からのInboundのみ許可 RBAC Kubernetes リソースに対するRBAC ClusterRole / ClusterRoleBindings および Role / RoleBindings を利用 ロールをAzure ADグループに紐づけ、特定の人間が特定のテナントの管理オペレーションを行う Azureリソース/外部サービスに対するRBAC 各サービスに接続する際に必要なクレデンシャル情報は、テナント内のSecret経由でのみ参照可能 テナントごとのクレデンシャル情報は自テナント専用のKey Vaultで管理し、 Kubernetes Secretと同期させる テナントごとのIDでKey Vaultアクセスを認証し、他テナントのKey Vaultはアクセスできない コンピューティングリソースのクォータ テナントごとにvCPU、Memoryなどのコンピューティングリソースの上限をResource Quotaで設定 ノイジーネイバー問題 を防ぐ 性能テストの結果および本番 トラフィック でのリソース使用量から上限値を決定 テナント追加のオペレーションコストの低減 テナントごとのAzureリソース、 Kubernetes リソースの管理を容易にするためにIaCで構築 テナント固有の一連のAzureリソースを管理するためのTerraformモジュール テナント固有の一連の Kubernetes リソースを管理するためのHelmチャート その他 他にも、権限分掌やセキュリティについて、Azureリソースや外部サービス利用についていくつかのポイントはありますが、本題ではないので簡単に紹介するにとどめます。 アクセスポリシーにより自テナントのKey Vaultにのみアクセスできるように制御 CosmosDBのアクセスに必要なアクセスキーは自テナントの Kubernetes Secret内に保持 Kubernetes Secretへのアクセスを自テナントのアプリケーションに限定 API で呼びだす外部 SaaS は、アクセスに必要なアクセスキー、 API トーク ンを自テナントのみ参照可能 ユーザー認証は全てAzureADに委譲 おわりに 今回は、 AKS 上で SaaS をマルチテナント構成で構築した設計戦略・構築上の大きなポイントについて書かせていただきました。まだまだ改善できるポイントはきっとあるので、日々 クラスタ を運用しながら検討を続けていきたいと思います。 最後までご覧いただきありがとうございました。皆さま良いお年を! 私たちは一緒に働いてくれる仲間を募集しています! 募集職種一覧 執筆: @mizuno.kazuhiro 、レビュー: @sato.taichi ( Shodo で執筆されました )
アバター
こんにちは。金融ソリューション事業部の水野です。 本記事は 電通国際情報サービス Advent Calendar 2023 の12月25日の記事です。 今回は、BtoB向け SaaS をマルチテナントで実装した際の検討事項、採用した戦略について記載します。 Kubernetes で クラスタ を構築しており、AzureのPaaSである AKS を利用しました。 テナントとは? 設計方法論 マルチテナントにおける要求 AKSでの分離方針 テナント分離方針 Three Tenancy Models For Kubernetes Namespaces as a Service N/W RBAC コンピューティングリソースのクォータ テナント追加のオペレーションコストの低減 その他 おわりに テナントとは? Kubernetes では、テナントの定義は一つではないと説明されています。 https://kubernetes.io/docs/concepts/security/multi-tenancy/#tenants テナントが「チーム」を指すか「顧客(カスタマー)」を指すかで定義は異なります。 テナントがチームを表しているケース 各チームはサービスの複雑さに応じてスケーリングする少数のワークロードをデプロイ チームは大きな部門であったり、小さなチーム(開発チームなど)に細分されることも テナントがカスタマーを表しているケース カスタマーごとに専用のワークロードを展開する場合、複数顧客モデルとなる テナントは会社全体と大きい場合もあれば、会社の1部署と小さいこともある 概念的には、以下の図のようになります。 multi-team tenancy multi-customer tenancy 今回説明するテナントの定義は、上記 multi-customer tenancyにおけるテナントです。 設計方法論 Azureではなく AWS なのですが・・・ デザインパターン のような モデル化された3つの手法 が提示されています。 まずはこの3つのパターンを整理し、ビジネス上の要求に最もフィットするモデルを選択することにしました。3つの設計モデルの概要及び、大まかなPros./Consは以下です。 モデル 特徴 Pros. Cons. サイロ ・すべてのリソースはテナントごとに専有する ・一つの クラスタ はシングルテナントになる ・テナント境界が強固なためセキュリティ向上 ・リソースの上限に到達する可能性が比較的低い ・アプリケーションの実装難易度が他のモデルより下がる ・ クラウド ランニング費用が増大 ブリッジ ・コンピューティングリソースは共有/データストアは専有 ・アカウント/ インスタンス / スキーマ など、データストアによって分離方法は異なる ・サイロよりはインフラ構築難易度が低い ・リスク影響度の高いデータに関するリスクを一定下げられる ・もっともインフラ的に複雑になりうるDB周りが依然複雑なため、開発・運用コストが増大 プール ・すべてのリソースを各テナントで共有する ・レコードで分離するため、データの取得時はアプリケーションでテナント識別子を指定する必要がある ・ ランニングコスト が低い ・構成がシンプル ・テナント間のデータ保護のほとんどをアプリケーションレイヤで担保 ・リソースのリミットに到達する可能性が比較的高い 3つのモデルを更にブレイクダウンし、いくつかの軸で評価・検討したものは以下(主観あり)です。 凡例 ◎:最も良い ○:良い △:普通 ×:悪い 特筆すべき点です。 セキュリティ サイロはN/W・H/W、リソースが完全に分離しており、テナント間の分離が容易に実現可能 ブリッジ、プールは共有部分に依存してリスクは高まるが、設計でカバー可能なレベル スケーラビリティ(ビジネス面) サイロ→プールに行くにしたがってROIは高まる 実装難度・コスト サイロのアプリ実装はシングルテナントと同様で特に考慮不要 ブリッジ→プールに行くほどテナント間のデータ境界を意識する必要があり、インフラ実装難度が上がる 可用性 全て分離している方が爆心半径が狭い パフォーマンス 専有リソースが多いほどシステムリソースに余裕がある(調整の余地が大きい) デプロイのアジリティ デプロイ対象が多いほど大変。プールならば一度のデプロイで全テナントに反映される マルチテナントにおける要求 今回実装する SaaS におけるビジネス要求は以下でした。 カテゴリ 要求事項 適したモデル セキュリティ 極めてセンシティブな企業の機密情報を扱う サイロ セキュリティ 未許可のデータが他のテナントから参照出来てはならない (アプリケーションのバグやオペミス含め、絶対に別テナントに見せてはならない) サイロ 分離レベル ストレージアカウント・データベースアカウントはテナントごとに物理的に分離し、データの独立性を保つ サイロ テナント数 一桁スタートで徐々に増加し、最大100想定 総合的に検討 ランニングコスト 各テナントの ランニングコスト を可視化したい サイロ ランニングコスト ランニングコスト は可能な限り下げたい プール 可用性 あるテナントの障害を別のテナントの障害に波及させない サイロ コンピューティング リソース テナントごとにワークロードが大きく異なり、テナント間でリソース干渉する事態は避けたい サイロ デプロイ デプロイ対象・回数は少ない方が良い プール デプロイ デプロイのアジリティを高めたい プール 物理的にリソースを分離する/ ランニングコスト をテナントごとに正確に把握するというビジネス要求から、サイロ寄りのブリッジモデルを選択しました。完全なサイロモデルの場合、テナント数から ランニングコスト が莫大になるという事情もありました。 AKS での分離方針 分離方式は、 クラスタ と ノードプール をどのように扱うかで、以下の3つが考えられます。 共有 クラスタ /共有ノードプール 全てのテナントのアプリケーションを一つの クラスタ 、一つのノードプールで共有する方式 共有 クラスタ /専有ノードプール 全てのテナントのアプリケーションを一つの クラスタ で共有するが、アプリケーションが稼働するノードプールはテナントごとに分離する方式 専有 クラスタ テナント共通アプリケーション、テナント固有アプリケーション双方を専用の クラスタ に分離する方式 クラスタ Podがデプロイされる Kubernetes ノードの集合 ノードプール Podがデプロイされる Kubernetes ノードの集合 systemノードプールとuserノードプールから成る 可用性の観点からZONE冗長構成を組むため、1ノードプールあたり3ノード必要=2ノードプールで6ノード必要 主要な検討項目ごとに、重みなしで点数を付けた結果が以下です。 項目 共有 クラスタ / 共有ノードプール 共有 クラスタ / 専有ノードプール 専有 クラスタ ランニングコスト ◎ 〇 × コスト管理の容易性 × △ ◎ N/Wの分離 〇 〇 ◎ IDの分離(アプリケーション) △ △ ◎ IDの分離( クラスタ オペレーション) 〇 〇 〇 コンピューティングリソースの分離 △ 〇 ◎ 運用性( クラスタ 管理) ◎ ◎ × 実装・運用の難易度 △ 〇 ◎ 1テナントあたりの実装・運用コスト ◎ 〇 × 拡張性 ◎ △ 〇 点数 19 21 19 凡例 ◎:3点 ○:2点 △:1点 ×:0点 3つの方式でほぼ同点、つまり各分離方針で大差はなく、どの方式でも最終的に実現される可用性、信頼性、セキュリティでは大きな違いはありません。 違いが出る&大きな要素に関わるのは以下の点のため、こちらに絞って検討しました。 ランニングコスト 実装の難易度 トラブルシューティング の容易性 保守運用業務の効率/生産性 AKS の仕様(提供機能、制約)との要件適合性 検討の結果、 共有クラスタ/共有ノードプール を選択し、ノードプール内のPodは各テナントで占有としました。 決め手になったポイントです。 専有 クラスタ はコストが割高 専有 クラスタ は実装難易度は低いが、テナントの数が増えるに従って運用が煩雑になる 共有クラスタ は、近い将来非推奨になる機能の書き換えが必要だが、実装時点でノックアウトはなく移行も容易 Pod Identity から Azure AD Workload Idenity への移行が必要となる(2023年12月現在既に移行済み) 共有 クラスタ /専有ノードプール は共有ノードプールよりノードプール部分の実装難易度が低い ただし、最大ノードプール数100の上限があるため、100テナントを超えると2つめの クラスタ が必要 共有クラスタ/共有ノードプール は実装・運用の難易度が最も高いが、保守効率が高い 共有クラスタ/共有ノードプール は、 ランニングコスト が最も低い テナントごとのコスト割合を厳密に算出することが難しいというデメリットはあるが、おおよそ正しい値を算出できるため許容する 概念図としては以下になります。 マルチテナントにおける要求 に記載の通り、データベースアカウントとシークレットをテナント毎に保持する必要があるため、占有リソースとしています。なお、データベースはCosmosDBを採用しています。 テナント分離方針 テナントの分離は Three Tenancy Models For Kubernetes から選択しました。 Three Tenancy Models For Kubernetes 分離モデル 特徴 Namespaces as a Service Namespaceで分離し、各テナントが個別のNamespaceを持つ Clusters as a Service クラスタ 単位で分離し、各テナントが個別の クラスタ を持つ Control planes as a Service クラスタ 単位で分離し、各テナントが個別のコン トロール プレーンを持つ 広く採用されており、最もシンプルに構成できる Namespaces as a Service を採用しました。 Namespaces as a Service Namespaceで必要な境界を設けます。 大方針は以下です。 テナントごとにNamespaceを分離 通常のワークロードとデータ監査のワークロードを分離するため、同一テナント内で2つのNamespaceに分離 テナントに依存しない認証などの共通機能は別のNamespaceで管理 分離に伴い、 Kubernetes やAzureのサービス/ コンポーネント は以下を使用しました。 カテゴリ 概要 構成要素 Namespace ・ Kubernetes リソースの分離の基本要素 Namespace N/W ・テナントのルーティング ・ トラフィック 制御 Application Gateway Ingress Controller Network Policy RBAC ・ Kubernetes リソースに対するRBAC ・Azureリソース/外部サービスに対するRBAC ClusterRole / ClusterRoleBindings Role / RoleBindings AAD Pod Identity Azure Key Vault Provider for Secrets Store CSI Driver コンピューティングリソース ・使用するリソースの上限 Resource Quota デプロイ ・運用 Terraform Module Helm Chart 上記を踏まえた、テナント毎に分離する アーキテクチャ の概念図は以下となります。 N/W N/W空間は共有 テナントのルーティング テナントごとに Ingress リソースを作成し、テナントごとのPodへのルーティング テナントごとのアプリケーションはFrontendのみを公開 Egressリソースで外部 SaaS 接続時のNAT IPは、全テナントで共通のIPを共用 トラフィック 制御 Network Policyを使用して トラフィック を制御し、Pod間の通信を制限 自テナントかつ当該Podにアクセスする必要がある送信元からのInboundのみ許可 RBAC Kubernetes リソースに対するRBAC ClusterRole / ClusterRoleBindings および Role / RoleBindings を利用 ロールをAzure ADグループに紐づけ、特定の人間が特定のテナントの管理オペレーションを行う Azureリソース/外部サービスに対するRBAC 各サービスに接続する際に必要なクレデンシャル情報は、テナント内のSecret経由でのみ参照可能 テナントごとのクレデンシャル情報は自テナント専用のKey Vaultで管理し、 Kubernetes Secretと同期させる テナントごとのIDでKey Vaultアクセスを認証し、他テナントのKey Vaultはアクセスできない コンピューティングリソースのクォータ テナントごとにvCPU、Memoryなどのコンピューティングリソースの上限をResource Quotaで設定 ノイジーネイバー問題 を防ぐ 性能テストの結果および本番 トラフィック でのリソース使用量から上限値を決定 テナント追加のオペレーションコストの低減 テナントごとのAzureリソース、 Kubernetes リソースの管理を容易にするためにIaCで構築 テナント固有の一連のAzureリソースを管理するためのTerraformモジュール テナント固有の一連の Kubernetes リソースを管理するためのHelmチャート その他 他にも、権限分掌やセキュリティについて、Azureリソースや外部サービス利用についていくつかのポイントはありますが、本題ではないので簡単に紹介するにとどめます。 アクセスポリシーにより自テナントのKey Vaultにのみアクセスできるように制御 CosmosDBのアクセスに必要なアクセスキーは自テナントの Kubernetes Secret内に保持 Kubernetes Secretへのアクセスを自テナントのアプリケーションに限定 API で呼びだす外部 SaaS は、アクセスに必要なアクセスキー、 API トーク ンを自テナントのみ参照可能 ユーザー認証は全てAzureADに委譲 おわりに 今回は、 AKS 上で SaaS をマルチテナント構成で構築した設計戦略・構築上の大きなポイントについて書かせていただきました。まだまだ改善できるポイントはきっとあるので、日々 クラスタ を運用しながら検討を続けていきたいと思います。 最後までご覧いただきありがとうございました。皆さま良いお年を! 私たちは一緒に働いてくれる仲間を募集しています! 募集職種一覧 執筆: @mizuno.kazuhiro 、レビュー: @sato.taichi ( Shodo で執筆されました )
アバター
こんにちは。金融ソリューション事業部の多田です。 本記事は 電通国際情報サービス Advent Calendar 2023 22日目の記事となります。 前日の記事は星野将吾さんの「 若手こそ受けておきたい!IPA システムアーキテクト試験 」でした。 はじめに microservices-demoについて productcatalogserviceをRustで実装する productcatalogserviceの内容を確認 準備 tonicについて Rustによる実装 gRPCサーバーの動作確認 EKSへのデプロイ 準備 コンテナイメージの準備 & ECRへの登録 AWS CloudShellの準備 AWS上にEKSクラスター/ノードグループを作成する microservices-demoのデプロイ 後始末 まとめ はじめに みなさん、 microservices-demo をご存知でしょうか。 Google が提供している クラウド を前提としたマイクロサービスのデモアプリケーションです。 今回はこのmicroservices-demoの一部をRust実装に置き換えて Amazon EKS(以降、EKS)にデプロイしてみました。 筆者は社内ワーキンググループの活動としてソフトウェア アーキテクチャ の技術調査などを行っており その一環としてRust/gRPC/GraphQLを用いたマイクロサービス アーキテクチャ を検討しております。 本記事はその検討にあたって実施した内容の一部をまとめたものになります。 microservices-demoについて ECサイト を模しており、商品の閲覧やカートへ入れる、購入するといったことが可能です(決済などはモックです)。 技術的には Kubernetes 、GKE、Istio、Stackdriver、gRPCなどを使用しています。 少し設定を加えればGKEなどに作成した Kubernetes クラスタ ー上にデプロイ可能となっています。 アーキテクチャ と各サービスの言語、役割は以下のようになっています。 今回はこの中の productcatalogservice をRust実装に置き換えます。 (役割は筆者の意訳です。詳細は README をご確認ください) サービス 言語 役割 frontend Go HTTPサーバ。ユーザーと直接やり取りするのはココ cartservice C# 商品の保存や取得(ショッピングカート) productcatalogservice Go 商品一覧と各商品情報(商品名、概要)の提供、検索 currencyservice Node.js 各通貨の変換 paymentservice Node.js クレジットカード(モック)で決済 shippingservice Go 送料の計算と住所(モック)への発送 emailservice Python 購入確認メール(メールアドレスはモック)の送信 checkoutservice Go カートの情報を元に注文準備や支払い、発送、メール通知を調整 recommendationservice Python カートにある商品を元に別の商品を推薦 adservice Java テキスト広告の提供 loadgenerator Python /Locust EC2の利用フローを模したリク エス トを継続的に実施(おそらく負荷テスト用) productcatalogserviceをRustで実装する productcatalogserviceの内容を確認 サービス同士の通信にはgRPCを使用しています。 Protocol Buffersは既にあるため、それを元にサービスを実装します。 demo.proto productcatalogserviceのインターフェースは以下です。 (Productなどのメッセージ定義は省略しています) service ProductCatalogService { rpc ListProducts(Empty) returns (ListProductsResponse) {} rpc GetProduct(GetProductRequest) returns (Product) {} rpc SearchProducts(SearchProductsRequest) returns (SearchProductsResponse) {} } microservices-demo上ではGoで実装されています。 コード を見てみると products.json に商品情報があり、これを元に商品一覧や各商品情報、検索機能を提供しているようです。 この実装を参考にRustで実装します。 準備 以下を参考にRustのインストールをお願いします。 https://www.rust-lang.org/ja/tools/install tonicについて tonic というクレートを使用して実装します。 tonicはRustネイティブのgRPC実装です。用途により コンポーネント が用意されており、それらを組み合わせて使用します。 今回はtonic-buildという コンポーネント を使用してprotoファイルを元にス ケルト ンとスタブを生成し、それを元にgRPCサーバーとクライアントを実装しました。 デモアプリケーション上ではクライアントは不要ですがテストのために実装しました。 tonicを利用するにはprotocのインストールが必要になります。 お使いの環境にあわせてインストールしてください。 https://github.com/hyperium/tonic?tab=readme-ov-file#dependencies Windows の場合、上記に加えてPROTOCという 環境変数 を用意しprotoc.exeへのパスを設定する必要があります。 (筆者はここで「 コンパイル できない(; ;)」と30分ほど無駄にしました) Rustによる実装 コードの全量は以下になります。 productcatalogservice 構成は以下のとおりです。 productcatalogservice |-- Cargo.toml |-- Dockerfile ... EKSへデプロイするためのイメージ作成で使用(後述) |-- build.rs ... スケルトン、スタブ生成用のコード |-- pb | |-- demo.proto ... 前述のproductcatalogserviceのインターフェースを定義 |-- products.json ... 商品情報リスト |-- src |-- client.rs ... gRPCクライアントのコード |-- server.rs ... gRPCサーバーのコード 本記事では build.rs と server.rs について解説します。 その他は実際のコードをご確認ください。 まずは build.rs です。 fn main () -> Result < (), Box < dyn std :: error :: Error >> { tonic_build :: configure () . type_attribute ( "." , "#[derive(serde::Deserialize)]" ) . type_attribute ( "." , "#[serde(rename_all = \" camelCase \" )]" ) . compile ( & [ "./pb/demo.proto" ], & [ "./pb" ]) ? ; Ok (()) } build.rs はビルド時にprotoファイルを読み込んでス ケルト ンとスタブのコードを生成します。 type_attribute(...) は生成されるス ケルト ンとスタブに属性を付与したい場合に使用します。 今回は product.json から自動生成されたコード(商品の構造体)に直接変換するため、そのための属性を付与しました。 (実開発においては直接変換ではなく間に DTO などを挟むと思います) ビルドに成功するとtarget配下にコードが生成されます。 続いて server.rs です(一部省略しています)。 // 生成されたコードの読み込み pub mod hipstershop { // demo.protoのpackageを指定 tonic :: include_proto! ( "hipstershop" ); } // 省略 #[derive( Default )] pub struct ProductCatalogServiceImpl {} // サーバ用のコードを実装 #[tonic::async_trait] impl ProductCatalogService for ProductCatalogServiceImpl { async fn list_products ( & self , _request: Request < Empty > ) -> Result < Response < ListProductsResponse > , Status > { let products = read_catalog_file ().await; let reply: ListProductsResponse = ListProductsResponse{ products: products }; Ok ( Response :: new (reply)) } async fn get_product ( & self , request: Request < GetProductRequest > ) -> Result < Response < Product > , Status > { //省略 } async fn search_products ( & self , request: Request < SearchProductsRequest > ) -> Result < Response < SearchProductsResponse > , Status > { //省略 } } #[tokio::main] async fn main () -> Result < (), Box < dyn std :: error :: Error >> { // 省略 let addr = "0.0.0.0:3550" . parse (). unwrap (); let product_catalog_service = ProductCatalogServiceImpl :: default (); println! ( "HealthServer + ProductCatalogServiceServer listening on {}" , addr); Server :: builder () . add_service (health_service) . add_service ( ProductCatalogServiceServer :: new (product_catalog_service)) . serve (addr) .await ? ; Ok (()) } pub mod hipstershop {...} では自動生成されたコードをモジュールとして定義しています。 tonic::include_proto!("hipstershop") は自動生成されたコードを読み込むためのマクロです。 引数にはprotoファイルのpackageを指定します。 impl ProductCatalogService for ProductCatalogServiceImpl {...} はサービスの実装です。 自動生成されたProductCatalogServiceトレイトを実装しています。 product.json から商品情報を読み込み、それをそのまま返したり、中身を検索したりしています。 main() はgRPCサーバーを起動するための実装です。 ポートやサービスの設定などをしています。 gRPCサーバーの動作確認 サーバーは以下のコマンドで起動します。 cargo run --bin server クライアントを実行して動作確認をしてみます。 cargo run --bin client 成功すると以下のような結果が表示されます。 RESPONSE =Response { metadata: MetadataMap { headers: { " content-type " : " application/grpc " , " date " : " Tue, 19 Dec 2023 08:02:30 GMT " , " grpc-status " : " 0 " } } , message: ListProductsResponse { products: [ Product { id: " OLJCESPC7Z " , name: " Sunglasses " , description: " Add a modern touch to your outfits with these sleek aviator sunglasses. " , picture: " /static/img/products/sunglasses.jpg " , price_usd: Some ( Money { currency_code: " USD " , units: 19 , nanos: 990000000 } ) , ...省略 これでRustによる実装ができましたので、次はEKSへデプロイします。 EKSへのデプロイ 準備 EKSへデプロイするために AWS アカウントの作成と AWS CLI のインストール、認証情報の設定をしてください。 また、イメージ作成にはDockerを使用しますのでお使いの環境にあわせてインストールしてください。 https://docs.docker.jp/desktop/install.html コンテナイメージの準備 & ECRへの登録 EKSへデプロイするためにproductcatalogserviceのイメージを作成しECRへイメージを登録します。 まず以下を参考に AWS コンソールからECRにプライベー トリポジ トリを作成します( リポジトリ 名はproductcatalogservice)。 https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/repository-create.html 次にイメージを作成しECRへpushするため、以下のコマンドを実行します。 AWS のアカウント番号は適宜置き換えてください。 リージョンは東京リージョンにしています。 # イメージ作成 docker build -t productcatalogservice . # タグ付けする docker tag productcatalogservice:latest < AWSのアカウント番号 > .dkr.ecr.ap-northeast-1.amazonaws.com/productcatalogservice:latest # dockerクライアントの認証 aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin < AWSのアカウント番号 > .dkr.ecr.ap-northeast-1.amazonaws.com # push docker push < アカウント番号 > .dkr.ecr.ap-northeast-1.amazonaws.com/productcatalogservice:latest AWS CloudShellの準備 EKSへのデプロイには AWS CloudShellを利用します。 まずはkubectlを使えるようにします。 kubectlは kubernetes 用の コマンドライン ツールです。 マイクロサービスのデプロイに使用します。 curl -O https://s3.us-west-2.amazonaws.com/amazon-eks/ 1 . 28 . 3 /2023-11-14/bin/linux/amd64/kubectl chmod +x ./kubectl mkdir -p $HOME /bin && cp ./kubectl $HOME /bin/kubectl && export PATH = $PATH : $HOME /bin echo ' export PATH=$PATH:$HOME/bin ' >> ~/.bashrc kubectl version --client 続いてeksctlを使えるようにします。 eksctlはEKS上で Kubernetes クラスタ ーを作成・管理するための コマンドライン ツールです。 curl --silent --location " https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_ $( uname -s ) _amd64.tar.gz " | tar xz -C /tmp sudo mv /tmp/eksctl /usr/local/bin eksctl version AWS 上にEKS クラスタ ー/ノードグループを作成する 以下のコマンドで クラスタ ーを作成できます(10分ほどで完了します)。 name は onlineboutique 、 region は東京リージョンとしています。 eksctl create cluster --name onlineboutique --region ap-northeast-1 --without-nodegroup クラスタ ーの作成が完了したらノードグループを作成します(2分ほどで完了します)。 cluster は onlineboutique 、ノード数は4としています。 eksctl create nodegroup --cluster onlineboutique --region ap-northeast-1 --nodes 4 --nodes-min 4 --nodes-max 4 microservices-demoのデプロイ クラスタ ーが作成できたらいよいよデプロイです。 microservices-demoをクローンし、ECRへpushしたイメージを使うよう マニフェスト を修正します。 ★でproductcatalogserviceの image を以下のように修正してください。 修正前: gcr.io/ google -samples/microservices-demo/productcatalogservice:<バージョン> 修正後:<アカウント番号>.dkr.ecr.ap-northeast-1.amazonaws.com/productcatalogservice:latest その後、 kubectl apply でデプロイします。 # microservices-demoをクローン git clone https://github.com/GoogleCloudPlatform/microservices-demo.git # リポジトリへ移動 cd microservices-demo # 書き換え(★) vi ./release/kubernetes-manifests.yaml # デプロイ kubectl apply -f ./release/kubernetes-manifests.yaml サービスの一覧を確認するとfrontendにELBの DNS 名が割り当てられています。 kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT ( S ) AGE adservice ClusterIP 10 . 100 . 8 . 99 < none > 9555 /TCP 2m34s cartservice ClusterIP 10 . 100 . 167 . 3 < none > 7070 /TCP 2m35s checkoutservice ClusterIP 10 . 100 . 155 . 33 < none > 5050 /TCP 2m35s currencyservice ClusterIP 10 . 100 . 81 . 172 < none > 7000 /TCP 2m34s emailservice ClusterIP 10 . 100 . 116 . 249 < none > 5000 /TCP 2m35s frontend ClusterIP 10 . 100 . 23 . 148 < none > 80 /TCP 2m35s frontend-external LoadBalancer 10 . 100 . 167 . 89 a0f6456281124412b8f095f94c6e242a-2020525330.ap-northeast-1.elb.amazonaws.com 80:31538/TCP 2m35s kubernetes ClusterIP 10 . 100 . 0 . 1 < none > 443 /TCP 17m paymentservice ClusterIP 10 . 100 . 154 . 183 < none > 50051 /TCP 2m35s productcatalogservice ClusterIP 10 . 100 . 20 . 37 < none > 3550 /TCP 2m35s recommendationservice ClusterIP 10 . 100 . 90 . 209 < none > 8080 /TCP 2m35s redis-cart ClusterIP 10 . 100 . 32 . 58 < none > 6379 /TCP 2m34s shippingservice ClusterIP 10 . 100 . 194 . 29 < none > 50051 /TCP 2m34s ブラウザでアクセスして画像のような画面が表示されれば成功です。 後始末 削除は以下の順でコマンドを実行します。 グループ名はマネジメントコンソールなどでご確認ください。 # podを削除 kubectl delete -f ./release/kubernetes-manifests.yaml # ノードグループを削除 eksctl delete nodegroup --cluster=onlineboutique --region ap-northeast-1 --name=<グループ名> --wait # クラスターを削除 eksctl delete cluster --name onlineboutique --region ap-northeast-1 --wait まとめ Google が提供しているmicroservices-demoの一部をRustに置き換えてEKSにデプロイしてみました。 tonicを用いることで簡単にRustで実装できました。 他のサービスもRustで置き換える場合、共通部分をライブラリクレートとして抜き出して各サービスで利用する(自動生成されたコードのモジュールを定義している部分など)、といったことも検討できそうです。 今回はRustを利用しましたが、gRPCが利用できれば他の言語でも可能ですのでご興味あればぜひお試しください。 デプロイ環境についてもKuberntes クラスタ ーであればどの環境でもデプロイ可能です。 microservices-demoの クイックスタート や 開発ガイド にGKEやローカルを利用する方法が載っていますので、こちらもぜひお試しください。 ここまでお読みいただきありがとうございました。 私たちは一緒に働いてくれる仲間を募集しています! 募集職種一覧 執筆: @tada.keisuke 、レビュー: @takeda.hideyuki ( Shodo で執筆されました )
アバター
こんにちは。金融ソリューション事業部の多田です。 本記事は 電通国際情報サービス Advent Calendar 2023 22日目の記事となります。 前日の記事は星野将吾さんの「 若手こそ受けておきたい!IPA システムアーキテクト試験 」でした。 はじめに microservices-demoについて productcatalogserviceをRustで実装する productcatalogserviceの内容を確認 準備 tonicについて Rustによる実装 gRPCサーバーの動作確認 EKSへのデプロイ 準備 コンテナイメージの準備 & ECRへの登録 AWS CloudShellの準備 AWS上にEKSクラスター/ノードグループを作成する microservices-demoのデプロイ 後始末 まとめ はじめに みなさん、 microservices-demo をご存知でしょうか。 Google が提供している クラウド を前提としたマイクロサービスのデモアプリケーションです。 今回はこのmicroservices-demoの一部をRust実装に置き換えて Amazon EKS(以降、EKS)にデプロイしてみました。 筆者は社内ワーキンググループの活動としてソフトウェア アーキテクチャ の技術調査などを行っており その一環としてRust/gRPC/GraphQLを用いたマイクロサービス アーキテクチャ を検討しております。 本記事はその検討にあたって実施した内容の一部をまとめたものになります。 microservices-demoについて ECサイト を模しており、商品の閲覧やカートへ入れる、購入するといったことが可能です(決済などはモックです)。 技術的には Kubernetes 、GKE、Istio、Stackdriver、gRPCなどを使用しています。 少し設定を加えればGKEなどに作成した Kubernetes クラスタ ー上にデプロイ可能となっています。 アーキテクチャ と各サービスの言語、役割は以下のようになっています。 今回はこの中の productcatalogservice をRust実装に置き換えます。 (役割は筆者の意訳です。詳細は README をご確認ください) サービス 言語 役割 frontend Go HTTPサーバ。ユーザーと直接やり取りするのはココ cartservice C# 商品の保存や取得(ショッピングカート) productcatalogservice Go 商品一覧と各商品情報(商品名、概要)の提供、検索 currencyservice Node.js 各通貨の変換 paymentservice Node.js クレジットカード(モック)で決済 shippingservice Go 送料の計算と住所(モック)への発送 emailservice Python 購入確認メール(メールアドレスはモック)の送信 checkoutservice Go カートの情報を元に注文準備や支払い、発送、メール通知を調整 recommendationservice Python カートにある商品を元に別の商品を推薦 adservice Java テキスト広告の提供 loadgenerator Python /Locust EC2の利用フローを模したリク エス トを継続的に実施(おそらく負荷テスト用) productcatalogserviceをRustで実装する productcatalogserviceの内容を確認 サービス同士の通信にはgRPCを使用しています。 Protocol Buffersは既にあるため、それを元にサービスを実装します。 demo.proto productcatalogserviceのインターフェースは以下です。 (Productなどのメッセージ定義は省略しています) service ProductCatalogService { rpc ListProducts(Empty) returns (ListProductsResponse) {} rpc GetProduct(GetProductRequest) returns (Product) {} rpc SearchProducts(SearchProductsRequest) returns (SearchProductsResponse) {} } microservices-demo上ではGoで実装されています。 コード を見てみると products.json に商品情報があり、これを元に商品一覧や各商品情報、検索機能を提供しているようです。 この実装を参考にRustで実装します。 準備 以下を参考にRustのインストールをお願いします。 https://www.rust-lang.org/ja/tools/install tonicについて tonic というクレートを使用して実装します。 tonicはRustネイティブのgRPC実装です。用途により コンポーネント が用意されており、それらを組み合わせて使用します。 今回はtonic-buildという コンポーネント を使用してprotoファイルを元にス ケルト ンとスタブを生成し、それを元にgRPCサーバーとクライアントを実装しました。 デモアプリケーション上ではクライアントは不要ですがテストのために実装しました。 tonicを利用するにはprotocのインストールが必要になります。 お使いの環境にあわせてインストールしてください。 https://github.com/hyperium/tonic?tab=readme-ov-file#dependencies Windows の場合、上記に加えてPROTOCという 環境変数 を用意しprotoc.exeへのパスを設定する必要があります。 (筆者はここで「 コンパイル できない(; ;)」と30分ほど無駄にしました) Rustによる実装 コードの全量は以下になります。 productcatalogservice 構成は以下のとおりです。 productcatalogservice |-- Cargo.toml |-- Dockerfile ... EKSへデプロイするためのイメージ作成で使用(後述) |-- build.rs ... スケルトン、スタブ生成用のコード |-- pb | |-- demo.proto ... 前述のproductcatalogserviceのインターフェースを定義 |-- products.json ... 商品情報リスト |-- src |-- client.rs ... gRPCクライアントのコード |-- server.rs ... gRPCサーバーのコード 本記事では build.rs と server.rs について解説します。 その他は実際のコードをご確認ください。 まずは build.rs です。 fn main () -> Result < (), Box < dyn std :: error :: Error >> { tonic_build :: configure () . type_attribute ( "." , "#[derive(serde::Deserialize)]" ) . type_attribute ( "." , "#[serde(rename_all = \" camelCase \" )]" ) . compile ( & [ "./pb/demo.proto" ], & [ "./pb" ]) ? ; Ok (()) } build.rs はビルド時にprotoファイルを読み込んでス ケルト ンとスタブのコードを生成します。 type_attribute(...) は生成されるス ケルト ンとスタブに属性を付与したい場合に使用します。 今回は product.json から自動生成されたコード(商品の構造体)に直接変換するため、そのための属性を付与しました。 (実開発においては直接変換ではなく間に DTO などを挟むと思います) ビルドに成功するとtarget配下にコードが生成されます。 続いて server.rs です(一部省略しています)。 // 生成されたコードの読み込み pub mod hipstershop { // demo.protoのpackageを指定 tonic :: include_proto! ( "hipstershop" ); } // 省略 #[derive( Default )] pub struct ProductCatalogServiceImpl {} // サーバ用のコードを実装 #[tonic::async_trait] impl ProductCatalogService for ProductCatalogServiceImpl { async fn list_products ( & self , _request: Request < Empty > ) -> Result < Response < ListProductsResponse > , Status > { let products = read_catalog_file ().await; let reply: ListProductsResponse = ListProductsResponse{ products: products }; Ok ( Response :: new (reply)) } async fn get_product ( & self , request: Request < GetProductRequest > ) -> Result < Response < Product > , Status > { //省略 } async fn search_products ( & self , request: Request < SearchProductsRequest > ) -> Result < Response < SearchProductsResponse > , Status > { //省略 } } #[tokio::main] async fn main () -> Result < (), Box < dyn std :: error :: Error >> { // 省略 let addr = "0.0.0.0:3550" . parse (). unwrap (); let product_catalog_service = ProductCatalogServiceImpl :: default (); println! ( "HealthServer + ProductCatalogServiceServer listening on {}" , addr); Server :: builder () . add_service (health_service) . add_service ( ProductCatalogServiceServer :: new (product_catalog_service)) . serve (addr) .await ? ; Ok (()) } pub mod hipstershop {...} では自動生成されたコードをモジュールとして定義しています。 tonic::include_proto!("hipstershop") は自動生成されたコードを読み込むためのマクロです。 引数にはprotoファイルのpackageを指定します。 impl ProductCatalogService for ProductCatalogServiceImpl {...} はサービスの実装です。 自動生成されたProductCatalogServiceトレイトを実装しています。 product.json から商品情報を読み込み、それをそのまま返したり、中身を検索したりしています。 main() はgRPCサーバーを起動するための実装です。 ポートやサービスの設定などをしています。 gRPCサーバーの動作確認 サーバーは以下のコマンドで起動します。 cargo run --bin server クライアントを実行して動作確認をしてみます。 cargo run --bin client 成功すると以下のような結果が表示されます。 RESPONSE =Response { metadata: MetadataMap { headers: { " content-type " : " application/grpc " , " date " : " Tue, 19 Dec 2023 08:02:30 GMT " , " grpc-status " : " 0 " } } , message: ListProductsResponse { products: [ Product { id: " OLJCESPC7Z " , name: " Sunglasses " , description: " Add a modern touch to your outfits with these sleek aviator sunglasses. " , picture: " /static/img/products/sunglasses.jpg " , price_usd: Some ( Money { currency_code: " USD " , units: 19 , nanos: 990000000 } ) , ...省略 これでRustによる実装ができましたので、次はEKSへデプロイします。 EKSへのデプロイ 準備 EKSへデプロイするために AWS アカウントの作成と AWS CLI のインストール、認証情報の設定をしてください。 また、イメージ作成にはDockerを使用しますのでお使いの環境にあわせてインストールしてください。 https://docs.docker.jp/desktop/install.html コンテナイメージの準備 & ECRへの登録 EKSへデプロイするためにproductcatalogserviceのイメージを作成しECRへイメージを登録します。 まず以下を参考に AWS コンソールからECRにプライベー トリポジ トリを作成します( リポジトリ 名はproductcatalogservice)。 https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/repository-create.html 次にイメージを作成しECRへpushするため、以下のコマンドを実行します。 AWS のアカウント番号は適宜置き換えてください。 リージョンは東京リージョンにしています。 # イメージ作成 docker build -t productcatalogservice . # タグ付けする docker tag productcatalogservice:latest < AWSのアカウント番号 > .dkr.ecr.ap-northeast-1.amazonaws.com/productcatalogservice:latest # dockerクライアントの認証 aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin < AWSのアカウント番号 > .dkr.ecr.ap-northeast-1.amazonaws.com # push docker push < アカウント番号 > .dkr.ecr.ap-northeast-1.amazonaws.com/productcatalogservice:latest AWS CloudShellの準備 EKSへのデプロイには AWS CloudShellを利用します。 まずはkubectlを使えるようにします。 kubectlは kubernetes 用の コマンドライン ツールです。 マイクロサービスのデプロイに使用します。 curl -O https://s3.us-west-2.amazonaws.com/amazon-eks/ 1 . 28 . 3 /2023-11-14/bin/linux/amd64/kubectl chmod +x ./kubectl mkdir -p $HOME /bin && cp ./kubectl $HOME /bin/kubectl && export PATH = $PATH : $HOME /bin echo ' export PATH=$PATH:$HOME/bin ' >> ~/.bashrc kubectl version --client 続いてeksctlを使えるようにします。 eksctlはEKS上で Kubernetes クラスタ ーを作成・管理するための コマンドライン ツールです。 curl --silent --location " https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_ $( uname -s ) _amd64.tar.gz " | tar xz -C /tmp sudo mv /tmp/eksctl /usr/local/bin eksctl version AWS 上にEKS クラスタ ー/ノードグループを作成する 以下のコマンドで クラスタ ーを作成できます(10分ほどで完了します)。 name は onlineboutique 、 region は東京リージョンとしています。 eksctl create cluster --name onlineboutique --region ap-northeast-1 --without-nodegroup クラスタ ーの作成が完了したらノードグループを作成します(2分ほどで完了します)。 cluster は onlineboutique 、ノード数は4としています。 eksctl create nodegroup --cluster onlineboutique --region ap-northeast-1 --nodes 4 --nodes-min 4 --nodes-max 4 microservices-demoのデプロイ クラスタ ーが作成できたらいよいよデプロイです。 microservices-demoをクローンし、ECRへpushしたイメージを使うよう マニフェスト を修正します。 ★でproductcatalogserviceの image を以下のように修正してください。 修正前: gcr.io/ google -samples/microservices-demo/productcatalogservice:<バージョン> 修正後:<アカウント番号>.dkr.ecr.ap-northeast-1.amazonaws.com/productcatalogservice:latest その後、 kubectl apply でデプロイします。 # microservices-demoをクローン git clone https://github.com/GoogleCloudPlatform/microservices-demo.git # リポジトリへ移動 cd microservices-demo # 書き換え(★) vi ./release/kubernetes-manifests.yaml # デプロイ kubectl apply -f ./release/kubernetes-manifests.yaml サービスの一覧を確認するとfrontendにELBの DNS 名が割り当てられています。 kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT ( S ) AGE adservice ClusterIP 10 . 100 . 8 . 99 < none > 9555 /TCP 2m34s cartservice ClusterIP 10 . 100 . 167 . 3 < none > 7070 /TCP 2m35s checkoutservice ClusterIP 10 . 100 . 155 . 33 < none > 5050 /TCP 2m35s currencyservice ClusterIP 10 . 100 . 81 . 172 < none > 7000 /TCP 2m34s emailservice ClusterIP 10 . 100 . 116 . 249 < none > 5000 /TCP 2m35s frontend ClusterIP 10 . 100 . 23 . 148 < none > 80 /TCP 2m35s frontend-external LoadBalancer 10 . 100 . 167 . 89 a0f6456281124412b8f095f94c6e242a-2020525330.ap-northeast-1.elb.amazonaws.com 80:31538/TCP 2m35s kubernetes ClusterIP 10 . 100 . 0 . 1 < none > 443 /TCP 17m paymentservice ClusterIP 10 . 100 . 154 . 183 < none > 50051 /TCP 2m35s productcatalogservice ClusterIP 10 . 100 . 20 . 37 < none > 3550 /TCP 2m35s recommendationservice ClusterIP 10 . 100 . 90 . 209 < none > 8080 /TCP 2m35s redis-cart ClusterIP 10 . 100 . 32 . 58 < none > 6379 /TCP 2m34s shippingservice ClusterIP 10 . 100 . 194 . 29 < none > 50051 /TCP 2m34s ブラウザでアクセスして画像のような画面が表示されれば成功です。 後始末 削除は以下の順でコマンドを実行します。 グループ名はマネジメントコンソールなどでご確認ください。 # podを削除 kubectl delete -f ./release/kubernetes-manifests.yaml # ノードグループを削除 eksctl delete nodegroup --cluster=onlineboutique --region ap-northeast-1 --name=<グループ名> --wait # クラスターを削除 eksctl delete cluster --name onlineboutique --region ap-northeast-1 --wait まとめ Google が提供しているmicroservices-demoの一部をRustに置き換えてEKSにデプロイしてみました。 tonicを用いることで簡単にRustで実装できました。 他のサービスもRustで置き換える場合、共通部分をライブラリクレートとして抜き出して各サービスで利用する(自動生成されたコードのモジュールを定義している部分など)、といったことも検討できそうです。 今回はRustを利用しましたが、gRPCが利用できれば他の言語でも可能ですのでご興味あればぜひお試しください。 デプロイ環境についてもKuberntes クラスタ ーであればどの環境でもデプロイ可能です。 microservices-demoの クイックスタート や 開発ガイド にGKEやローカルを利用する方法が載っていますので、こちらもぜひお試しください。 ここまでお読みいただきありがとうございました。 私たちは一緒に働いてくれる仲間を募集しています! 募集職種一覧 執筆: @tada.keisuke 、レビュー: @takeda.hideyuki ( Shodo で執筆されました )
アバター
こんにちは。金融ソリューション事業部の星野です。 本記事は 電通国際情報サービス Advent Calendar 2023 21日目の記事となります。 今回は、 IPA の システムアーキテクト 試験を若手エンジニアが受験することの意義について、受験体験と共にお話させて頂きます。 1. IPA システムアーキテクト試験(SA試験)とは 1.1 SA試験の概要 1.2. 試験内容 2. 私の受験勉強内容の概要 2.1. 私の前提知識・経験 2.2. 勉強した内容について 3. 若手エンジニアが受けて良かったこと 3.1. 若手エンジニアが直面する試験の壁 3.2. 若手鬼門の午後II 3.3. 若手が試験勉強を通して得られること 4. まとめ 1. IPA システムアーキテクト 試験(SA試験)とは 1.1 SA試験の概要 応用情報技術者試験 の上位である、「高度試験」などと呼ばれる区分に属する試験です。 同じ区分には データベーススペシャリスト 、 ネットワークスペシャリスト なども含まれます。 参考: IPA試験区分 IPAのSA試験概要ページ をご覧頂くと、試験で求められるスキルについて確認できますが、ざっくり言ってしまうと要件定義や設計といった工程のスキルが試される試験です。 1.2. 試験内容 試験の内容は以下4つで構成されており、試験日当日は上から実施されます。 午前I 選択式解答 AP試験の午前試験と分野、難易度共に同等の内容。 受験免除対象であったため( 詳細はこちら )、私は受けていません。 午前II 選択式解答 APの午前試験よりやや難しい内容が問われているはずですが、難易度は大きく変わらない感覚。 出題分野は以下のとおりで、午前Iと比べて技術系がやや多めの割合となる。 コンピュータシステム(コンピュータ構成要素、システム要素) 技術要素(DB、NW、セキュリティ) 開発技術( システム開発 技術、ソフトウェア開発管理技術) システム戦略 午後I 記述式解答 APの午後試験と同形式 問題文に記載されているシステムや業務上の課題に対し、どのようにシステム設計すれば課題解決ができるかを問に沿って解答していく。 午後II 小論文 受験者の経験に基づき、問題文記載のお題に沿って、システム構築で工夫したことを述べる。 2. 私の受験勉強内容の概要 2.1. 私の前提知識・経験 以下のような前提知識・経験を持った状態で受験しました。 ご覧の通り、 下流 工程中心の経験となっており、SA試験の対象工程の経験は十分とは言えない状況です。 ISID 新卒4年目 経験してきた工程:プログラミング、UT、オンプレ-> クラウド 移行対応のアプリ関連作業内容策定・実施 バッチで動作するバックエンドシステムのコーディング/UT CI/CD実装 簡単な詳細設計 クラウド 移行、リージョン切替対応に伴うアプリ改修方針検討と作業(インフラ領域も多少含む) 簡単な 結合テスト 経験案件数:2つ 保有 資格 基本情報技術者試験 応用情報技術者試験 AWS ソリューションアーキテクト アソシエイト 2.2. 勉強した内容について 今回、合格するための勉強方法について説明する趣旨ではないため、簡単に記載します。 合否 1回目受験:午後IIがC評価(内容が不十分である、問題文の趣旨から逸脱している)で不合格 2回目受験:合格 この試験のための勉強時間 土日を隔週弱ペース 勉強した日は2,3h勉強 期間としては1回目受験4ヶ月, 2回目受験2ヶ月程 使用した参考書 システムアーキテクト 「専門知識+午後問題」の重点対策 システムアーキテクト 合格論文の書き方・事例集 3. 若手エンジニアが受けて良かったこと 3.1. 若手エンジニアが直面する試験の壁 私のような経験の浅いエンジニアはSA試験に当たって以下の壁にぶち当たります。 1. 要件定義・基本設計の経験が無い 2. 経験案件数が少なく午後IIの論述ネタがない 「1.」については、ひたすら午後Iの過去問演習を積むことが効果的です。 問題文に記載されている各課題を解消するに当たって、どのような設計にすべきであるかを導き出すことができる力を問題演習を通じて身に付ければ、試験に太刀打ちできると考えます。 知識という観点では、 応用情報技術者試験 相当の知識があれば十分で、プラスで必要な知識については過去問演習で足りると思っています。 「2.」が若手エンジニアにとって鬼門となります。 問題文を 過去問ページ でご覧いただくと分かると思うのですが、問題文記載のお題に沿ったシステム構築の経験について、アーキテクトとして工夫したことを小論文で述べなければなりません。 例として私が2回目受験した際の問題文を以下に記載します。 近年、企業においては競争優位の獲得や企業自身の存続のために、デジタルトランスフォーメーション(DX)を推進することが増えている。しかし、DXの推進に必要な情報が整備されていないなどの課題が原因で、推進が困難になる場合も多い。 そのため、 システムアーキテクト は、課題を解決してDXの推進を支援する必要がある。このような課題には例えば、次のようなものがある。 <中略:POS情報を活用したビジネスを可能にするDXについての例が問題文中に記載> 設問ア あなたが携わったDXの推進では、どのような課題があったか。DXの目的と情報システムの概要を含め、800字以内で述べよ。 設問イ 設問アで述べた課題の解決のために、情報システムをどのように改善しようとしたか。解決できると考えた理由を含め、800字以上 1,600字以内で具体的に述べよ。 設問ウ 設問イで述べた情報システムの改善において、何のためにどのような工夫を検討したか。600字以上 1,200字以内で具体的に述べよ。 引用・抜粋:令和5年度 春期 システムアーキテクト 試験 午後II 問1 これを見て、「あ、あの案件のこと書けるぞ」と思う若手エンジニアは少ないと思います。 前述の通り、私は二度目の受験で合格しており、一度目の不合格要因は午後IIの小論文不合格でした。 評価ランクはCであり、問題文に沿った小論文ネタではなかったことが大きな要因であったと考えられます。 (細かいレビュー等は試験後に返ってこないので推測です) この点については、3.2.にて詳細を記載します。 3.2. 若手鬼門の午後II 前述の問題文を見ていただくと、案件を多く経験していない若手エンジニアにとって、自身の経験のみでお題に沿ったシステム構築の経験に基づく小論文を書くことはとても困難であるのはお分かり頂けると思います。 そこで以下のような学習で乗り越える必要があります。 1. 様々な案件事例と設計上の工夫点について学習 2. 自身の経験と1.の学習内容を問題文にあわせて変換する力を養う まず「1.」については、午後II対策用の小論文事例が多く掲載された参考書を通して学習するのがおすすめです。 内容を理解して大方の内容を頭にインプットし、疑似的にその案件に携わった状態を自分自身に作り出すイメージで学習することが効果的です。 注意したいのが丸暗記は良くないということです。 システム構築で生じるありがちな課題の理解とそれに対応する設計上の工夫について、内容をきちんと理解することで、参考書に出てこなかったような問題への対応が可能になります。 加えて、学習量の面も重要で、多くの事例のインプットが出来ていればそれだけ本番の問題への対応力もあがります。 次に「2.」についてです。 これは参考書ではなく、実際の過去問演習を通じて養う必要があります。 参考書通りの問題が本番に出題されることはほぼ有り得ません。 自身の経験と「1.」のインプット内容を基に、問題文にあわせてあたかもそのようなシステムを構築した経験があるかのように小論文を書く力が必要です。 これは過去問演習でしか鍛えられないものになります。 また 下流 工程のみの経験しかない若手でも「この課題について、こんな仕様の機能追加で解決した」という工夫点を論述するにあたり、自身の経験は十分使えるネタとなります。 過去問演習ではこの点も意識すると、試験本番への対応力がグッと増すでしょう。 3.3. 若手が試験勉強を通して得られること 既に上記に記載したことの裏返しではありますが、試験勉強を通して得られることは以下です。 1. 業務上・システムの課題を要件定義・設計に反映させる力 2. 将来上流工程に携わる前の予行練習 3. 下流 工程担当としての視座の向上 「1.」についてはこの試験で問われる力そのものの向上と言えます。 この試験を通して課題 => 要件定義・設計の考え方を午後試験を通して身に付けることができます。 若手エンジニアは 下流 工程中心で業務する人も多く、そのような人にとってはこの試験は難しい部類に入ると思います。 逆にとらえれば業務上得られない力をこの試験を通して養うことができることは大きいメリットだと言えます。 その点で「2.」のように、将来、要件定義・設計に携わることを考えているエンジニアにとっては、この試験は予行練習の役割を果たしてくれるといえます。 もちろん、実務を通したト レーニン グに比べれば試験勉強のト レーニン グ力は劣ります。 しかし、ゼロから要件定義・設計に携わるよりも、この試験を受けた後に携わるほうがその後の成長スピードは良いのではないかと考えています。 また、 下流 工程中心で今後も働き続ける人にとってもメリットはあると考えられます。 上流工程の人の考え方を学ぶことで、上流工程担当者とのコミュニケーションも取りやすくなると言えます。 また、試験を通じて「業務課題理解」の大切さを学ぶことができ、日ごろのコーディングにおいても、その機能を使う人の立ち位置に立った適切な仕様を考えるにあたり生きるものがあると考えます。 4. まとめ システムアーキテクト 試験の受験は、経験が比較的浅い若手エンジニアにとっては難易度が高いものと言えます。 ただその対価として得られるものとしてはそれなりのものがあり、業務上・システムの課題を設計に反映させる力を養うことができると言えます。 これは私の個人的な意見ですが、要件定義・設計の工程はシステムの良し悪しを大きく左右するポイントではないかと考えており、この試験を通して要件定義・設計に必要な考え方を学ぶ意義は大きいとも考えます。 仮に受験者が プログラマー の役割であったとしても、設計の考え方を身に付けることで業務に寄り添った仕様のコーディングに役立てることができると考えます。 また、将来上流工程に携わりたい人にとっては特におすすめで、経験ゼロでそのロールを担う際に試験で養った考え方はスタート ダッシュ に効果を発揮すると考えられます。 資格試験はあえて背伸びして受験することで、自分の経験値にプラスアルファできることが旨みであると考えています。 システムアーキテクト としての経験がない方こそ、この試験の受験を強くおススメします。 執筆: @hoshino.shogo 、レビュー: @fukutake.hiroaki ( Shodo で執筆されました )
アバター
こんにちは。金融ソリューション事業部の星野です。 本記事は 電通国際情報サービス Advent Calendar 2023 21日目の記事となります。 今回は、 IPA の システムアーキテクト 試験を若手エンジニアが受験することの意義について、受験体験と共にお話させて頂きます。 1. IPA システムアーキテクト試験(SA試験)とは 1.1 SA試験の概要 1.2. 試験内容 2. 私の受験勉強内容の概要 2.1. 私の前提知識・経験 2.2. 勉強した内容について 3. 若手エンジニアが受けて良かったこと 3.1. 若手エンジニアが直面する試験の壁 3.2. 若手鬼門の午後II 3.3. 若手が試験勉強を通して得られること 4. まとめ 1. IPA システムアーキテクト 試験(SA試験)とは 1.1 SA試験の概要 応用情報技術者試験 の上位である、「高度試験」などと呼ばれる区分に属する試験です。 同じ区分には データベーススペシャリスト 、 ネットワークスペシャリスト なども含まれます。 参考: IPA試験区分 IPAのSA試験概要ページ をご覧頂くと、試験で求められるスキルについて確認できますが、ざっくり言ってしまうと要件定義や設計といった工程のスキルが試される試験です。 1.2. 試験内容 試験の内容は以下4つで構成されており、試験日当日は上から実施されます。 午前I 選択式解答 AP試験の午前試験と分野、難易度共に同等の内容。 受験免除対象であったため( 詳細はこちら )、私は受けていません。 午前II 選択式解答 APの午前試験よりやや難しい内容が問われているはずですが、難易度は大きく変わらない感覚。 出題分野は以下のとおりで、午前Iと比べて技術系がやや多めの割合となる。 コンピュータシステム(コンピュータ構成要素、システム要素) 技術要素(DB、NW、セキュリティ) 開発技術( システム開発 技術、ソフトウェア開発管理技術) システム戦略 午後I 記述式解答 APの午後試験と同形式 問題文に記載されているシステムや業務上の課題に対し、どのようにシステム設計すれば課題解決ができるかを問に沿って解答していく。 午後II 小論文 受験者の経験に基づき、問題文記載のお題に沿って、システム構築で工夫したことを述べる。 2. 私の受験勉強内容の概要 2.1. 私の前提知識・経験 以下のような前提知識・経験を持った状態で受験しました。 ご覧の通り、 下流 工程中心の経験となっており、SA試験の対象工程の経験は十分とは言えない状況です。 ISID 新卒4年目 経験してきた工程:プログラミング、UT、オンプレ-> クラウド 移行対応のアプリ関連作業内容策定・実施 バッチで動作するバックエンドシステムのコーディング/UT CI/CD実装 簡単な詳細設計 クラウド 移行、リージョン切替対応に伴うアプリ改修方針検討と作業(インフラ領域も多少含む) 簡単な 結合テスト 経験案件数:2つ 保有 資格 基本情報技術者試験 応用情報技術者試験 AWS ソリューションアーキテクト アソシエイト 2.2. 勉強した内容について 今回、合格するための勉強方法について説明する趣旨ではないため、簡単に記載します。 合否 1回目受験:午後IIがC評価(内容が不十分である、問題文の趣旨から逸脱している)で不合格 2回目受験:合格 この試験のための勉強時間 土日を隔週弱ペース 勉強した日は2,3h勉強 期間としては1回目受験4ヶ月, 2回目受験2ヶ月程 使用した参考書 システムアーキテクト 「専門知識+午後問題」の重点対策 システムアーキテクト 合格論文の書き方・事例集 3. 若手エンジニアが受けて良かったこと 3.1. 若手エンジニアが直面する試験の壁 私のような経験の浅いエンジニアはSA試験に当たって以下の壁にぶち当たります。 1. 要件定義・基本設計の経験が無い 2. 経験案件数が少なく午後IIの論述ネタがない 「1.」については、ひたすら午後Iの過去問演習を積むことが効果的です。 問題文に記載されている各課題を解消するに当たって、どのような設計にすべきであるかを導き出すことができる力を問題演習を通じて身に付ければ、試験に太刀打ちできると考えます。 知識という観点では、 応用情報技術者試験 相当の知識があれば十分で、プラスで必要な知識については過去問演習で足りると思っています。 「2.」が若手エンジニアにとって鬼門となります。 問題文を 過去問ページ でご覧いただくと分かると思うのですが、問題文記載のお題に沿ったシステム構築の経験について、アーキテクトとして工夫したことを小論文で述べなければなりません。 例として私が2回目受験した際の問題文を以下に記載します。 近年、企業においては競争優位の獲得や企業自身の存続のために、デジタルトランスフォーメーション(DX)を推進することが増えている。しかし、DXの推進に必要な情報が整備されていないなどの課題が原因で、推進が困難になる場合も多い。 そのため、 システムアーキテクト は、課題を解決してDXの推進を支援する必要がある。このような課題には例えば、次のようなものがある。 <中略:POS情報を活用したビジネスを可能にするDXについての例が問題文中に記載> 設問ア あなたが携わったDXの推進では、どのような課題があったか。DXの目的と情報システムの概要を含め、800字以内で述べよ。 設問イ 設問アで述べた課題の解決のために、情報システムをどのように改善しようとしたか。解決できると考えた理由を含め、800字以上 1,600字以内で具体的に述べよ。 設問ウ 設問イで述べた情報システムの改善において、何のためにどのような工夫を検討したか。600字以上 1,200字以内で具体的に述べよ。 引用・抜粋:令和5年度 春期 システムアーキテクト 試験 午後II 問1 これを見て、「あ、あの案件のこと書けるぞ」と思う若手エンジニアは少ないと思います。 前述の通り、私は二度目の受験で合格しており、一度目の不合格要因は午後IIの小論文不合格でした。 評価ランクはCであり、問題文に沿った小論文ネタではなかったことが大きな要因であったと考えられます。 (細かいレビュー等は試験後に返ってこないので推測です) この点については、3.2.にて詳細を記載します。 3.2. 若手鬼門の午後II 前述の問題文を見ていただくと、案件を多く経験していない若手エンジニアにとって、自身の経験のみでお題に沿ったシステム構築の経験に基づく小論文を書くことはとても困難であるのはお分かり頂けると思います。 そこで以下のような学習で乗り越える必要があります。 1. 様々な案件事例と設計上の工夫点について学習 2. 自身の経験と1.の学習内容を問題文にあわせて変換する力を養う まず「1.」については、午後II対策用の小論文事例が多く掲載された参考書を通して学習するのがおすすめです。 内容を理解して大方の内容を頭にインプットし、疑似的にその案件に携わった状態を自分自身に作り出すイメージで学習することが効果的です。 注意したいのが丸暗記は良くないということです。 システム構築で生じるありがちな課題の理解とそれに対応する設計上の工夫について、内容をきちんと理解することで、参考書に出てこなかったような問題への対応が可能になります。 加えて、学習量の面も重要で、多くの事例のインプットが出来ていればそれだけ本番の問題への対応力もあがります。 次に「2.」についてです。 これは参考書ではなく、実際の過去問演習を通じて養う必要があります。 参考書通りの問題が本番に出題されることはほぼ有り得ません。 自身の経験と「1.」のインプット内容を基に、問題文にあわせてあたかもそのようなシステムを構築した経験があるかのように小論文を書く力が必要です。 これは過去問演習でしか鍛えられないものになります。 また 下流 工程のみの経験しかない若手でも「この課題について、こんな仕様の機能追加で解決した」という工夫点を論述するにあたり、自身の経験は十分使えるネタとなります。 過去問演習ではこの点も意識すると、試験本番への対応力がグッと増すでしょう。 3.3. 若手が試験勉強を通して得られること 既に上記に記載したことの裏返しではありますが、試験勉強を通して得られることは以下です。 1. 業務上・システムの課題を要件定義・設計に反映させる力 2. 将来上流工程に携わる前の予行練習 3. 下流 工程担当としての視座の向上 「1.」についてはこの試験で問われる力そのものの向上と言えます。 この試験を通して課題 => 要件定義・設計の考え方を午後試験を通して身に付けることができます。 若手エンジニアは 下流 工程中心で業務する人も多く、そのような人にとってはこの試験は難しい部類に入ると思います。 逆にとらえれば業務上得られない力をこの試験を通して養うことができることは大きいメリットだと言えます。 その点で「2.」のように、将来、要件定義・設計に携わることを考えているエンジニアにとっては、この試験は予行練習の役割を果たしてくれるといえます。 もちろん、実務を通したト レーニン グに比べれば試験勉強のト レーニン グ力は劣ります。 しかし、ゼロから要件定義・設計に携わるよりも、この試験を受けた後に携わるほうがその後の成長スピードは良いのではないかと考えています。 また、 下流 工程中心で今後も働き続ける人にとってもメリットはあると考えられます。 上流工程の人の考え方を学ぶことで、上流工程担当者とのコミュニケーションも取りやすくなると言えます。 また、試験を通じて「業務課題理解」の大切さを学ぶことができ、日ごろのコーディングにおいても、その機能を使う人の立ち位置に立った適切な仕様を考えるにあたり生きるものがあると考えます。 4. まとめ システムアーキテクト 試験の受験は、経験が比較的浅い若手エンジニアにとっては難易度が高いものと言えます。 ただその対価として得られるものとしてはそれなりのものがあり、業務上・システムの課題を設計に反映させる力を養うことができると言えます。 これは私の個人的な意見ですが、要件定義・設計の工程はシステムの良し悪しを大きく左右するポイントではないかと考えており、この試験を通して要件定義・設計に必要な考え方を学ぶ意義は大きいとも考えます。 仮に受験者が プログラマー の役割であったとしても、設計の考え方を身に付けることで業務に寄り添った仕様のコーディングに役立てることができると考えます。 また、将来上流工程に携わりたい人にとっては特におすすめで、経験ゼロでそのロールを担う際に試験で養った考え方はスタート ダッシュ に効果を発揮すると考えられます。 資格試験はあえて背伸びして受験することで、自分の経験値にプラスアルファできることが旨みであると考えています。 システムアーキテクト としての経験がない方こそ、この試験の受験を強くおススメします。 私たちは一緒に働いてくれる仲間を募集しています! 電通総研中途採用ページ 電通総研新卒採用ページ 執筆: @hoshino.shogo 、レビュー: @fukutake.hiroaki ( Shodo で執筆されました )
アバター
こんにちは。 XI 本部 AI トランスフォーメンションセンター 所属の後藤です。 本記事は「 電通国際情報サービス Advent Calendar 2023 」の12月 20日 (水)の回の記事になります。 本記事では、つい先日利用が可能となったAzureの「GPT-4 Turbo with Vision 」の紹介と使い方の解説をします。 使ってみた所感として、今回のAzure版GPT-4 Turbo with Vision は単なるOpenAIの機能の追随に留まらず、Azure固有の追加機能である「 Vision enhancement」が印象的でした。特に、画像や動画の扱いにおいて、OpenAIのモデルよりも応用範囲が大きく広がっていることが感じられました。 OpenAIのGPT-4Vに関してはTechBlogの以下の記事でも紹介されていますので、ぜひご参照ください。 参考: https://tech.isid.co.jp/entry/explaination_gpt4v 使用準備 Azure OpenAI Studio からの利用 Azure AI Visionを使ったVision enhancementを有効にする REST APIから使ってみる Azure とOpenAI のGPT-4 Turbo with Visionの違い まとめ 使用準備 現在、GPT-4 Turbo with Vision の利用可能なリージョンはAustralia East、Sweden Central、Switzerland North、West USの4つです。 上記4つのリージョンのいずれかにAzure OpenAI Serviceのリソースを作成します。 価格は トーク ンベースの計算になり、基本的にはOpenAI のGPT-4 Turbo with Vision と計算方法は一緒ですが、細部は異なるようです。 モデル コンテキスト 入力(1,000 トーク ンあたり) 出力(1,000 トーク ンあたり) GPT-4 Turbo with Vision 128k $0.01 $0.03 GPT-4 32K $0.06 $0.12 参考までにGPT-4の価格を載せましたが、コンテキスト長も増えて料金が1/6に下がったのは非常に嬉しいですね。 参考: GPT-4 Turbo with Vision is now available on Azure OpenAI Service! 画像を扱う際には低解像度と高解像度の2つのモードがあり、設定はlow, high, autoの3つがありデフォルト設定ではautoになっています。低解像度の場合は画像サイズによらず固定で85 トーク ンがプラスされます。高解像度の場合は画像を拡大縮小して512 ピクセル の正方形タイルに切り出してその数かける170 トーク ン+85 トーク ンで計算されます。 以下はAzureの記事内で紹介されていた計算例です。 例:2048 x 4096画像(高詳細) 最初に1024 x 2048にサイズ変更して、2048の正方形に収める。 さらに768 x 1536にサイズ変更。 カバーするために6つの512pxタイルが必要。 合計コストは170 × 6 + 85 = 1105 トーク ンです。 参考: What is Azure OpenAI Service? - Azure AI services Detail parameter settings in image processing: Low, High, Auto Azure OpenAI Studio からの利用 以下のようにモデルのデプロイができたら早速 Azure OpenAI Studioのプレイグラウンドから利用してみます。 デプロイしたgpt-4の vision - preview モデルを選択して簡単な画像のプロンプトを入力してみます。 画像を認識できない旨の内容が返ってきます。次は英語で書いてみます。 レスポンスから画像内容をしっかり理解していることがわかります。以下はレスポンスの翻訳内容です。 この画像は、青空とわずかな白い雲の下にある鮮やかなひまわり畑を映しています。ひまわりは大きく、明るい黄色の花びらと濃い茶色の中心を持っています。満開で、太陽に向かって上を向いているように見えます。全体的な印象は、晴れやかで陽気な夏の日のものです。 色々試しましたが、日本語だとプレイグラウンドではうまく動かないことが多いです。後述する REST API なら日本語でも安定して動作します。 Azure AI Vision を使った Vision enhancementを有効にする Azure のGPT-4 Turbo with Vision では本家OpenAIにはない特徴として、Azure の Computer Vision (※ portal 上のリソース名)を組み合わせることができます。 この組み合わせは非常に強力な機能で、例えばOpenAIのGPT-4では苦手とされていた画像関連のタスクを、Azure AI Vision と組み合わせることで効果的に処理することが可能になります 例えば、本家のGPT-4では日本語の OCR 精度はかなり低くとても実利用できるものではなかったのですが、 Vision enhancementを有効にすると日本語に関しても正確に読み取ってくれます。 Vision enhancementを有効にしてできることは以下のとおりです。 OCR 物体のタグ付けと バウンディ ングボックスの表示 動画入力 Azure AI Searchと組み合わせた画像検索 ※ こちらは本記事では紹介しません 参考: GPT-4 Turbo with Vision is now available on Azure OpenAI Service! Vision enhancementを有効化するにはAzure のGPT-4 Turbo with Vision と同じリージョンにAzure Computer Vision のリソースを作成します。価格はS1にします(価格がS1の場合のみ組み合わせが可能)。 プレイグラウンドでは右側のパネルよりビジョンのトグルを有効化し、先ほどのリソースを選択するとチャットセッションで Vision enhancementが有効化されます。 以下はDALL-Eで作成した動物が複数いる画像の詳細情報を要求した時のレスポンスです。 入力画像に バウンディ ングボックスとタグが付与され、出力されたテキストの内の単語とリンクするようになっています。かなり正確に位置を検出できていることがわかります。 動画の入力もやってみました。グーチョキパーを連続で出す動画です。 レスポンスの日本語訳です。 動画は、キーボードの上で人の手がさまざまな ジェスチャー を行う一連のシーンを映しているようです。 ジェスチャー には、手が平らに置かれている様子、 ピースサイン 、開いた手、握りこぶし、そしてタイピングをしている手があり、この一連が繰り返されています。この動画は、キーボードを使用する際に行うかもしれない様々な手の位置とアクションを示しており、恐らく指導目的や ユーザーインターフェース のデモンストレーションのためのものでしょう。 キーボードの上で行ったのでそれが誤解を与えてしまっていますが、行った ジェスチャー は正しく読み取れています。 REST API から使ってみる 現時点では API から使用した方が安定した回答を得られます。 こちらは日本語のプロンプトでも動作しました。 通常のGPT-4 Turbo with Vision のリク エス トボディは以下のような形になります。画像部分はURLか base64 エンコーディング された形式になります。 { " messages ": [ { " role ": " system ", " content ": " あなたは役に立つAIアシスタントです " } , { " role ": " user ", " content ": [ " 画像を説明して: ", { " image ": encoded_string } ] } ] , " max_tokens ": 300 , " stream ": False } 続いて Vision enhancementを使う場合です。 Vision enhancementを使う場合のエンドポイントはただのGPT-4 Turbo with Vision とは異なるので注意です。 通常: https://{RESOURCE_NAME}.openai.azure.com/openai/deployments/{DEPLOYMENT_NAME}/chat/completions?api-version=2023-12-01-preview 拡張機能 : https://{RESOURCE_NAME}.openai.azure.com/openai/deployments/{DEPLOYMENT_NAME}/extensions/chat/completions?api-version=2023-12-01-preview 参考: How to use the GPT-4 Turbo with Vision model - Azure OpenAI Service 以下が Vision enhancementのリク エス トボディです。 enhancements と dataSources という項目が新たに加わります。 { " enhancements ": { " ocr ": { " enabled ": True } , " grounding ": { " enabled ": True } } , " dataSources ": [ { " type ": " AzureComputerVision ", " parameters ": { " endpoint ": ai_vision_endpoint, " key ": ai_vision_key } }] , " messages ": [ { " role ": " system ", " content ": " あなたは役に立つAIアシスタントです。回答は日本語でお願いします。 " } , { " role ": " user ", " content ": [ " 画像内の文字を書き起こして: ", { " image ": encoded_string } ] } ] , " max_tokens ": 500 , " stream ": False } 試しに手書き文字の書き起こしをやってみました。 入力画像は以下のような日本語の手書き文字です。 以下のような結果が返ってきました。(レスポンスの一部抜粋) 'model': 'gpt-4', 'choices': [{'finish_details': {'type': 'stop', 'stop': '<|fim_suffix|>'}, 'index': 0, 'message': {'role': 'assistant', 'content': '画像内の文字は「 電通国際情報サービス 」となっています。'}}], 'usage': {'prompt_tokens': 925, 'completion_tokens': 24, 'total_tokens': 949}} 正確に読み取れていることがわかります。ただ トーク ンの消費量は多くなってしまいますね。 ちなみに本家OpenAIのChatGPTに同様の手書き文字を読み取らせると 画像内の文字は「高温注意報」と書かれています。 というレスポンスが返ってくるのでAzure の Vision enhancementの有用性がわかります。 Azure とOpenAI のGPT-4 Turbo with Vision の違い 大きな違いはやはりAzure AI Vision を使用した Vision enhancementの有無です。 以下のスライドは同僚の太田さんが動画像マルチモーダルLLMの研究動向について調査したものです。その中でGPT-4Vで困難なタスクの例が論文を元に紹介されています。 参考: マルチモーダルLLMの応用動向の論文調査 調査の中で難しいとされていた「日本語 OCR 」、「画像内の物体位置座標の生成」に関してはGPT-4 Turbo with Vision とAzure独自の Vision enhancementの組み合わせにより実現できました。また、OpenAIの方では動画入力はできませんが、Azureでは可能になります。 まとめ 本記事では、Azure上で新たに利用可能となった「GPT-4 Turbo with Vision 」の特徴とその使い方を紹介しました。また、Azureが提供する独自の Vision enhancementとの組み合わせ方法とその使い方についても解説しました。 今回特に注目すべき点は、AzureがOpenAIの基本的な機能に加えて、独自のカスタマイズや 拡張機能 を提供したことです。これにより、ユーザーはOpenAIのGPT-4を利用するだけでなく、自分たちのニーズに合わせてより柔軟にシステムをカスタマイズできます。 また記事中でも言及しましたがAzure OpenAI Studioのプレイグラウンドはまだあまり安定していない印象をうけました。英語でプロンプトを作成したとしても、画像の内容を一回で返答してくれないことや、 Vision enhancementがトリガーされないことが多々ありました。 もし現時点でAzureのGPT-4 Turbo with Vision の機能を一通り試すなら REST API から試すのがおすすめです。 本記事の内容が何かの参考になれば幸いです。 最後に私が所属するAIトランスフォーメーションセンターでもAIに関するコラムを多数記載しておりますのでそちらも是非ご参照ください。 参考: AIトランスフォーメーションセンターコラム 執筆: @goto.yuki 、レビュー: @yamada.y ( Shodo で執筆されました )
アバター
こんにちは。 XI 本部 AI トランスフォーメンションセンター 所属の後藤です。 本記事は「 電通国際情報サービス Advent Calendar 2023 」の12月 20日 (水)の回の記事になります。 本記事では、つい先日利用が可能となったAzureの「GPT-4 Turbo with Vision 」の紹介と使い方の解説をします。 使ってみた所感として、今回のAzure版GPT-4 Turbo with Vision は単なるOpenAIの機能の追随に留まらず、Azure固有の追加機能である「 Vision enhancement」が印象的でした。特に、画像や動画の扱いにおいて、OpenAIのモデルよりも応用範囲が大きく広がっていることが感じられました。 OpenAIのGPT-4Vに関してはTechBlogの以下の記事でも紹介されていますので、ぜひご参照ください。 参考: https://tech.isid.co.jp/entry/explaination_gpt4v 使用準備 Azure OpenAI Studio からの利用 Azure AI Visionを使ったVision enhancementを有効にする REST APIから使ってみる Azure とOpenAI のGPT-4 Turbo with Visionの違い まとめ 使用準備 現在、GPT-4 Turbo with Vision の利用可能なリージョンはAustralia East、Sweden Central、Switzerland North、West USの4つです。 上記4つのリージョンのいずれかにAzure OpenAI Serviceのリソースを作成します。 価格は トーク ンベースの計算になり、基本的にはOpenAI のGPT-4 Turbo with Vision と計算方法は一緒ですが、細部は異なるようです。 モデル コンテキスト 入力(1,000 トーク ンあたり) 出力(1,000 トーク ンあたり) GPT-4 Turbo with Vision 128k $0.01 $0.03 GPT-4 32K $0.06 $0.12 参考までにGPT-4の価格を載せましたが、コンテキスト長も増えて料金が1/6に下がったのは非常に嬉しいですね。 参考: GPT-4 Turbo with Vision is now available on Azure OpenAI Service! 画像を扱う際には低解像度と高解像度の2つのモードがあり、設定はlow, high, autoの3つがありデフォルト設定ではautoになっています。低解像度の場合は画像サイズによらず固定で85 トーク ンがプラスされます。高解像度の場合は画像を拡大縮小して512 ピクセル の正方形タイルに切り出してその数かける170 トーク ン+85 トーク ンで計算されます。 以下はAzureの記事内で紹介されていた計算例です。 例:2048 x 4096画像(高詳細) 最初に1024 x 2048にサイズ変更して、2048の正方形に収める。 さらに768 x 1536にサイズ変更。 カバーするために6つの512pxタイルが必要。 合計コストは170 × 6 + 85 = 1105 トーク ンです。 参考: What is Azure OpenAI Service? - Azure AI services Detail parameter settings in image processing: Low, High, Auto Azure OpenAI Studio からの利用 以下のようにモデルのデプロイができたら早速 Azure OpenAI Studioのプレイグラウンドから利用してみます。 デプロイしたgpt-4の vision - preview モデルを選択して簡単な画像のプロンプトを入力してみます。 画像を認識できない旨の内容が返ってきます。次は英語で書いてみます。 レスポンスから画像内容をしっかり理解していることがわかります。以下はレスポンスの翻訳内容です。 この画像は、青空とわずかな白い雲の下にある鮮やかなひまわり畑を映しています。ひまわりは大きく、明るい黄色の花びらと濃い茶色の中心を持っています。満開で、太陽に向かって上を向いているように見えます。全体的な印象は、晴れやかで陽気な夏の日のものです。 色々試しましたが、日本語だとプレイグラウンドではうまく動かないことが多いです。後述する REST API なら日本語でも安定して動作します。 Azure AI Vision を使った Vision enhancementを有効にする Azure のGPT-4 Turbo with Vision では本家OpenAIにはない特徴として、Azure の Computer Vision (※ portal 上のリソース名)を組み合わせることができます。 この組み合わせは非常に強力な機能で、例えばOpenAIのGPT-4では苦手とされていた画像関連のタスクを、Azure AI Vision と組み合わせることで効果的に処理することが可能になります 例えば、本家のGPT-4では日本語の OCR 精度はかなり低くとても実利用できるものではなかったのですが、 Vision enhancementを有効にすると日本語に関しても正確に読み取ってくれます。 Vision enhancementを有効にしてできることは以下のとおりです。 OCR 物体のタグ付けと バウンディ ングボックスの表示 動画入力 Azure AI Searchと組み合わせた画像検索 ※ こちらは本記事では紹介しません 参考: GPT-4 Turbo with Vision is now available on Azure OpenAI Service! Vision enhancementを有効化するにはAzure のGPT-4 Turbo with Vision と同じリージョンにAzure Computer Vision のリソースを作成します。価格はS1にします(価格がS1の場合のみ組み合わせが可能)。 プレイグラウンドでは右側のパネルよりビジョンのトグルを有効化し、先ほどのリソースを選択するとチャットセッションで Vision enhancementが有効化されます。 以下はDALL-Eで作成した動物が複数いる画像の詳細情報を要求した時のレスポンスです。 入力画像に バウンディ ングボックスとタグが付与され、出力されたテキストの内の単語とリンクするようになっています。かなり正確に位置を検出できていることがわかります。 動画の入力もやってみました。グーチョキパーを連続で出す動画です。 レスポンスの日本語訳です。 動画は、キーボードの上で人の手がさまざまな ジェスチャー を行う一連のシーンを映しているようです。 ジェスチャー には、手が平らに置かれている様子、 ピースサイン 、開いた手、握りこぶし、そしてタイピングをしている手があり、この一連が繰り返されています。この動画は、キーボードを使用する際に行うかもしれない様々な手の位置とアクションを示しており、恐らく指導目的や ユーザーインターフェース のデモンストレーションのためのものでしょう。 キーボードの上で行ったのでそれが誤解を与えてしまっていますが、行った ジェスチャー は正しく読み取れています。 REST API から使ってみる 現時点では API から使用した方が安定した回答を得られます。 こちらは日本語のプロンプトでも動作しました。 通常のGPT-4 Turbo with Vision のリク エス トボディは以下のような形になります。画像部分はURLか base64 エンコーディング された形式になります。 { " messages ": [ { " role ": " system ", " content ": " あなたは役に立つAIアシスタントです " } , { " role ": " user ", " content ": [ " 画像を説明して: ", { " image ": encoded_string } ] } ] , " max_tokens ": 300 , " stream ": False } 続いて Vision enhancementを使う場合です。 Vision enhancementを使う場合のエンドポイントはただのGPT-4 Turbo with Vision とは異なるので注意です。 通常: https://{RESOURCE_NAME}.openai.azure.com/openai/deployments/{DEPLOYMENT_NAME}/chat/completions?api-version=2023-12-01-preview 拡張機能 : https://{RESOURCE_NAME}.openai.azure.com/openai/deployments/{DEPLOYMENT_NAME}/extensions/chat/completions?api-version=2023-12-01-preview 参考: How to use the GPT-4 Turbo with Vision model - Azure OpenAI Service 以下が Vision enhancementのリク エス トボディです。 enhancements と dataSources という項目が新たに加わります。 { " enhancements ": { " ocr ": { " enabled ": True } , " grounding ": { " enabled ": True } } , " dataSources ": [ { " type ": " AzureComputerVision ", " parameters ": { " endpoint ": ai_vision_endpoint, " key ": ai_vision_key } }] , " messages ": [ { " role ": " system ", " content ": " あなたは役に立つAIアシスタントです。回答は日本語でお願いします。 " } , { " role ": " user ", " content ": [ " 画像内の文字を書き起こして: ", { " image ": encoded_string } ] } ] , " max_tokens ": 500 , " stream ": False } 試しに手書き文字の書き起こしをやってみました。 入力画像は以下のような日本語の手書き文字です。 以下のような結果が返ってきました。(レスポンスの一部抜粋) 'model': 'gpt-4', 'choices': [{'finish_details': {'type': 'stop', 'stop': '<|fim_suffix|>'}, 'index': 0, 'message': {'role': 'assistant', 'content': '画像内の文字は「 電通国際情報サービス 」となっています。'}}], 'usage': {'prompt_tokens': 925, 'completion_tokens': 24, 'total_tokens': 949}} 正確に読み取れていることがわかります。ただ トーク ンの消費量は多くなってしまいますね。 ちなみに本家OpenAIのChatGPTに同様の手書き文字を読み取らせると 画像内の文字は「高温注意報」と書かれています。 というレスポンスが返ってくるのでAzure の Vision enhancementの有用性がわかります。 Azure とOpenAI のGPT-4 Turbo with Vision の違い 大きな違いはやはりAzure AI Vision を使用した Vision enhancementの有無です。 以下のスライドは同僚の太田さんが動画像マルチモーダルLLMの研究動向について調査したものです。その中でGPT-4Vで困難なタスクの例が論文を元に紹介されています。 参考: マルチモーダルLLMの応用動向の論文調査 調査の中で難しいとされていた「日本語 OCR 」、「画像内の物体位置座標の生成」に関してはGPT-4 Turbo with Vision とAzure独自の Vision enhancementの組み合わせにより実現できました。また、OpenAIの方では動画入力はできませんが、Azureでは可能になります。 まとめ 本記事では、Azure上で新たに利用可能となった「GPT-4 Turbo with Vision 」の特徴とその使い方を紹介しました。また、Azureが提供する独自の Vision enhancementとの組み合わせ方法とその使い方についても解説しました。 今回特に注目すべき点は、AzureがOpenAIの基本的な機能に加えて、独自のカスタマイズや 拡張機能 を提供したことです。これにより、ユーザーはOpenAIのGPT-4を利用するだけでなく、自分たちのニーズに合わせてより柔軟にシステムをカスタマイズできます。 また記事中でも言及しましたがAzure OpenAI Studioのプレイグラウンドはまだあまり安定していない印象をうけました。英語でプロンプトを作成したとしても、画像の内容を一回で返答してくれないことや、 Vision enhancementがトリガーされないことが多々ありました。 もし現時点でAzureのGPT-4 Turbo with Vision の機能を一通り試すなら REST API から試すのがおすすめです。 本記事の内容が何かの参考になれば幸いです。 最後に私が所属するAIトランスフォーメーションセンターでもAIに関するコラムを多数記載しておりますのでそちらも是非ご参照ください。 参考: AIトランスフォーメーションセンターコラム 執筆: @goto.yuki 、レビュー: @yamada.y ( Shodo で執筆されました )
アバター
こんにちは。XI 本部 AIトランスフォーメーションセンター 所属の山田です。 本記事は「 電通国際情報サービス Advent Calendar 2023 」の12月19日(火)の回の記事になります。 私たちのチームでは、データベースAzure CosmosDB for MongoDB (RU) を採用したアプリケーション開発を行っています。 開発を進める中でつまづいたり失敗も多く「使う前に知っていれば苦労しなかったのに…」と思うことが何度かありました。 そこで本記事では「失敗から学ぶ Azure Cosmos DB for MongoDB (RU) の歩き方」と題して、それらの内容を紹介したいと思います。 前提 Azure CosmosDB for MongoDB (RU) とは? Azure CosmosDB の NoSQL API について知っておこう Azure CosmosDB の公式ドキュメントの読み方について知っておこう サーバレスとプロビジョニングされたスループットの違いを把握しておこう サーバレス プロビジョニングされたスループット RU/s の制限はデータベース単位とコレクション単位が存在することを知っておこう サポートされていない命令や制限があることを知っておこう Azure CosmosDB for MongoDB の拡張コマンドについて理解しておこう バックアップポリシーを慎重に検討しよう O/Rマッパーは障壁となる場合があることを理解しておこう シャーディングによるRUの制限および容量の制限を知っておこう コレクション設計は慎重にしておこう 診断設定とフルテキストクエリは有効にしておこう $explain コマンドについて知っておこう まとめ 前提 Azure CosmosDB for MongoDB (RU) とは? 前提の話になりますが、Azure CosmosDB は複数の API をサポートしているフルマネージドのデータベースサービスです。 Azure Cosmos DB for MongoDB はAzure Cosmos DBの API のひとつで、Azure Cosmos DBをMongoDBデータベースのように操作するものになります。 このAzure Cosmos DB for MongoDBには「RUベースの アーキテクチャ 」と「vCoreベースの アーキテクチャ 」の2種類が存在しており、本記事では「RUベースの アーキテクチャ 」を扱います。本記事ではこちらをAzure Cosmos DB for MongoDB (RU) と表記しています。 以下からは、本題である Azure Cosmos DB for MongoDB (RU) をプロダクションで使うにあたって、知っておけばよかったことや注意点などを経験をもとに記載しています。 Azure CosmosDB の NoSQL API について知っておこう Azure Cosmos DB for MongoDB (RU) について扱うと述べたのに、なぜ NoSQL API の話が出てくるのか疑問に思われた方もいるかもしれません。 しかしこれには事情があります。NoSQL API は Azure ComsosDBのネイティブ実装であり、Azure CosmosDBの特徴的な機能は、NoSQL API をベースに実装されています。 Azure Cosmos DB for MongoDB (RU) は Azure CosmosDB for NoSQL を MongoDB の API を通して操作できるラッパーのようなものであり、Azure CosmosDB for NoSQL について知っておくことで仕様や制限についてより理解できます。 そのため、Azure CosmosDB for NoSQL のドキュメントも一通り確認しておくことを強くおすすめします。 また Azure CosmosDB for NoSQLについては、 Microsoft の資格試験「 DP-420: Microsoft Azure Cosmos DB を使用したクラウドネイティブ アプリケーションの設計と実装 」が用意されているので、こちらの資格取得を通してキャッチアップをするのもよい方法です。 重要なのは、 Azure Cosmos DB for MongoDB (RU) が純粋な MongoDB の実装ではなく、 Azure CosmosDB for NoSQL をベースとした実装であることを知っておくことで仕様への理解が進む ということです。 Azure CosmosDB の公式ドキュメントの読み方について知っておこう Azure CosmosDB は API ごとに使える機能の違いが存在します。 Azure CosmosDB の機能として紹介されている場合でも、選択した API によってはサポートされていなかったり、他のデータベースシステムでサポートされていると思っているものが Azure CosmosDB ではサポートされていなかったりといったことがあります。 こういった違いを開発者が把握するために、 Microsoft の公式ドキュメントの各ページでは、サポート対象の API が以下のように記述されています。 [ スクリーンショット 元記事] Azure Cosmos DB のコンテナーとデータベースにスループットをプロビジョニングする | Microsoft Learn 機能について調査を実施する場合は、ドキュメントのこの箇所を必ずチェックをするようにしましょう。 サーバレスとプロビジョニングされた スループット の違いを把握しておこう Azure CosmosDB for MongoDB (RU) では、リソース作成時に容量モードを「サーバレス」と「プロビジョニングされた スループット 」から選択する必要があります。 2つの容量モードは料金形態だけでなく、配置できるリージョンやストレージにも違いがあります。 この2つのモードはリソース作成後に変更できないため、事前に仕様について理解をしておく必要があります。 サーバレス サーバレスは消費したRU量に応じてコストが発生する完全な従量課金モデルになります。 サーバレスモードを利用する場合、Azure CosmosDBは1つのAzureリージョンにしかデプロイできません。 また1つのコレクションに保存できるデータ量の最大値は1TBになります。 プロビジョニングされた スループット プロビジョニングされた スループット では、あらかじめ設定した スループット 値に応じてコストが発生する課金モデルになります。 プロビジョニングされた スループット モードは、複数のAzureリージョンにデプロイ可能で、コレクションあたりに保存できるデータ量にも制限がありません。 スループット 値は「手動」と「自動スケール」の2つがあり、手動の場合は400RU/sから、自動スケールの場合は1,000RU/sから設定ができます。 自動スケールの場合は、設定した スループット 値の10%刻みでスケーリングが瞬時に行われます。 例えば、自動スケールで スループット 値を最大 4,000RU/s とした場合は、400RU/s ~ 4,000RU/sの間でスケーリングが行われることになります。 また「手動」と「自動スケール」ではRU/sに対する料金が異なり、自動スケールでは1時間あたりの100RU/sに対する課金額が手動スケールの価格の1.5倍になります。 自動スケールでは、 スループット 値に対する10%分は定常的な課金が発生するので、 スループット 値に大きなRU/sを設定すればするほど定常的に支払うコストが高くなる点は要注意です。 learn.microsoft.com RU/s の制限はデータベース単位とコレクション単位が存在することを知っておこう プロビジョニングされた スループット の容量モードで Azure CosmosDB を利用する場合、 スループット として設定する RU/s の制限はデータベース全体と各コレクションの2つがあります。 データベース全体で RU/s の設定をする場合は、設定したデータベースに含まれるコレクションすべてで利用可能な RU/s が共有されます。これはスモールスタートしたプロジェクトで必要なコレクションの数の見積もりが難しい場合などに有効な設定です。 データベース全体で RU/s の設定をする場合は、特定のコレクションが過剰に RU を消費していると全体の スループット にも影響を及ぼすので注意が必要です。 コレクション単位で設定する場合は、各コレクション個別に RU/s を割り当てできるため、各コレクションのアクセスパターンに応じて最大のパフォーマンスが得られるように配分できます。 一方、コレクション単位に設定をする場合、新しいコレクションを作成する際に追加で スループット 値を割り当てる必要があるため、コレクション数が増えるのに応じて定常コストが増加することになるため注意が必要です。 サポートされていない命令や制限があることを知っておこう Azure CosmosDB for MongoDB(RU) でサポートされている MongoDB の命令には制限があります。 サポートされている命令などは以下のドキュメントで確認できます。 learn.microsoft.com 多くの命令が網羅されている印象はありますが、現状では特に集計コマンドについては制限が大きいです。 私たちはアプリケーションで集計処理を実装する ユースケース があったのですが、集計パイプラインの $lookup 演算子 が使えない問題に直面しました。この部分は find クエリを複数回、発行することで回避しています。 Azure CosmosDB for MongoDB の拡張コマンドについて理解しておこう 先に MongoDB のコマンドの中でサポートされていないものがあると説明しましたが、逆にAzure CosmosDB for MongoDB 固有の拡張コマンドも存在します。 learn.microsoft.com 実はAzure CosmosDB for MongoDB の機能をフルに活用するためには、この拡張コマンドについて理解する必要があります。 例えば、コレクションの作成時にコレクションに対して スループット を割り当てたりシャードキーの指定などの操作は拡張コマンド からし かできません。 # コレクション作成コマンド MongoDB のネイティブコマンド db.createCollection("sample") CosmosDB の MongoDB 拡張コマンド db.runCommand({ customAction: "CreateCollection", collection: "sample", shardKey: "_id", autoScaleSettings: { maxThroughput: 4000 } }) その他に純粋な MongoDB であれば、コレクションの作成とインデックスの作成は別々に行いますが Azure CosmosDB for MongoDB ではコレクション作成時にインデックスの指定ができます。 バックアップポリシーを慎重に検討しよう バックアップポリシーには「定期的なバックアップ」と「継続的なバックアップ」の2つがあります。 「定期的なバックアップ」と「継続的なバックアップ」の大きな違いとしてデータ復旧方法があります。 「定期的なバックアップ」の場合、データ復旧のためには Azure サポートにチケットで依頼をする必要がありますが、「継続的なバックアップ」の場合はユーザー自身でデータ復旧を実施できます。 これだけ聞くと「継続的なバックアップ」の方が魅力的に思えるかもしれませんが、現状は「継続的なバックアップ」を利用する場合には機能的な制限があるので慎重に検討しておく必要があります。 Azure CosmosDB for MongoDBの バックアップポリシーに「継続的なバックアップ」を利用する場合、コレクションに対し、ユニークキーインデックスを後から追加することはできません。 O/Rマッパーは障壁となる場合があることを理解しておこう アプリケーションからデータベースにアクセスする際に、O/Rマッパーを使いたいと考える開発者は多いと思います。 Azure CosmosDB for MongoDB(RU) の場合、安易に MongoDB の O/Rマッパーを使うと問題に直面する場合があります。 O/Rマッパーで、コレクションの作成やインデックス定義が行われる場合、通常の MongoDB の命令が裏で発行され、Azure CosmosDB 側に送られます。 命令は先の拡張コマンドではないため、Azure CosmosDB 側で実施したい設定と競合する、あるいは命令が通らずに失敗するといったことが起きます。 少なくとも、データベースの作成操作、コレクションの定義、インデックスの定義の操作については、Azure CosmosDB 拡張コマンドで行うことを強くおすすめします。 シャーディングによるRUの制限および容量の制限を知っておこう Azure CosmosDB ではシャーディングによる分割によって、コレクションのスケーリングを実現しています。 コレクション内のシャーディングはコレクションのシャーディングキーによって分割されます。 シャーディングキーの値によって、ドキュメントは論理 パーティション (シャード)に振り分けて保存がされます。 この1つの論理 パーティション に保存できるデータは20GBという制約があります。 NoSQL API を利用する場合は、 パーティション キー(シャーディングキー)を選択しなければコンテナ(コレクション)の作成ができないのですが、MongoDB API を利用する場合、シャーディングキーなしにコレクションを作成できます。 シャーディングキーがないコレクションの場合、コレクションは1つの論理 パーティション にのみ保存されるためコレクションに保存されるデータ量は20GBに制限されます。 また スループット についても制限があり、シャーディングキーがないコレクションの場合、 スループット に設定可能なRUは10,000RU/sという制限を受けることになります。これは論理 パーティション よりも背後にある物理 パーティション 側の制約になりますが、1つの物理 パーティション で提供可能な スループット が10,000RU/sでありシャーディングが行われない場合は、全てのデータは1つの物理 パーティション にのみ保存されるため、この制限を直接受けることになります。 コレクション設計は慎重にしておこう 先に述べたシャーディングによるRUや容量の制限があることを考慮しながらコレクションを慎重に設計しましょう。 例えば、会社情報を保存するコレクション「companies」の設計をする場合を考えてみます。 各会社の所在地の国「country」をシャードキーにする場合、以下の画像のような形でデータが保存されます。 アプリケーションの要件によってはこの設計でも問題がないかもしれませんが、この設計は1つの国に20GBを超える会社情報がないことを仮定しています。 また国ごとにデータ数の偏りがあるため、特定の パーティション のデータ量が肥大化するホット パーティション 問題のリスクもあります。 その他に複数の国をまたがってクエリをする ユースケース がある場合、この設計だとクロス パーティション クエリによって RU の消費量が大きくなります。 このように比較的単純なデータでもコレクション設計を始めると悩むポイントがそれなりにあります。 時間を費やしすぎないためにもコレクション設計において気をつけるべきポイントを持っておくことが重要です。 私なりに意識するポイントを 言語化 しておくと以下のような観点になります。 クエリパターンや保存するデータの特定を考慮してシャーディングキーを適切に選択しておく。 シャーディングキーは後から追加することができないので十分にスケーリングできるように設計をしましょう。 アプリケーションから発行するクエリパターンを把握しておくことでクロス パーティション クエリの発生を抑えることができます。 ユニークインデックスの設計しておく。 バックアップポリシーで「継続的なバックアップ」を選択した場合、後からユニークインデックスを追加することや変更することができないため先に設計をしましょう。 設計ミスをした際のプランを考えておく。 どんなに避けようとしても設計ミスが起きることはあります。適切な設計パターンに対応するためのデータ移行方法を模索しておくのも重要です。 診断設定とフルテキストクエリは有効にしておこう Azure CosmosDB for MongoDB ではフルテキストクエリを有効にすることで、すべてのクエリをログに記録できます。 少なくとも開発中は診断設定でフルテキストクエリを有効にして、診断設定から Log Analytics ワークスペース に流すように構成することをおすすめします。 フルテキストクエリを有効にすると Log Analytics ワークスペース では PIICommandText 列で発行された具体的なクエリを見ることができるため、アプリケーションで発行されているクエリパターンの分析やスロークエリの発見ができます。 learn.microsoft.com $explain コマンドについて知っておこう 先に診断設定とセットで問題となるクエリの分析方法を把握しておく必要があります。 Micorosfot の公式ドキュメントによると、Azure CosmosDB では RU の消費量が50を超えるかをスロークエリの大まかな ガイドライン としているようです。 Log Analytics を見て、RU の消費量が50を超えるクエリに対しては分析を行うようにしましょう。 この分析には MongoDB の $explain コマンドを利用します。 なお Azure CosmosDB for MongoDB での $explain コマンドで得られる結果は純粋な MongoDB とは異なるので注意が必要です。 実際の分析方法については以下の公式ドキュメントが参考になるため、ここでは紹介しませんが、 $explain コマンドを使って分析をすることで、足りないインデックスを把握するなど改善のためのヒントを得ることができます。 learn.microsoft.com まとめ 本記事では「失敗から学ぶ Azure Cosmos DB for MongoDB (RU) の歩き方」と題して、Azure Cosmos DB for MongoDB (RU) をプロダクションで使うにあたって知っておけばよかったことや注意点などを紹介しました。 本記事で紹介した内容のほとんどは公式ドキュメントにも記載されているのですが、実際は失敗するまでそれらの存在に気付かないことが多くあることを痛感しました。 なお Azure Cosmos DB for MongoDB (RU) は適切に設計を行った上で利用できれば、非常に高いスケール性能を得られるのでメリットを享受できるように使いこなしていきたいですね。 また純粋な MongoDB との違いも多いので、純粋な MongoDB を Azure で利用したい場合は、最近 GA された仮想コアベースの「 Azure Cosmos DB for MongoDB (vCore) 」の利用を検討するのが良いでしょう。 本記事の内容が何かの参考になれば幸いです。 執筆: @yamada.y 、レビュー: 寺山 輝 (@terayama.akira) ( Shodo で執筆されました )
アバター
こんにちは。XI 本部 AIトランスフォーメーションセンター 所属の山田です。 本記事は「 電通国際情報サービス Advent Calendar 2023 」の12月19日(火)の回の記事になります。 私たちのチームでは、データベースAzure CosmosDB for MongoDB (RU) を採用したアプリケーション開発を行っています。 開発を進める中でつまづいたり失敗も多く「使う前に知っていれば苦労しなかったのに…」と思うことが何度かありました。 そこで本記事では「失敗から学ぶ Azure Cosmos DB for MongoDB (RU) の歩き方」と題して、それらの内容を紹介したいと思います。 前提 Azure CosmosDB for MongoDB (RU) とは? Azure CosmosDB の NoSQL API について知っておこう Azure CosmosDB の公式ドキュメントの読み方について知っておこう サーバレスとプロビジョニングされたスループットの違いを把握しておこう サーバレス プロビジョニングされたスループット RU/s の制限はデータベース単位とコレクション単位が存在することを知っておこう サポートされていない命令や制限があることを知っておこう Azure CosmosDB for MongoDB の拡張コマンドについて理解しておこう バックアップポリシーを慎重に検討しよう O/Rマッパーは障壁となる場合があることを理解しておこう シャーディングによるRUの制限および容量の制限を知っておこう コレクション設計は慎重にしておこう 診断設定とフルテキストクエリは有効にしておこう $explain コマンドについて知っておこう まとめ 前提 Azure CosmosDB for MongoDB (RU) とは? 前提の話になりますが、Azure CosmosDB は複数の API をサポートしているフルマネージドのデータベースサービスです。 Azure Cosmos DB for MongoDB はAzure Cosmos DBの API のひとつで、Azure Cosmos DBをMongoDBデータベースのように操作するものになります。 このAzure Cosmos DB for MongoDBには「RUベースの アーキテクチャ 」と「vCoreベースの アーキテクチャ 」の2種類が存在しており、本記事では「RUベースの アーキテクチャ 」を扱います。本記事ではこちらをAzure Cosmos DB for MongoDB (RU) と表記しています。 以下からは、本題である Azure Cosmos DB for MongoDB (RU) をプロダクションで使うにあたって、知っておけばよかったことや注意点などを経験をもとに記載しています。 Azure CosmosDB の NoSQL API について知っておこう Azure Cosmos DB for MongoDB (RU) について扱うと述べたのに、なぜ NoSQL API の話が出てくるのか疑問に思われた方もいるかもしれません。 しかしこれには事情があります。NoSQL API は Azure ComsosDBのネイティブ実装であり、Azure CosmosDBの特徴的な機能は、NoSQL API をベースに実装されています。 Azure Cosmos DB for MongoDB (RU) は Azure CosmosDB for NoSQL を MongoDB の API を通して操作できるラッパーのようなものであり、Azure CosmosDB for NoSQL について知っておくことで仕様や制限についてより理解できます。 そのため、Azure CosmosDB for NoSQL のドキュメントも一通り確認しておくことを強くおすすめします。 また Azure CosmosDB for NoSQLについては、 Microsoft の資格試験「 DP-420: Microsoft Azure Cosmos DB を使用したクラウドネイティブ アプリケーションの設計と実装 」が用意されているので、こちらの資格取得を通してキャッチアップをするのもよい方法です。 重要なのは、 Azure Cosmos DB for MongoDB (RU) が純粋な MongoDB の実装ではなく、 Azure CosmosDB for NoSQL をベースとした実装であることを知っておくことで仕様への理解が進む ということです。 Azure CosmosDB の公式ドキュメントの読み方について知っておこう Azure CosmosDB は API ごとに使える機能の違いが存在します。 Azure CosmosDB の機能として紹介されている場合でも、選択した API によってはサポートされていなかったり、他のデータベースシステムでサポートされていると思っているものが Azure CosmosDB ではサポートされていなかったりといったことがあります。 こういった違いを開発者が把握するために、 Microsoft の公式ドキュメントの各ページでは、サポート対象の API が以下のように記述されています。 [ スクリーンショット 元記事] Azure Cosmos DB のコンテナーとデータベースにスループットをプロビジョニングする | Microsoft Learn 機能について調査を実施する場合は、ドキュメントのこの箇所を必ずチェックをするようにしましょう。 サーバレスとプロビジョニングされた スループット の違いを把握しておこう Azure CosmosDB for MongoDB (RU) では、リソース作成時に容量モードを「サーバレス」と「プロビジョニングされた スループット 」から選択する必要があります。 2つの容量モードは料金形態だけでなく、配置できるリージョンやストレージにも違いがあります。 この2つのモードはリソース作成後に変更できないため、事前に仕様について理解をしておく必要があります。 サーバレス サーバレスは消費したRU量に応じてコストが発生する完全な従量課金モデルになります。 サーバレスモードを利用する場合、Azure CosmosDBは1つのAzureリージョンにしかデプロイできません。 また1つのコレクションに保存できるデータ量の最大値は1TBになります。 プロビジョニングされた スループット プロビジョニングされた スループット では、あらかじめ設定した スループット 値に応じてコストが発生する課金モデルになります。 プロビジョニングされた スループット モードは、複数のAzureリージョンにデプロイ可能で、コレクションあたりに保存できるデータ量にも制限がありません。 スループット 値は「手動」と「自動スケール」の2つがあり、手動の場合は400RU/sから、自動スケールの場合は1,000RU/sから設定ができます。 自動スケールの場合は、設定した スループット 値の10%刻みでスケーリングが瞬時に行われます。 例えば、自動スケールで スループット 値を最大 4,000RU/s とした場合は、400RU/s ~ 4,000RU/sの間でスケーリングが行われることになります。 また「手動」と「自動スケール」ではRU/sに対する料金が異なり、自動スケールでは1時間あたりの100RU/sに対する課金額が手動スケールの価格の1.5倍になります。 自動スケールでは、 スループット 値に対する10%分は定常的な課金が発生するので、 スループット 値に大きなRU/sを設定すればするほど定常的に支払うコストが高くなる点は要注意です。 learn.microsoft.com RU/s の制限はデータベース単位とコレクション単位が存在することを知っておこう プロビジョニングされた スループット の容量モードで Azure CosmosDB を利用する場合、 スループット として設定する RU/s の制限はデータベース全体と各コレクションの2つがあります。 データベース全体で RU/s の設定をする場合は、設定したデータベースに含まれるコレクションすべてで利用可能な RU/s が共有されます。これはスモールスタートしたプロジェクトで必要なコレクションの数の見積もりが難しい場合などに有効な設定です。 データベース全体で RU/s の設定をする場合は、特定のコレクションが過剰に RU を消費していると全体の スループット にも影響を及ぼすので注意が必要です。 コレクション単位で設定する場合は、各コレクション個別に RU/s を割り当てできるため、各コレクションのアクセスパターンに応じて最大のパフォーマンスが得られるように配分できます。 一方、コレクション単位に設定をする場合、新しいコレクションを作成する際に追加で スループット 値を割り当てる必要があるため、コレクション数が増えるのに応じて定常コストが増加することになるため注意が必要です。 サポートされていない命令や制限があることを知っておこう Azure CosmosDB for MongoDB(RU) でサポートされている MongoDB の命令には制限があります。 サポートされている命令などは以下のドキュメントで確認できます。 learn.microsoft.com 多くの命令が網羅されている印象はありますが、現状では特に集計コマンドについては制限が大きいです。 私たちはアプリケーションで集計処理を実装する ユースケース があったのですが、集計パイプラインの $lookup 演算子 が使えない問題に直面しました。この部分は find クエリを複数回、発行することで回避しています。 Azure CosmosDB for MongoDB の拡張コマンドについて理解しておこう 先に MongoDB のコマンドの中でサポートされていないものがあると説明しましたが、逆にAzure CosmosDB for MongoDB 固有の拡張コマンドも存在します。 learn.microsoft.com 実はAzure CosmosDB for MongoDB の機能をフルに活用するためには、この拡張コマンドについて理解する必要があります。 例えば、コレクションの作成時にコレクションに対して スループット を割り当てたりシャードキーの指定などの操作は拡張コマンド からし かできません。 # コレクション作成コマンド MongoDB のネイティブコマンド db.createCollection("sample") CosmosDB の MongoDB 拡張コマンド db.runCommand({ customAction: "CreateCollection", collection: "sample", shardKey: "_id", autoScaleSettings: { maxThroughput: 4000 } }) その他に純粋な MongoDB であれば、コレクションの作成とインデックスの作成は別々に行いますが Azure CosmosDB for MongoDB ではコレクション作成時にインデックスの指定ができます。 バックアップポリシーを慎重に検討しよう バックアップポリシーには「定期的なバックアップ」と「継続的なバックアップ」の2つがあります。 「定期的なバックアップ」と「継続的なバックアップ」の大きな違いとしてデータ復旧方法があります。 「定期的なバックアップ」の場合、データ復旧のためには Azure サポートにチケットで依頼をする必要がありますが、「継続的なバックアップ」の場合はユーザー自身でデータ復旧を実施できます。 これだけ聞くと「継続的なバックアップ」の方が魅力的に思えるかもしれませんが、現状は「継続的なバックアップ」を利用する場合には機能的な制限があるので慎重に検討しておく必要があります。 Azure CosmosDB for MongoDBの バックアップポリシーに「継続的なバックアップ」を利用する場合、コレクションに対し、ユニークキーインデックスを後から追加することはできません。 O/Rマッパーは障壁となる場合があることを理解しておこう アプリケーションからデータベースにアクセスする際に、O/Rマッパーを使いたいと考える開発者は多いと思います。 Azure CosmosDB for MongoDB(RU) の場合、安易に MongoDB の O/Rマッパーを使うと問題に直面する場合があります。 O/Rマッパーで、コレクションの作成やインデックス定義が行われる場合、通常の MongoDB の命令が裏で発行され、Azure CosmosDB 側に送られます。 命令は先の拡張コマンドではないため、Azure CosmosDB 側で実施したい設定と競合する、あるいは命令が通らずに失敗するといったことが起きます。 少なくとも、データベースの作成操作、コレクションの定義、インデックスの定義の操作については、Azure CosmosDB 拡張コマンドで行うことを強くおすすめします。 シャーディングによるRUの制限および容量の制限を知っておこう Azure CosmosDB ではシャーディングによる分割によって、コレクションのスケーリングを実現しています。 コレクション内のシャーディングはコレクションのシャーディングキーによって分割されます。 シャーディングキーの値によって、ドキュメントは論理 パーティション (シャード)に振り分けて保存がされます。 この1つの論理 パーティション に保存できるデータは20GBという制約があります。 NoSQL API を利用する場合は、 パーティション キー(シャーディングキー)を選択しなければコンテナ(コレクション)の作成ができないのですが、MongoDB API を利用する場合、シャーディングキーなしにコレクションを作成できます。 シャーディングキーがないコレクションの場合、コレクションは1つの論理 パーティション にのみ保存されるためコレクションに保存されるデータ量は20GBに制限されます。 また スループット についても制限があり、シャーディングキーがないコレクションの場合、 スループット に設定可能なRUは10,000RU/sという制限を受けることになります。これは論理 パーティション よりも背後にある物理 パーティション 側の制約になりますが、1つの物理 パーティション で提供可能な スループット が10,000RU/sでありシャーディングが行われない場合は、全てのデータは1つの物理 パーティション にのみ保存されるため、この制限を直接受けることになります。 コレクション設計は慎重にしておこう 先に述べたシャーディングによるRUや容量の制限があることを考慮しながらコレクションを慎重に設計しましょう。 例えば、会社情報を保存するコレクション「companies」の設計をする場合を考えてみます。 各会社の所在地の国「country」をシャードキーにする場合、以下の画像のような形でデータが保存されます。 アプリケーションの要件によってはこの設計でも問題がないかもしれませんが、この設計は1つの国に20GBを超える会社情報がないことを仮定しています。 また国ごとにデータ数の偏りがあるため、特定の パーティション のデータ量が肥大化するホット パーティション 問題のリスクもあります。 その他に複数の国をまたがってクエリをする ユースケース がある場合、この設計だとクロス パーティション クエリによって RU の消費量が大きくなります。 このように比較的単純なデータでもコレクション設計を始めると悩むポイントがそれなりにあります。 時間を費やしすぎないためにもコレクション設計において気をつけるべきポイントを持っておくことが重要です。 私なりに意識するポイントを 言語化 しておくと以下のような観点になります。 クエリパターンや保存するデータの特定を考慮してシャーディングキーを適切に選択しておく。 シャーディングキーは後から追加することができないので十分にスケーリングできるように設計をしましょう。 アプリケーションから発行するクエリパターンを把握しておくことでクロス パーティション クエリの発生を抑えることができます。 ユニークインデックスの設計しておく。 バックアップポリシーで「継続的なバックアップ」を選択した場合、後からユニークインデックスを追加することや変更することができないため先に設計をしましょう。 設計ミスをした際のプランを考えておく。 どんなに避けようとしても設計ミスが起きることはあります。適切な設計パターンに対応するためのデータ移行方法を模索しておくのも重要です。 診断設定とフルテキストクエリは有効にしておこう Azure CosmosDB for MongoDB ではフルテキストクエリを有効にすることで、すべてのクエリをログに記録できます。 少なくとも開発中は診断設定でフルテキストクエリを有効にして、診断設定から Log Analytics ワークスペース に流すように構成することをおすすめします。 フルテキストクエリを有効にすると Log Analytics ワークスペース では PIICommandText 列で発行された具体的なクエリを見ることができるため、アプリケーションで発行されているクエリパターンの分析やスロークエリの発見ができます。 learn.microsoft.com $explain コマンドについて知っておこう 先に診断設定とセットで問題となるクエリの分析方法を把握しておく必要があります。 Micorosfot の公式ドキュメントによると、Azure CosmosDB では RU の消費量が50を超えるかをスロークエリの大まかな ガイドライン としているようです。 Log Analytics を見て、RU の消費量が50を超えるクエリに対しては分析を行うようにしましょう。 この分析には MongoDB の $explain コマンドを利用します。 なお Azure CosmosDB for MongoDB での $explain コマンドで得られる結果は純粋な MongoDB とは異なるので注意が必要です。 実際の分析方法については以下の公式ドキュメントが参考になるため、ここでは紹介しませんが、 $explain コマンドを使って分析をすることで、足りないインデックスを把握するなど改善のためのヒントを得ることができます。 learn.microsoft.com まとめ 本記事では「失敗から学ぶ Azure Cosmos DB for MongoDB (RU) の歩き方」と題して、Azure Cosmos DB for MongoDB (RU) をプロダクションで使うにあたって知っておけばよかったことや注意点などを紹介しました。 本記事で紹介した内容のほとんどは公式ドキュメントにも記載されているのですが、実際は失敗するまでそれらの存在に気付かないことが多くあることを痛感しました。 なお Azure Cosmos DB for MongoDB (RU) は適切に設計を行った上で利用できれば、非常に高いスケール性能を得られるのでメリットを享受できるように使いこなしていきたいですね。 また純粋な MongoDB との違いも多いので、純粋な MongoDB を Azure で利用したい場合は、最近 GA された仮想コアベースの「 Azure Cosmos DB for MongoDB (vCore) 」の利用を検討するのが良いでしょう。 本記事の内容が何かの参考になれば幸いです。 執筆: @yamada.y 、レビュー: 寺山 輝 (@terayama.akira) ( Shodo で執筆されました )
アバター