FORCIA Meetup #4 PostgreSQL開発とテスト
こんにちは、広報の伊藤です。
本日はエンジニアがテーマに沿ってLT(ライトニングトーク: 10分程度の発表)を行うイベント「FORCIA Meetup」の内容をお届けいたします。
FORCIA Meetup #4 高速検索を支えるPostgreSQLのノウハウ
2月15日開催のLTのテーマは「高速検索を支えるPostgreSQLのノウハウ」
フォルシアでは、独自の技術基盤Spook®の開発にPostgreSQLを採用しています。Spook®はデータを様々な軸で高速に検索するための技術基盤です。(参考:フォルシアサイト テクノロジーページ)フォルシアは膨大で複雑なデータを持ったお客様にSpook®を提供しており、「独自の検索最適化技術」と「これまで培ってきたノウハウ」を駆使して高速なDB検索をすることがフォルシアエンジニアの仕事の一つとなっています。
そんなフォルシアから、PostgreSQLにまつわるトピックを4人のエンジニアが語ります。
イベントの詳細はこちらをご覧ください。
本記事では「PostgreSQL開発とテスト」についてご紹介します。イベントの雰囲気が少しでも伝わればと思いますので、ここから先は書き起こしスタイルにてお届けいたします。
PostgreSQL開発とテスト
力石(司会):では続いて吉田さんお願いします。
吉田:はい、ありがとうございます。では、PostgreSQL開発とテストというテーマに関してお話させていただきます。ちょっと地味めな話なんですけれどもよろしくお願いします。
私はフォルシアのソフトウェアエンジニアをしております吉田といいます。主にWebアプリケーションの開発をしていて、今は社内では大規模アプリの開発チームに配属されています。またアプリ開発と並行して、アプリケーションのパフォーマンスチューニングなんかも行ったりしています。
で、本題に入る前に少しだけ前提についてお話させていただきたいんですけれども、DB関連のテストっていうのは比較的アプリと比べると大変というふうなことが言われています。理由としては、アプリケーションと比較すると環境構築するまでのコストが高いっていう点であったり、作業者間の差異がない環境下でテストする、再現性を担保するのが比較的難しいというふうな点があるかなと思います。
ただ、フォルシアの環境は少し特殊といいますか、テストの実施が容易な環境であるというふうな点もあるかなっていうふうに思っています。
理由としてはフォルシアでは以下のような工程が多いというのがあります。以下というのは、例えば元々データがあってそのデータを検索用のデータに加工するような工程、バッチSQLっていうふうに呼んでいるんですけれども、そういった工程であったり、その加工された検索のデータから必要なデータを高速に抽出するっていうふうな工程、オンラインSQLの工程であったり、それらを支える汎用的なモジュール開発、先ほどの説明でもあったように拡張機能、やっぱりユーザ定義関数を作るっていうふうな工程が多いので、元あるデータからそういった結果を取るという点で、テストの実施が容易な面はあるかなっていうふうには考えています。
テスト実施の観点
これらに対して、どういった観点でテストを実施するべきかっていうことなんですけれども、例えばバッチSQLであると、そのバッチ処理自体が正常終了するかっていう点であったり、その処理によって元のデータベースから意図した通りに検索用のデータベースが作られているかっていう点になるかなというふうに思います。
また、オンラインSQLに関しては、これはバッチと観点的には一緒ではあるんですけれども、オンラインで生成しているSQLのクエリがSQLとして正しいかどうかっていう点であったり、そのSQL文を通して意図したアウトプットが得られるか、という点をテストすることになるかなというふうに思います。
それらに対して実際にフォルシアがどういった形でテストを実施しているかという話なんですけれども、バッチ処理が正常終了するかに関しては、実際にテストデータでデータベースを作って、それに対してバッチ処理を実行するというふうな形で行うのが多いかなというふうに思います。これはほとんどの開発者が無意識にやっていることではあるかなと思うんですけれども、これも立派なテストと言えるかなというふうに考えています。それに処理が意図した通りに行われているかっていう点なんですけれども、これに関してはDBを丸ごと比較するってのはなかなか現実的には難しいので、実際には、アプリケーションとDBを結合して結合テストのレイヤーで判定するっていうふうなことが多いのかなというふうに思います。
次に、オンラインSQLなんですけれども、正しいSQL文が生成されているかっていうのは、発行されているSQL文に対して、スナップショットテストをかけていて、変更があったときに意図しない差分が入ったりしていないかっていうふうなことを見るようなことが多いかなというふうに思います。
クエリが意図した通りに発行されているか、意図したアウトプットが得られているかっていう点に関しては、これもバッチと同様なんですけれども、データがないとどうしようもないっていう点もあると思うので、アプリとDBを結合してテストするっていうな形が多かなというふうに思っています。
こうして見ると、結構そのDBのテストと言いつつアプリに依存している部分が多いんですね。私たちは主にJavaScriptやTypeScriptでアプリケーション書くことが多いんですけれども、そのJavaScript、TypeScriptでのテスト環境にも少しだけ触れておきます。
これは、プロジェクトにもよるかなと思うんですけど、自分のプロジェクトですと、JestとFrisbyというふうなライブラリを使っています。JestはJavaScriptの結構汎用的なテストのフレームワークで、FrisbyはJestの上で動くAPIのテストフレームワークになっています。
先ほど説明したSQL文に対して、スナップショットテストを実施する部分はJestの単体テストで実施して、結合テストの方はJest + Frisbyで実施するというような形が多いかなというふうに思います。
右のスクリーンショットですと、これはSQL文の訂正に対してスナップショットテストを実施している部分ですかね。AとBっていう数字からセレクトAプラスBっていうSQL文を生成する関数があって、それに対してスナップショットをかけている、こういった形でやっているという感じです。
拡張機能に対するテスト
次にモジュールのテストに関して説明したいんですけれども、その前に一応その拡張機能とはなんぞやという話の説明をさせていただきますと、先ほどの説明にもあった通りPostgreSQLは拡張性の高いDBシステムであるっていうふうなことが特徴で、フォルシアはその特徴に着目して多くの拡張機能を利用しています。
例えば外部ツールですと、全文検索用のインデックスを貼るpg_bigmであったりとか、ロードを高速化するpg_bulkloadといった拡張機能を使うことが多いです。また自社でも、C言語でユーザ定義の関数を書いて、それを拡張機能として利用してるっていうようなことが多いです。
こういった拡張機能やユーザー定義の関数に対してどういったテストの観点があるかという感じなんですけれども、これも先ほどと同様に実際に正しく投入できるかビルドやインストールがきちんとできるかっていう観点と、それらの拡張関数がインプットに対して意図したアウトプットを得られるかっていうふうな点が挙げられるかなというふうに思います。
これらに対してフォルシアがどういった形でテストを実施しているかというと、導入に関しては、仮想環境(docker)でのビルドであったりインストールっていうふうなことを実施しています。ただ意図した結果を得られるかに関しては、関数に対してのリグレッションテストを走らせて結果の差分がないかっていうふうなことを判断しています。
仮想環境でのビルドなんですけれども、基本的に新しめのプロジェクトはほとんどが仮想環境でDBサーバーを用意しています。そのため、フォルシアでは社内共通のPostgreSQLのイメージというものを用意していまして、それを各プロジェクトが利用するというような形になっています。このため、プロジェクトにまたがる汎用的なモジュールを開発する際には、共通イメージ環境下でのビルドがきちんと行われて、テストが通ることをきちんと確認するというふうなことが推奨されています。
関数に対してのリグレッションテストなんですけれども、これはpg_regressというツールを使っています。これがPostgreSQL標準で搭載されているリグレッションテストツールで、これを実行すると一時的にサーバーが起動して、テスト用のDBがつくられまして、そこに対して、あらかじめ用意しておいたSQL文が実行されて、その結果と、あらかじめ用意しておいた実行結果と突き合わせて差分がないかっていうふうなことをチェックするテストになっています。
下のスクリーンショットですと、左側で第1引数と第2引数をたすだけのテスト用の関数を作ったんですけど、それを実行するようなSQL文を用意しておいて、その結果、期待されるアウトプットを用意しておくと、テスト実行した際に、左側のSQL文が実行されて右側の結果と突き合わせて差分がないかっていうふうなことを確認するテストが実行されます。
こういったテストをDB開発時に手元で実行してはいるんですけれども、それ以外にもCIでも実行するようにしています。どうしてもDB周りの処理は環境の差異が出やすいことが多いなと思っていて、実際に手元では動いたんだけれども、CIでエラーが検知されたっていうふうなケースは体感結構多いかなっていうふうに思っています。
ただ一方でやっぱり拡張ビルドしてスクラッチでデータベースを作ってそれに対してAPIリクエスト何度も投げるっていうふうな一連のテストを全部するには、ある程度マシンパワーだったり時間が必要かなっていうふうに思っていて、実際、全てのテストをやりきるまでに40分、50分かかるようなプロジェクトも中にはあったりするかなっていうふうに思っていて、それをプッシュの度に実行するというのも、非現実的ではあるので、時には実行タイミングをある程度制御するっていうなこともやっています。例えば、ビルドはmaster mergeのときのみであったり、バッチ処理はもう定時実行のときのみやるというふうな制御を入れたりもしています。
今後の展望
最後に今後こういったテストが導入されるといいなっていうふうな事を社内で議論している内容について軽く触れておきます。
一つはSQLの文法チェックですね。
これは、現状はクエリを直接DBに投げて、それが返ってきたらOKっていうような形で見ることが多いんですけれども、これをDBサーバーを介さずにアプリに閉じた形でチェックができると嬉しいかなっていうふうなことを思っていて、これはpglastっていうPythonのPostgreSQLの構文を解析するライブラリがあるんですけれども、そういったものを活用すると実現できるんじゃないかなというふうなことを考えたりしています。
もう一つは、パフォーマンステストですね。
フォルシアは高速な検索というのを売りにしているのもあって、実際に拡張だったり関数がピュアな実装と比べてきちんと効果があるんだよっていうふうなことが定量的に測定できる環境があるといいなっていうふうなことも考えていて、実現の方法を模索しているっていうふうな状態になります。
以上でフォルシアがDBに対してどういったテストを実施しているかっていうふうなことを説明させていただきました。以上となります。
LTを終えて
力石(司会):ありがとうございます。では、質問などあれば、メッセージの方に、もしくはTwitterのハッシュタグ「#forciameetup」の方でも随時受け付けております。
そうですね。先ほどのCIでこけて、SQLの間違いに気づくみたいなところがあるかなと思ったんですけど、あれはすごい自分もよくあるので、すごくわかるなと思いながら聞いておりました。
チャット欄から、「テストデータというのはどう準備されていますか」との質問が来ております。
吉田:そうですね。これもプロジェクトによるかなと思うんですけど基本的には先方のデータを使って検索用のデータを作るっていうのが多いので、データを先方にもらうパターンと、当然そのバッチ処理の中で複雑なコーナーケースの処理だったりをする場合であればそのコーナーケースに引っかかりかねないデータを意図的に作って、それをテストデータにするっていうふうなこともあるかなというふうに思います。これは、場合によるかなっていう感覚です。
力石(司会):なるほど。そうですよね。はい、質問ありがとうございます。
私の方からも質問いいでしょうか?一番最後のページに、今後の展望みたいなものとして、定量的にパフォーマンステストを計測するみたいなことを書いてあると思うんですけど、結構もうこれは、実際に取りかかられているというか、どうなんでしょうか?
吉田:いや、手は動かせてないですね。実際どういう方法があるのかなっていうふうなことは考えている途中という段階で、実際形になるまでには時間がかかるかなと思っています。
力石(司会):そうですね、どの値で定量的に比較していくというか、そこら辺もかなり難しいですよね。ありがとうございます。追加で質問が来ました。「テストを書いていたことで救われたケースは多かったでしょうか?」
吉田:なるほどそうですね。そもそも書かないとやってられないというか、そういう部分が多いかなと思っていて。なので、具体的に救われたケースもあるかなと思うんですけれども、それ以前にテストがないとお話にならない部分の方が大きいかなというふうに思います。なのでちょっと具体的なケースをお話できないんですが、そうですね、テストは書くべきだと思いました。
力石(司会):ありがとうございます。そうですよね、自分も社会人エンジニアとして働くようになってからテストの大事さがわかるようになりました。本当その通りだなと思います。はい。ありがとうございます。他に質問は。どうでしょうか?そうですね、はい、特になければ、以上で吉田さんの発表を終わりにしたいと思います。
吉田:ありがとうございました。
FORCIA Meetup #4 書き起こし記事、続々公開
いかがでしたでしょうか。きっと読んでくださった皆さんも、テストの大変さあるあるに共感する部分や、テストに関しての気付きになる部分があったのではないでしょうか。
続いて公開するのは、
「PostgreSQL vs Elasticsearch -ファセットカウント編-」
アドベントカレンダー2020で好評だった記事、「Elasticsearch vs. PostgreSQL」の続編となります。お楽しみに!
伊藤 明日香
2021年6月キャリア入社/経営企画室 広報
書き起こしツールを利用して執筆を進める中で、
「意図した」が全部「愛した」と書き起こされていて楽しかったです。
フォルシアではフォルシアに興味をお持ちいただけた方に、社員との面談のご案内をしています。
採用応募の方、まずはカジュアルにお話をしてみたいという方は、お気軽に下記よりご連絡ください。
※ 弊社社員に対する営業行為などはお断りしております。ご希望に沿えない場合がございますので予めご了承ください。