tl;dr
とてもいい感じに出来ていると評判のMetabaseですが
BigQueryのドライバに少し問題がありました。
修正し、PRを送った所次のバージョン(0.29.0)に取り込んで貰える事になったので
どんどんMetabaseを使っていきましょう!
注意
この記事の半分は、Metabaseが日本でもっと流行って欲しいという気持ちでできています。
もう半分は上手くいった事を自慢したい気持ちでできています。
改めて偉大な元記事様に感謝します。
https://qiita.com/acro5piano/items/0920550d297651b04387
どんな問題があって何に対応したの?
問題内容
MetabaseはBigQueryにクエリを送る事ができます。
(未検証ですがGUIからリクエストを送ってもクエリ形式になるんじゃないかな?)。
ただ、BigQueryの性質上大きなクエリを送ると応答が遅くなり、
環境によってはタイムアウトが発生していました。
少なくとも東京リージョンのAWS EC2上に構築したMetabaseから
応答に2分ぐらいかかるクエリ量のデータを送ると頻繁にタイムアウトが発生しました。
普通のRDBだと2分かかるクエリとかあんまり無さそうな気がしていまいますが
分析用クエリだとこのタイムアウトはかなり問題だと感じていました。
この問題はMetabaseのIssueにも登録されていました。
Cannot successful query data in Metabase - question took too long (data from google sheet in BigQuery) #6060
https://github.com/metabase/metabase/issues/6060
対応
どうやら単純なリクエストタイムアウトっぽかったので何とかなるんじゃないかな?と思っていた所
BigqueryのSDKにわかりやすくタイムアウトを設定するパラメータがあったので
それを参照するように修正しました。
(defn- ^Bigquery credential->client [^GoogleCredential credential]
(.build (doto (Bigquery$Builder. google/http-transport google/json-factory credential)
(defn- ^Bigquery credential->client [^GoogleCredential credential]
(.build (doto (Bigquery$Builder.
google/http-transport
google/json-factory
(reify HttpRequestInitializer
(initialize [this httpRequest]
(.initialize credential httpRequest)
(.setConnectTimeout httpRequest 0)
(.setReadTimeout httpRequest 0))))
(.setApplicationName google/application-name))))
https://developers.google.com/api-client-library/java/google-http-java-client/reference/1.19.0/com/google/api/client/http/HttpRequestInitializer
https://github.com/metabase/metabase/pull/6982/commits/03aaf62758005f0be009d7929c1ea9dbb194e223
https://qiita.com/hid_tgc/items/ce1517308607f23d594b
この記事が大変参考になりました、ありがとうございます!
この修正によりBigQueryが読み込み待ち状態でタイムアウトになる事はなくなったと思います。
次のリリースから反映されるようなので、MetabaseからBigQueryを繋いでいる方は試してみてください。
今のMasterから持ってきても使えます。
どうやって修正したか
ここから若干蛇足にはなるのですが、
修正までのアプローチも書いておきます。
MetabaseはClojureで書かれているので修正に躊躇してしまう人もいるかもしれないのですが
やってみると案外簡単に出来るんだよって話をしておこうと思います。
問題がわかった経緯
元々、社内のデータ分析のBIツールとしてReDashを使っていました。
今年頭にいろんな場所でMetabaseが話題になった時
いろんな人に良さを散々説いて移行を進める事になりました。
が、既存のクエリが検証中に実行に失敗しました。
Issueでは同じような問題で引っかかってる人がいました。
その時、MetabaseはClojureで出来ている事をふと思い出したのです。
ポール・グレアム教の信者でSchemeとか少しだけ触れたので
(本当に、簡単なwebサーバ作って満足したぐらい少しだけ)
まぁやれば出来るんじゃないかな?みたいな軽い感じで触ってみる事にしました。
この時、Clojureの知識はなく、Lispもちゃんと仕事で使った経験はありませんでした。
勘違いした修正
最初は、もっと単純な修正になると思っていました。
ドライバかコネクタあたりじゃないかなーってあたりをつけてソースを眺めていた所
怪しげな箇所が二箇所ありました。
https://github.com/metabase/metabase/blob/master/src/metabase/driver/bigquery.clj
https://github.com/metabase/metabase/blob/master/src/metabase/driver/google.clj
大体60秒超えるクエリで問題がありそうだなー…と思いながら
ソースを見ていたらずばりなソースがありました。
(後にこの60秒は間違いだとわかるのですが)。
(def ^:private ^:const ^Integer query-timeout-seconds 60)
60秒って書いてる!こいつを300秒とかに変更したら解決だね!(無邪気)。
みたいな感じでこの値を変更してjarファイルを作ってみました。
この時、こちらの記事が大変参考になりました。
https://qiita.com/argius/items/5f66349395cef67f5185
https://qiita.com/ayato_p/items/8bac8229cf8de93df887
ただ、まぁそんな問題ならもっと早めに解決されていたでしょう。
当然この修正では何も挙動に変化はありませんでした。
はじめてのClojure
このあたりでようやくClojureをまじめに見ないといけないなと思い始めました。
ClojureはJVMベースのLispの方言のようです。
という事でJavaの資産をそのまま使えるようです。
Rhinoみたいな感じかな?
JVMで動くJava以外の言語はJavaのライブラリなどを繋ぐのが簡単な印象があります。
何にせよ、JavaのSDKがそのまま使えるのはありがたいです。
サーバサイドJavaをちゃんと使った事はないのですが
参考文献とかは出てきやすいんじゃないかなと。
そう思い調べていると、やはり出てきました。
上で紹介させて頂いた、hid_tgcさんのJavaのBigQueryドライバの記事です。
Javaで書かれたソースをClojureで置き換える例はあちこちに見つかったので簡単にいけそうだなと。
そういう想定だったのです。
元々、この辺りに修正を加える予定でした。
https://github.com/metabase/metabase/blob/master/src/metabase/driver/google.clj#L89-L91
(doto (.build (doto (GoogleCredential$Builder.)
(.setClientSecrets client-id client-secret)
(.setJsonFactory json-factory)
(.setTransport http-transport)))
(.setAccessToken access-token)
(.setRefreshToken refresh-token))))
が、dotoマクロ内で新しくBindさせたリストがうまく参照できない…。
出来たと思ったら違うスコープに向いていたり。
あれ、そもそもレキシカルスコープ?ダイナミックスコープだっけ?みたいな
初歩的な内容で結構ウンウン言ってました。
reifyマクロってどのようなスコープなんだ…とも。
まぁ、ちゃんとLisp触るの久しぶりだしずっとEmacs Lispしか触ってなかったし、しょうがないですよね…。
というか、後になって思えば単純にデバッガ用意してから取り掛かろうで良かった気もします。
ともかく、苦労してこの中にHttpRequestInitializerを仕込めた訳ですが
それでもタイムアウトが発生していました。
どうやらsetしたつもりのInitializerがリクエスト発行時にnullになっている様子。
よく考えるとこのリクエスト、発行される前にスコープから外れて死ぬんじゃね?
というあたりにも気が付いたり。
そもそも別の箇所でHttpRequestInitializerを仕込む方が正しいよなーって思いつつAPIリファレンス見ていたら
素直にCredential作成時じゃなくBigquery.Builder作成時にもインタフェースが用意されていました。
https://developers.google.com/resources/api-libraries/documentation/bigquery/v2/java/latest/com/google/api/services/bigquery/Bigquery.Builder.html
もっとAPIリファレンスをきちんと読んでおこうという教訓ですね。
インフラエンジニアになってから少し忘れかけてしまっていたので自戒です。
確認してPRだしました
きちんと動くjarファイルが作成でき
無事に手元の環境では今までタイムアウトが発生していたクエリが流れるようになりました。
折角だし本家にPR出してみようと思いました。
小規模のOSSやforkされたOSSにはちょくちょくPR出していたのですが
この規模のOSSにPR出すのは初めてでした。
PRテンプレートなどを出来る限り読み
なれない英語をGoogle翻訳の力も借りて頑張って使い
待つことしばし…。
一週間ぐらいたつと、salsakranさんからseniorさんにレビューリクエストがつき
その一週間後ぐらいにレビュー通過しmasterにマージ!
いやぁ、この時は気持ちがブワワって高鳴りましたね。
senior commented 5 days ago
@HelenMertes This should be fixed thanks to a fix submitted by @cahlchang and will be included in the next Metabase release (0.29.0).
https://github.com/metabase/metabase/issues/6060
とても今更ですが、cahlchangは私のgithubアカウント名です。
issueでもこのようなコメントつけて頂いたので、0.29.0のバージョンが今から楽しみです。
って今記事書きながら調べていたら
このsalsakranさんっ方、metabaseのCEOって書いてる!
そしてseniorさんって方はClojureのOrganizationに入っている!
えらいこっちゃ…(今更)。
何にせよ、これである程度の規模のBigQueryでもMetabaseは運用出来そうだなと思います。
おわりに
Metabase、すっごく良いのでもっと流行ってほしいですね。
日本じゃBIツールは商用のTableauかOSSのReDashってイメージが大きいのですが
海外だともう一般的みたいですね。
優劣という意味ではなく使われいる規模という意味で出すのですが
OSSだとMetabaseの方がReDashよりGithubのスター数多いんですよね。
(Qiitaの記事数では10倍程度ReDashの方が多いのですが)
私もできるならちょくちょく貢献していきたいので
これからもMetabaseが流行ってほしいなと思います。
わーい!
Contributionsに名前のってるぞー。