Liberent-Dev’s blog

株式会社リベル・エンタテインメントのテックブログです。

Google Cloud Spannerを使った際に感じた良かった点と注意点

Google Cloud Spannerを使った際に感じた良かった点と注意点

みなさま、こんにちは!
システム開発部のK.Mです。

弊社でGoogle Cloud Spannerをデータベースに使用する機会がありましたので、開発・運用時に感じた良かった点・注意点を個人的な見解を交えて記載していきます。

f:id:Liberent-Dev:20211125175521p:plain

  • Google Cloud Spannerを使った際に感じた良かった点と注意点
    • Google Cloud Spannerとは
    • 良かった点
    • 注意点
    • 開発時、運用時に起きた他の事例
    • その他、未確認事項
    • まとめ
    • 最後に

Google Cloud Spannerとは

Googleが開発した分散データベース
RDBMSとNoSQLの良い部分が合体したデータベース

良かった点

  • フルマネージドなので運営中に手がかからない

    • 運営期間中は追加実装など他業務に集中出来る。
      実際の運用時にspannerが落ちて繋がらなくなるということはありませんでした
    • イベントなどの負荷が上がりそうな時に事前にノード数を増やしたり、アクセス数が落ち着いてからノード数を減らすという作業しか行っていない
    • それ以外だと1日1回GCPの管理画面からspannerのCPU負荷やレイテンシに問題が発生していないかを確認する程度の作業量でした
  • データの水平・垂直分割しなくてもspanner側で勝手にやってくれる

    • DBの読み書き処理で水平・垂直分割の処理が不要なので、事前に分割しないといけないぐらいのデータ量になる想定がついている場合は、「実装コストが減る=テスト工数が減る=変なバグを仕込む心配が無い」という形になります
    • 例えると、MySQL ClusterやMySQLのSpiderストレージエンジンと同じような機能が設定不要で使えるということです
    • この機能は、かなり強いです
  • 運用時にメンテナンスを入れずにスキーマー変更が可能

    • 使用した案件では、本番環境にて動作確認をするためのメンテナンスを入れるという工程があったため、メンテナンス中にスキーマー更新を行っていたが、運営サイクルにてメンテナンスを無くすことを検討しているのであれば、魅力的な機能
  • 配列型や構造体型でデータが持てる

    • DBの設計がすっきりして、プログラム側での処理がしやすくなる
    • 配列型の一例
      • ストーリーの第何話を読んだというのを単純に実装しようとして、ユーザーIDと読んだストーリーの話数を保存するテーブルを作った場合、下記のように読んだストーリー数分のレコードが作られてしまいデータが膨れ上がるし、selectやinsert、updateの速度にも影響が出てしまう。(インデックスを設定すればselect自体の速度は速くなるが、insertの速度がデータが増えていくたびにインデックスの更新も入り遅くなっていきますので通常は取りえない設計)

        ユーザーID 読んだストーリーID
        1 1
        1 2
        1 3
        2 1
        2 2
      • 次に考えられるのが無駄にレコードが作られないように、読んだストーリー部分をカンマ区切りの文字列などで保存するという方法がある。こうすることで、ユーザー数分のレコードで済むのでデータ数は激減するが、プログラム側でDBからの読み込んだ際に、カンマで区切られた文字列をカンマ毎に分けて数字にしたり、DBに書き込む際に、数字をカンマで連結して文字列にしたりという処理が入ってきて、少し煩雑になってしまいます。

        ユーザーID 読んだストーリーID
        1 "1,2,3"
        2 "1,2"
      • そういった諸々を回避する方法として読んだストーリーIDをint型の配列型に設定することが可能になっています。配列型に設定出来る型自体は自由です。

        ユーザーID 読んだストーリーID
        1 [1,2,3]
        2 [1,2]
      • goの場合ですが、spannerから読み込んだ時点でint型のスライス(goでの配列のようなもの)として扱えるようになっているので、追加する場合は下記のようにappendするだけでデータが追加されます。

ストーリーテーブル.読んだストーリーID = append(ストーリーテーブル.読んだストーリーID, 4)
  • spannerの管理画面にて下記のような統計を表示するページがあり、クエリのCPU使用率や実行回数、レイテンシが見れるので調査のためにSQL(EXPLAINとか)を叩かなくてもブラウザ上で確認が出来るので調整が簡単に行える
    f:id:Liberent-Dev:20211122185625p:plain

  • GCP標準機能であるトレースにて、スタックトレースのようにspannerのコール順が分かるので、チューニング時にネックになっている箇所が分かりやすい。

    • 下記図はスタックトレースの一例になりますが、この内容ですとReadが頻繁に呼ばれているので、なるべくまとめてRead出来れば処理を短縮出来そうなので調べてみる。
      この例に挙げたケースは、バッチ処理で各テーブルを読み込んでいるという処理だったので、そのままにしておくという判断をしています。 f:id:Liberent-Dev:20211122185621p:plain
続きを読む

ゲームのお知らせページをJamstackで構築した

Jamstack logo

こんにちわ。 システム開発部ネットワーク課のsupercontinueです。

  • ゲーム内お知らせやガチャの情報を扱うWebアプリケーションのサーバ側の仕組みを紹介します。
  • Jamstack を採用して、低コスト・安全 な仕組みができました。

Jamstackとは

特徴

  • 基本的に、CI(継続的インテグレーション。Jenkinsなど)の利用を前提とした設計パターンです。

  • たとえば、Jamstackではない従来型設計の典型であるWordpressに比べると、低コストで安全性も高く、スケール・イン&アウトもしやすくなります

    • なぜ、安全性が高いのか?
      • コンテンツが静的配置され、バックエンドでデータベースに接続する必要がなく、サーバの仕組みが単純になり、セキュリティを担保する必要がある機能が最小限になるからです。
    • なぜ、低コストなのか?
      • 高コストになりがちなデータベースサーバが不要になります。
      • サーバ側でレンダリング(ページの生成)が不要になるため、必要なCPUパワーが少なくなります。
  • ブログやお知らせ・ガチャ・商品情報など、更新頻度があまり高くない、特定のフォーマット(レコード単位の情報)でページが構成される情報のサービスに向いています。

    • 多数ユーザーが高頻度で書き込みを行うようなサービスには向いていません。
  • 複数のシステムで構成され、それぞれは小さいですがスクリプトを記述することが多くなるため、Wordpressのように非エンジニアでも管理できる可用性は失われます。いわゆる「フルスタック・エンジニア」が必要かもしれません。

本案件の構成要素

ヘッドレスCMS

http://takano-plantuml-server.herokuapp.com/svg/SoWkIImgAStDuU8gpixCAqWiIinLoCtFoq_EAChFJLKeAIfDvU9I08E2nEJinFHK1QNm_AAKWgBKuc8bXMe5gAI2WeQpRx0cWlUuUStZvisFcniUDwy2CPesm2HhkP0qAEZgse4KjpzktlEuQV_ZvfbWnavDAuNdsrUydDt6XTiyd7eLh1IUzZSzRrtEvP2QbmBq7G00

  • ヘッドレスCMSは、データを編集・アウトプットする機能を、独立して提供します。
    • ヘッドレスCMSを使う場合、ビルド、レンダリング機能を自前で用意する必要があります

http://takano-plantuml-server.herokuapp.com/svg/SoWkIImgAStDuU8gpixCAqWiIinLoCtFoq_EAChFJLKeAIfDvU9IK2X8JCvEJ4zLK7hSFEDnS_FZvix7pMiUD-rqzWrMKgW6Ab1Gq02oDO6iMXJbJLiVDorvtDpnk77Tu-R9ZvjN0xN2TS157ZVl1Xhsk6dzu-PLZvkd0zNZDWck--NScSzdjJnkRd_SlETnqtwO3h0x57HrxK3cG-KUDyy4CtPgAbWfFD--ukNiDhXA6rrTNVnE0Ufvsj_ql7Kv5m4tGsn5TnV8oYdpdtLCuCBYQ0MGZcTTUv-sxzBaSaZDIm761G00

  • ヘッドレスCMSとして、Cockpit を使いました。
    • Mongodbにデータをアウトプットします。
    • オンプレ環境のDockerで運用しました。

f:id:Liberent-Dev:20211018142838p:plain

cockpitでの編集

  • 複数ユーザーアカウント、ロールで運用できます。

  • collectionsingletonasset の概念があります。

    • collection は複数レコードで構成されます。
      • お知らせ、ヘルプなどで使います。
    • singleton は単一レコードで構成されます。
      • ライセンス表示、利用規約などで使います。
    • どちらも、レコードのフィールドをカスタマイズできます。
      • 日付、時間、テキスト、Wysiwyg、数値、真偽値、オプション、、、
    • asset は基本的に画像ファイルです。

トップページ

f:id:Liberent-Dev:20211018135418p:plain
スクリーンショット:cockpit:トップページ

編集画面の例

f:id:Liberent-Dev:20211018135619p:plain
スクリーンショット:cockpit:記事編集1

f:id:Liberent-Dev:20211018135721p:plain
スクリーンショット:cockpit:記事編集2

アセット画面

f:id:Liberent-Dev:20211018135742p:plain
スクリーンショット:cockpit:アセット一覧

ビルド・スクリプト

  • 下記のように、Cockpitの提供するREST APIを使って、jsonデータを持ってきます。
## お知らせ
if [ "${ENV_VERSION}" = ".prod" ]; then
    INFOMATION_FILTER='{"sort":{"releaseDate":-1,"releaseTime":-1},"filter":{"production":true}}'
else
    INFOMATION_FILTER='{"sort":{"releaseDate":-1,"releaseTime":-1}}'
fi
curl -s ${CMS_API}/collections/get/information?token=${COCKPIT_API_TOKEN} \
 -H "Accept: application/json" -H "Content-type: application/json" \
 -d ${INFOMATION_FILTER} \
 | python -m json.tool > gae/collections/information.json
  • ゲームのレポジトリから、ゲームのマスターデータ(キャラクターやガチャなど)も参照します。

  • 生成する静的データのディレクトリ構成

    • collections 以下には、複数レコードで構成されるjsonデータを置きます。

      例)

      • お知らせ information.json
      • ヘルプ help.json
      • ガチャ gacha.json
    • singletons 以下には、1レコードで構成されるjsonデータを置きます。

      例)

      • ライセンス表記 License.json
      • 利用規約 TermsOfService.json
  • 画像などのファイルは、Cockpitの特定の場所にファイルとして保存されています。 デプロイ時に、CDNに同じファイルをコピーします。

サイト構成

http://takano-plantuml-server.herokuapp.com/svg/SoWkIImgAStDuU8gpixCAqWiIinLoCtFoq_EAChFJLKeAIfDvUBYKW22WiJaxCJqL0KbTqTNXRpyb5Izh68bXMgm70XeP9JavkWeP1NhA2GN5siYn8jJYyfIYu2gaSHUpftvV5RBu-Rsnyrx7ZVjLtYoO_VZnjLPnVbv44Mrg5Owk_YXM8LT-_CfkvyszoCReF6uUThZvfMFcvOzRjhskAabF3KfB3Er_77JUh3eaiTDYnutRtxStA6feAjhXzKBf1g1yAs2bGBSXK_xfptTDvqi0mdx5TbEF5h0eGjsrDJ7JOiVDwy6IW7jVzmy2wni1yZMfWrS3gbvAS040G00

  • html, js, cssは、CDNに置くことも可能ですが、サイズが小さく更新しやすいのでGAEに置きます。
  • 今回は node.js を使いましたが、サーバのスクリプトはとても小さいので、goでもpythonでもなんでもいいと思います。

Webページ

  • ページの開発は riot を使いました。
    • vueのようにメジャーではありませんが、覚えることが少なくて楽で、ビルドも早いしサイズも小さいです。

f:id:Liberent-Dev:20211018153352p:plain

  • ブラウザやWebViewから、お知らせなどのデータを取得するには、フィルタなどを指定して、下記のようにAPIで動的に取得します。
      var url = '/api/collections/get/information';

      fetch(url, {
        method: 'post',
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          filter: {infoType: self.infoType},
          limit: self.limit,
          skip: self.limit * (self.page - 1),
          sort: {releaseDate:-1, releaseTime:-1},
        })
      })
  • サーバ側のスクリプト server.jsは、起動時に静的データを全てメモリに読み込み、リクエストに応じて、データを返します。
    const information = require('./collections/information.json');
    app.post('/api/collections/get/:collection', (req, res) => {
        // 指定した条件で抽出したデータをjsonで返す。
        ...
    app.get('/api/singletons/get/:singletonname', (req, res) => {
        // 指定した条件で抽出したデータをjsonで返す。
        ...

おわりに

  • Jamstackは「コストとセキュリティが気になる」、「スクリプトが得意」なエンジニアに向いています。

  • ブラックボックスがほとんどないので、問題が発生した時、解決できないリスクが少ないし、セキュリティも担保しやすいです。

    • Wordpressで深めの問題が起こったら、ほとんどの人は自力ではどうしようもないのとは対照的です。
  • 導入にあたっては、CMSを使う人やサービスを運用する人の理解や、その人たちへのサポートが必要です。


リベル・エンタテインメントでは、このような最新技術などの取り組みに興味のある方を募集しています。もしご興味を持たれましたら下記サイトにアクセスしてみてください。 https://liberent.co.jp/recruit/

負荷試験のためにLocust試してみた

みなさま、初めまして。
システム開発部のK.Mです。

今回はサーバアプリケーションに対する負荷試験をする時に使用するツールの1つであるLocustを使用手順や使用時に発生した諸々をご紹介していきます。

  • なぜLocust?
  • 負荷試験とは?
  • Locustインストール手順
  • Locust実行手順
  • Locustのシナリオ書き方例
  • Dokerを使ったMaster-Slave設定による沢山の負荷をかける手順
    • ローカルでdocker動かしてみる
    • GKE環境への構築と実施
  • Locustのアップデート
    • GKE部分の差分
  • まとめ
  • 最後に

なぜLocust?

負荷試験で使用するツールとして真っ先に名前が出てくるのは、Apache JMeterになります。

しかし、このJMeterですが、

  • テスト用のシナリオを作る時にUI上でポチポチ選択することで時間が思ったより取られる。
    • GUIで多機能だが、どの項目が何を表すのかが、分かりにくい点がある。
  • テスト用のシナリオがXMLでも用意出来るが、こちらも分かりにくいXMLを読み解いて書いたりするのに時間が取られる。
  • リクエストやレスポンス部分の暗号化とかセキュリティ用の機能があると、その機能をOFFにしないとテストがやりにくい。
    • リクエストとレスポンスを独自に暗号化している案件で、JMeterに暗号化・複合化を入れ込む方法が無く、一時的に暗号化OFFにして試験をしたこともありました。

等々、色々と使う上での難点がありました。

JMeterで難点になっている部分を解消するために、テスト用シナリオをプログラムで書けるツールを探しているところ、pythonで書けるLocustを発見したので使ってみることにしました。

Locustを使う以前は、k6というjsベースでシナリオを書けるツールやvegetaというgoベースでシナリオを書けるツールも使ってみましたが、それぞれ一長一短ありますが現時点ではLocustが上記に挙げたJMeterの難点が無く、使いやすいと個人的には感じています。

続きを読む