2019年末版: Redash のメモリ使用量を節約する
まえがき
約2年前にこんな記事を書きました。
最近、Twitter で趣味の Redash エゴサをしていると、メモリ使用量でお悩みの方がいるようだったので、2019/12/20 現在で Redash のメモリ節約にチャレンジしてみます。
サクッといきます。
環境
先日公開した以下の記事の手順に沿って Vagrant 上で環境構築しました。
コンテナのリソース確認のため、 ctop も使います。
節約前
ctop コマンドで見るとこんな感じ。
ざっくり Redash のコンテナ群だけで1.2 GB 前後といったところでしょうか。
(注)PostgreSQL のメモリ使用量については、この記事ではいっさい触れません。
節約後
起動しているコンテナ自体が減っていることもありますが、全体で300MBほど。メモリ使用量だけでいえば 1/4 程度に収まりました。
何をやったか
サービス、プロセスを減らす
docker-compose.yml
をいろいろ書き換えました。詳しくは diff を見てみましょう。
@@ -13,25 +13,13 @@ ports: - "5000:5000" environment: - REDASH_WEB_WORKERS: 4 - scheduler: + REDASH_WEB_WORKERS: 1 + worker: <<: *redash-service command: scheduler environment: - QUEUES: "celery" + QUEUES: "celery,scheduled_queries,schemas,queries" WORKERS_COUNT: 1 - scheduled_worker: - <<: *redash-service - command: worker - environment: - QUEUES: "scheduled_queries,schemas" - WORKERS_COUNT: 1 - adhoc_worker: - <<: *redash-service - command: worker - environment: - QUEUES: "queries" - WORKERS_COUNT: 2 redis: image: redis:5.0-alpine restart: always
Web のワーカーを減らす
性能度外視で節約を目的にするので、プロセス数を1にします
Celery のワーカーをまとめて減らす
デフォルトでは Celery の管理、スケジュール実行、アドホック実行と、3つのサービスにわかれていますが、それをひとつのサービスにまとめます。
ひとつのサービスに詰め込むことになるので、サービス名を worker
としています。さらにワーカーのプロセス数も減らして 1 にします。
もちろん、キューが処理されるのは遅くなりますが、これも節約のためです。
使用しないクエリランナーを無効にする
Redash は多くのデータソースに対応している反面、依存パッケージも多く、それらの読み込みによってメモリが多く消費されるようです。
今回の検証では、PostgreSQL、MySQL、SQLite、BigQuery 以外は無効にするため、以下の設定を /opt/redash/env
に追加しました。
REDASH_DISABLED_QUERY_RUNNERS=redash.query_runner.athena,redash.query_runner.google_spreadsheets,redash.query_runner.graphite,redash.query_runner.mongodb,redash.query_runner.couchbase,redash.query_runner.url,redash.query_runner.influx_db,redash.query_runner.elasticsearch,redash.query_runner.amazon_elasticsearch,redash.query_runner.presto,redash.query_runner.databricks,redash.query_runner.hive_ds,redash.query_runner.impala_ds,redash.query_runner.vertica,redash.query_runner.clickhouse,redash.query_runner.yandex_metrica,redash.query_runner.rockset,redash.query_runner.treasuredata,redash.query_runner.dynamodb_sql,redash.query_runner.mssql,redash.query_runner.memsql_ds,redash.query_runner.mapd,redash.query_runner.jql,redash.query_runner.google_analytics,redash.query_runner.axibase_tsd,redash.query_runner.salesforce,redash.query_runner.prometheus,redash.query_runner.qubole,redash.query_runner.db2,redash.query_runner.druid,redash.query_runner.kylin,redash.query_runner.drill,redash.query_runner.uptycs,redash.query_runner.snowflake,redash.query_runner.phoenix,redash.query_runner.json_ds,redash.query_runner.cass,redash.query_runner.dgraph,redash.query_runner.azure_kusto
まとめ
とにかくメモリ使用量を減らすことに集中すると、設定を変えるだけでかなり多くのメモリを節約できます。実用性はともかく、ここまでやれば AWS EC2 の t3.micro 相当でもなんとか動かせるのではないかなと思います。
この記事で紹介した設定はあくまでメモリ使用量節約のデモであり、そのまま使うことはおすすめできませんが、使っていないデータソースの精査だけでも効果が大きいというのを以前の記事でもご紹介していますので、まずはそこから手を付けてみるのが良いと思います。
この記事が Redash の運用でお困りのかたの役に立つとうれしいです。
Redash v8.0.0 の環境を構築する3行のコマンド
まえがき
フォーラムで質問いただいたので、2019/12時点でサクッと環境構築できる方法を確かめてみました。
使用しているバージョンは記事執筆時点で最新の安定版リリースである v8.0.0。AWS を使用していない方も多くいらっしゃると思いますので、Vagrant で立ち上げた VM で検証しました。
使用した Vagrantfile はこちら。 Redash の公式ドキュメントにあわせて、スペックは AWS EC2 の t2.small を意識しています
Vagrant.configure("2") do |config| config.vm.box = "ubuntu/bionic64" config.vm.network "forwarded_port", guest: 80, host: 8080 config.vm.provider "virtualbox" do |vb| vb.cpus = 1 vb.memory = 2048 end end
手順
まっさらな Ubuntu 18.04 で以下を実行します。
$ export REDASH_BRANCH=v8.0.0 $ wget https://raw.githubusercontent.com/getredash/redash/${REDASH_BRANCH}/setup/setup.sh $ sudo -E bash ./setup.sh
Docker イメージの pull に時間がかかりますが、ネットワーク環境がよければ5分ほどでインストールが完了します
確認
先述の Vagrantfile で VM で起動していれば、 http://localhost:8080/ にアクセスすると Redash の画面が確認できます。
ユーザー名など必要な情報を登録して、トップページを表示、右上のメニューをクリックして、v8.0.0 がインストールされていることを確認しました。
まとめ
Redash はバージョンによって導入の仕方が変わることがあり、初心者ユーザーにとっては優しくない一面もありますが、基本的には簡単に導入ができます。
この記事をきっかけに、ひとりでも多く Redash に触れてみようと思ってもらえると嬉しいです。
使われていない、を知る
この記事について
既存の仕組みを「捨てる」というのは得てして影響が大きく、それを実行するには準備と勇気がいる。
builderscon 2019 で聴講した fujiwara さんの「レガシーサーバーを現代の技術で再構築する」の質疑応答で「再構築にあたり、使われていないものを捨てるときにどのように"使われていない"ことを確認するのか」質問させていただいたことを期に、日頃考えていたり、過去に経験したりといったことを書き出してみたくなった。
セッションの内容は大変すばらしいものだったので、ぜひスライドや動画を見ていただきたい。スライドのリンクを見つけられなかったので、セッション詳細のページを紹介しておく。
あまりまとまりがないものになるが、個人のメモだと思ってご容赦いただきたい。
前提
この記事では、主に会社や部署など特定の組織内で利用されているもの。特に Web アプリケーションを対象に扱い、BtoC など組織外の利用者がいるケースは想定していない。
また、以降は対象のアプリケーションや仕組みのことを簡便のために「システム」と呼ぶことにする。
「使われていない」ことを知るために
使われていないという状態は、どのように知ることができるだろう。
現時点で思いつく限りを列挙してみる。
- アクセスログやデータの作成・更新日時から知る
- 運用マニュアルなどが存在する場合は、そのドキュメントを参照する
- 利用者が特定できる場合は、ヒアリングをする
- 利用者にアンケートを取る
- 計画的に対象を停止し、利用者からの反応を見る
アクセスログやデータの作成・更新日時から知る
アクセスログやデータから利用情報を知るというのは、ごく一般的かつ、信頼性の高い方法だと思う。
Web アプリケーションという前提においては、期間はさておき何らかの形でアクセスログは残る。
また、データベースやファイルシステムに保存されたデータの量や更新日時などから、どれぐらい回数や量、どの程度の頻度で利用されているかを掴むことができると。
運用マニュアルなどが存在する場合は、そのドキュメントを参照する
特定の組織内で利用するシステムには、マニュアルや業務フローなどのドキュメント類が整備・定義されていることも多い。
それらの情報に触れることができる場合は、ドキュメントから利用シーン、利用頻度などを読み解くこともできる。
ただし、こういったドキュメント類は「使われていない=メンテナンスされない」となるケースも多く、現在そのドキュメントが取り扱うシステムが使われているかどうかの判断材料にはならないことが多いように思う。
利用者が特定できる場合は、ヒアリングをする
組織内でも特定の部署や担当者が利用するシステムで、それが明らかな場合は、ヒアリングを行うことも有用だ。
対象のシステムが扱う業務ドメインについても豊富な知識を持つ担当者にヒアリングができれば、システムがどのように使われているか、またはいつから使われなくなったか、なぜ使われなくなったかなど、前述のふたつの方法では知ることのできない情報を得ることができることが多い。
しかし、相手は人間になるので、ヒアリングをしてもその場で思い出せなかった、言いそびれてしまった、忘れてしまったということは簡単に起こりうるので、前述の方法で得た情報とあわせてヒアリング内容を精査したほうがよい。
利用者にアンケートを取る
組織内でも不特定。というには大げさだが、組織横断的に利用されているシステムでは、利用者が定まらないようなケースもある。
その場合、何らかの方法でアンケートを取ったり、意見を求めたりすることも利用状況を知る方法となる。
これによって、今まで知りえなかったような情報を想定外の利用者から提供してもらえることなどが期待できるが、アンケートのような手法を取ると、アンケートの設問の設計、回収率などの頭を抱えることになるかもしれない。
計画的に対象を停止し、利用者からの反応を見る
これは当日の質問でも登壇者や参加者、質問者である私も思わず笑ってしまった方法ではあるが、現実においてはあながちトンデモな方法と言えなくもないし、むしろ実践的とも言える側面もあると思う。
前述のどのような方法をとっても、実際にシステムを止めてみないとそれが使われているかどうかを真に知ることは難しい。
ただし、この方法は業務フローに大きな影響を与えてしまう可能性を含んでいるため、計画や実施を慎重におこの合う必要がある。
たとえば、以下のような段階を考えることができる。
- システムの一時停止を告知し、そのスケジュールにあわせてシステムを停止する
- システムの一時停止を告知せず、システムを短期間停止する
各段階のいずれにおいても、ロールバック(再開)の手順は必ず用意しておく。
また、実施する時間帯は業務にあわせて計画する。
早朝や休日など明らかに利用者が居ない時間帯や日程で実行しても得られる情報は少なくなるし、かといって月末、月初、期末の多忙な時期にシステムの停止をすると、リカバリーが難しい規模の業務停止を引き起こしてしまう可能性もある。
まとめ
個人の経験からいくつかの例を挙げつつ、それぞれの方法について意見を書いてみた。
ここで挙げられなかった方法や、こんな方法を取ったことがある。などがあれば、どんな形でもいいので教えてほしい。
この記事が、誰かにとっての Discover Something New になっていたら嬉しい。
あとがき
この記事は builderscon 2019 会場近くのイタリアントマトで書きました。
参加者にランチを提供していただいた、さくらインターネットさん、ごちそうさまでした。
Redash で 502 Bad Gateway が発生したときに見直すべき Gunicorn のタイムアウト
業務で使い倒している Redash で、あるクエリーの結果をダウンロードすると、「502 Bad Gateway」が発生していたので調査・対応したメモ
発生していた現象
行数約28,000行、列数約70の結果を返すクエリーを Excel ダウンロードしようとすると nginx の 「502 Bad Gateway」エラーが発生しファイルがダウンロードできない。条件を絞って取得行数を減らすとダウンロードできる。
調査
nginx のエラーログには以下のようなメッセージが記録されていた。
... upstream prematurely closed connection while reading response header from upstream, client: xxx.xxx.xxx.xxx ...
また、server
コンテナのログには、ワーカーがタイムアウトしたようなログが記録されていた(詳細は割愛)
ここでの「ワーカー」は Celery 上で動く Redash のワーカーではなく、Redash がアプリケーションサーバーとして使用している Gunicorn のワーカーのこと。
対応
エラーログから Gunicorn がタイムアウトしていると推測し、設定を調査した。
結果として、タイムアウトのオプションがあり、それはデフォルトで 30
秒になっていることがわかった。
また、Gunicorn のオプションはコマンドライン引数として与える以外にも、以下のように環境変数で渡すことができる。
$ GUNICORN_CMD_ARGS="--bind=127.0.0.1 --workers=3" gunicorn app:app
Redash は現在 Docker 環境を推奨しているため、コマンドラインオプションの変更ははイメージの再構築が必要になってしまい、相性が悪い。
その点、GUNICORN_CMD_ARGS
環境変数を使えば docker-compose.yml
の変更のみでオプションを適用できる。
これらを踏まえて、以下の設定を docker-compose.yml
の server
サービス内、 environment
に追加した。
GUNICORN_CMD_ARGS: "--timeout 90"
90秒という設定は適当。
docker-compose.yml
を編集後、docker-compose down
、docker-compose up -d
でコンテナを再起動。
エラーが出ていたクエリをブラウザで表示し、クエリー結果を Excel ダウンロードしたところ、ダウンロード成功。
まとめ
Redash でファイルダウンロード時に 502 エラーが発生した際は、Gunicorn のタイムアウトを見直すことで解決することがある。
この記事では Docker 環境で動作している Redash を扱っているが、レガシー(Ubuntu に直接導入)セットアップでも似たような対応ができるはず。
Mackerel アンバサダーになりました
アンバサダープログラムについては以下の記事に詳しく書いてあります。
Mackerel 関連の活動ふりかえり
アンバサダーに選出していただいたので、これまでの活動をざっくり振り返ってみました。
プラグイン開発への参加
Mackerel はエージェントやプラグインを OSS として公開していますが、私も以下のプラグインの開発に微力ながら参加しました。
- mackerel-plugin-aws-rds
- mackerel-plugin-elasticsearch
- mackerel-plugin-td-table-count
- mackerel-plugin-php-fpm
- mackerel-plugin-aws-ec2-ebs
個人の OSS
個人的にもいくつか Mackerel 関連の OSS を公開しています。実装が中途半端なものも多いですが、以下の2つはそれなりに使える状態になっていると思います。
- GitHub - ariarijp/mackerel-plugin-ping: ICMP Ping RTT custom metrics plugin for mackerel-agent.
- GitHub - ariarijp/mackerel-client-php: mackerel-client-php is an unofficial port of mackerelio/mackerel-client-ruby.
ブログなどでの記事公開
改めて振り返ってみると。意外といろいろ書いていました。
- Raspberry PIでGoとmackerel-agentをビルドして動作させてみる - Qiita
- mackerel-agentのARM版バイナリーはRaspberry PI 2でもさくっと動く - Qiita
- MackerelでEC2スポットインスタンスの価格変動を監視する - ariarijp’s blog
- PHP-FPMのステータスをメトリクスとして収集するMackerelプラグインを作った - ariarijp’s blog
- Raspberry PIとUSBマイクとMackerelを組み合わせて、室内の騒音レベルを可視化する - ariarijp’s blog
- mackerel-agent-pluginsにmackerel-plugin-php-fpmが含まれてないんだけど?と言われて調べた - ariarijp’s blog
- mackerel-client-goを使ったBotを作る - ariarijp’s blog
- Mackerel Meetup #9でPHPerとしてLTしてきました - ariarijp’s blog
- Mackerel UG × IDCFクラウド UG Meetup で半飛び込み LT してきました - ariarijp’s blog
イベントでの LT 登壇
参加者としては以下のイベント意外にも参加したことがありますが、2度ほど LT 枠で登壇したこともありました。
今後の活動について
アンバサダーになったからといって、変に気負って Mackerel 関連の活動をすることは無いと思いますが、Mackerel は気に入っているプロダクトのひとつなので、今後もなんらかの形でコミュニティやエコシステムに関わりたいと思っています。
Happy Monitoring !!