Blazerで異常値検知を試してみる

先日の記事の続きです。

ariarijp.hatenablog.com

Blazerで異常値検知も試してみました。

検証に使用したVagrantfileは以下のものです。

github.com

vagrant up してBlazerを起動し、ブラウザでアクセスできる状態を前提にします。

サンプルを見てみる

Vagrantfileで使用している ankane/blazer-dev では、開発用のリポジトリであるためか、デフォルトで異常値検知が有効になっています。

...省略...
anomaly_checks: true
...省略...

http://localhost:3000/queries/12-check-for-anomalies にアクセスすると、以下のような画面が表示されます。

f:id:ariarijp:20180113143909p:plain

FAILING · Anomaly detected in new_ratings というメッセージが表示されており、 new_ratings の値の推移にAnomalyな値が検出されたことがわかります。

このクエリで実行されているSQLを見てみます。

http://localhost:3000/queries/12-check-for-anomalies/edit にアクセスすると、SQLの編集画面が表示され、以下のようなSQLが実行されていることがわかります。

SELECT date_trunc('week', rated_at)::date AS week, COUNT(*) AS new_ratings FROM ratings GROUP BY week ORDER BY week

SQLをいじってみる

先程は異常検知されていたので、このクエリを少し変えて、異常値が検出されないようにしてみます。

SELECT date_trunc('week', rated_at)::date AS week, COUNT(*) AS new_ratings FROM ratings GROUP BY week HAVING COUNT(*) < 5000 ORDER BY week

HAVING 句で5000件以上の行をフィルタしています。このSQLを保存し、再度クエリを実行してみると、以下のような画面が表示されます。

f:id:ariarijp:20180113144419p:plain

PASSING · No anomalies detected というメッセージが表示されており、異常値が検出されていないことがわかります。

さらにSQLを変更し、再度異常検知されるようにしてみます。

SELECT
    date_trunc('week', rated_at)::date AS week,
    CASE
        WHEN
            date_trunc('week', rated_at)::date = to_date('1998-03-09', 'YYYY-MM-DD') THEN CAST (0 AS BIGINT)
        WHEN
            date_trunc('week', rated_at)::date = to_date('1998-03-16', 'YYYY-MM-DD') THEN CAST(0 AS BIGINT)
        WHEN
            date_trunc('week', rated_at)::date = to_date('1998-03-23', 'YYYY-MM-DD') THEN CAST(0 AS BIGINT)
        ELSE COUNT(*)
    END AS new_ratings
FROM
    ratings
GROUP BY
    week HAVING COUNT(*) < 5000
ORDER BY
    week

少し長くなりましたが、もとのSQLが週単位でデータを取っているので、1998-03-09-1998-03-23週のデータを無理やり0にしてみました。 このSQLを保存し、再度クエリを実行してみると、また異常値が検知されます。

f:id:ariarijp:20180113150512p:plain

ちなみに、1週分のデータだけ0にしても異常値としては認識されませんでした。このあたりのチューニングはできるのかもしれませんが、今回はそこまで調べていません。

まとめ

データ分析などを専門にしていないエンジニアでも、Blazer(というよりRのtwitter/AnomalyDetectionパッケージ)によって異常検知が簡単に利用できました。

他のOSSのBIツールではあまり見かけた記憶がないので、異常値検知はBlazerの特徴ひとつになるかもしれません。

Rもちょっとしたパッケージを使えるぐらいには勉強しようかな。

Rではじめるデータサイエンス

Rではじめるデータサイエンス

表参道.rb #30でBlazerについて調べて発表してきた

得意の当日LT応募で参加してきました。

omotesandorb.connpass.com

発表スライドはこちら。

speakerdeck.com

通勤中にconnpassを見ていて、LTテーマがフリーだったのでRedashっぽいRubyで書かれたBIなんかがあれば話せそう。と思った矢先、Blazerを見つけたのはラッキーでした。 Star数もかなり多いわりに日本語の記事もなかったので、LTネタとしてかなり助かりました。

github.com

Redashっぽいところもありつつ、RailsアプリなのでRailsらしさのようなものも感じられて、BI/可視化ツール好きにとってはなかなかおもしろかったです。

資料には含まれていませんが、Rをインストールして何かをゴニョゴニョすると異常値検知もできるらしいので、それについてはまた調べてみるつもりです。

表参道.rbでの発表は3回目で、過去に#1#14で発表していたので、次回は#45あたりにLT参加したいと思っています。

Rubyistに囲まれたせいか、少しRuby書きたくなったので、さくらんぼ本を買うか悩む。

Redashの開発環境をあえてVagrantで構築する

はじめに

Redash は公式ドキュメントでは、開発環境には Docker を使うことを推奨されています。

Guide · Redash Help Center

以前は Redash のリポジトリVagrantfile も含まれていましたが、今ではDocker移行を推奨するためか削除されています。

Docker を使うようになったことで、環境構築がかなり気軽にできるようになりました。 Redash Meetup ハンズオンで使用している以下の資料も、Docker を使った環境構築手順になっています。

github.com

しかし、Redash のコードを追っていったり、ミドルウェア周りの調査で DB や稼働プロセスを覗き見したりするときは、VagrantVM を1台起動して、その中にRedash も PostgreSQL も Redis も入っている方が便利なことがあります。

この記事では、あえて今 Vagrant で Redash の環境構築をする方法を紹介します。

環境構築

前置きが長くなりましたが、とても簡単です。

前提条件

以下の環境で動作確認しました。

手順

Redash のバージョン v3.0.0 の環境を構築します。

$ mkdir redash_on_vagrant
$ cd redash_on_vagrant
$ wget https://raw.githubusercontent.com/ariarijp/vagrantfiles/master/redash/Vagrantfile
$ vagrant up

Vagrant が使える状態になっていれば、手順は上記のコマンドだけです。

VM が起動するまで10-15分ほど時間がかかりますが、ほとんど cassandra-driver のビルド待ちです。気長に待ちましょう。

動作確認

ブラウザで http://localhost:8080/setup にアクセスすると、Redash ユーザーには見慣れた画面が表示されます。

f:id:ariarijp:20180104212003p:plain

Vagrant で環境構築をするメリットである、「全部入り」になっていることを確認するため、 VM 上で ps コマンドを実行してみます。

$ vagrant ssh -- ps axuf
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
...省略...
postgres 14048  0.0  1.1 293424 24424 ?        S    12:10   0:00 /usr/lib/postgresql/9.5/bin/postgres -D /var/lib/postgresql/9.5/main -c config_file=/etc/postgresql/9.5/main/postgresql.conf
postgres 14050  0.0  0.3 293556  6316 ?        Ss   12:10   0:00  \_ postgres: checkpointer process   
postgres 14051  0.0  0.2 293424  5624 ?        Ss   12:10   0:00  \_ postgres: writer process   
postgres 14052  0.0  0.4 293424  8800 ?        Ss   12:10   0:00  \_ postgres: wal writer process   
postgres 14053  0.0  0.3 293852  6628 ?        Ss   12:10   0:00  \_ postgres: autovacuum launcher process   
postgres 14054  0.0  0.1 148568  3188 ?        Ss   12:10   0:00  \_ postgres: stats collector process   
postgres 17700  0.0  0.7 300764 16148 ?        Ss   12:18   0:00  \_ postgres: redash redash [local] idle
postgres 17701  0.0  0.7 300716 15868 ?        Ss   12:18   0:00  \_ postgres: redash redash [local] idle
postgres 17702  0.0  0.7 300716 15004 ?        Ss   12:18   0:00  \_ postgres: redash redash [local] idle
postgres 17704  0.0  0.7 301292 16376 ?        Ss   12:19   0:00  \_ postgres: redash redash [local] idle
postgres 17705  0.0  0.7 300716 15068 ?        Ss   12:19   0:00  \_ postgres: redash redash [local] idle
redis    14267  0.1  0.5  37228 10420 ?        Ssl  12:10   0:00 /usr/bin/redis-server 127.0.0.1:6379
root     17621  0.0  0.9  57376 19880 ?        Ss   12:18   0:00 /usr/bin/python /usr/bin/supervisord -n -c /etc/supervisor/supervisord.conf
redash   17658  0.6  4.7 293576 96684 ?        S    12:18   0:01  \_ [celeryd: celery@ubuntu-xenial:MainProcess] -active- (worker --app=redash.worker --beat -c2 -Qqueries,celery --maxtasksperchild=10 -Ofair)
redash   17695  0.1  4.7 303888 97108 ?        S    12:18   0:00  |   \_ [celeryd: celery@ubuntu-xenial:Worker-2]
redash   17697  0.1  4.7 303892 96996 ?        S    12:18   0:00  |   \_ [celeryd: celery@ubuntu-xenial:Worker-3]
redash   17698  0.0  4.3 301300 90004 ?        S    12:18   0:00  |   \_ [celery beat]
redash   17659  0.0  0.9  55952 18516 ?        S    12:18   0:00  \_ gunicorn: master [redash]
redash   17682  0.4  4.9 293476 101916 ?       S    12:18   0:01  |   \_ gunicorn: worker [redash]
redash   17684  0.4  4.9 293080 101352 ?       S    12:18   0:01  |   \_ gunicorn: worker [redash]
redash   17688  0.4  4.9 293892 102296 ?       S    12:18   0:01  |   \_ gunicorn: worker [redash]
redash   17691  0.4  4.9 294152 102324 ?       S    12:18   0:01  |   \_ gunicorn: worker [redash]
redash   17660  0.6  4.7 293296 96688 ?        S    12:18   0:01  \_ [celeryd: celery@ubuntu-xenial:MainProcess] -active- (worker --app=redash.worker -c2 -Qscheduled_queries --maxtasksperchild=10 -Ofair)
redash   17694  0.0  4.6 302564 94268 ?        S    12:18   0:00      \_ [celeryd: celery@ubuntu-xenial:Worker-1]
redash   17696  0.0  4.6 302564 94476 ?        S    12:18   0:00      \_ [celeryd: celery@ubuntu-xenial:Worker-2]
root     17647  0.0  0.0 124972  1436 ?        Ss   12:18   0:00 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
www-data 17648  0.0  0.1 125348  3148 ?        S    12:18   0:00  \_ nginx: worker process
www-data 17649  0.0  0.2 125420  4844 ?        S    12:18   0:00  \_ nginx: worker process
...省略...

Redash の主要なプロセスが稼働していることがわかりました。

Redash のソースコード一式は /opt/redash 以下にあります。

$ vagrant ssh -- ls -la /opt/redash
total 16
drwxr-xr-x 3 redash root    4096 Jan  4 12:34 .
drwxr-xr-x 3 root   root    4096 Jan  4 12:34 ..
lrwxrwxrwx 1 root   root      30 Jan  4 12:34 current -> /opt/redash/redash.3.0.0.b3134
-rw-r--r-- 1 redash nogroup  191 Jan  4 12:34 .env
drwxr-xr-x 9 redash nogroup 4096 Jan  4 12:34 redash.3.0.0.b3134

あとは vagrant ssh してコードを変えてみたり、ミドルウェアの設定を変えてみたりといろいろ試せます。

まとめ

Vagrant でも、それなりに簡単に Redash の環境を構築することができるようになりました。

Docker に少し苦手意識があるけど Redash を試してみたい方にも、この記事が参考になるかもしれません。

実践 Vagrant

実践 Vagrant

Redashについていろいろ調べるときに頭のなかでイメージしている図

draw.ioを試してみたかったので、試してみたついでにメモ。

Flowchart Maker & Online Diagram Software

構成図

間違っているところもあるかもしれないけど、こんな図をイメージしている。

f:id:ariarijp:20180103223507p:plain

備考

図には書いてないけどRedash ServerはFlask、Redash WorkerはCelery上で動く。このあたりは以下の記事にメモした。

ariarijp.hatenablog.com

基本的にWorkerしかデータソースに触らない。

ただし、データソース設定画面でTest Connectionした時はServerからデータソースにアクセスする。

Redashのメモリ使用量を節約する

IaaSが一般化してからメモリで悩むことは減りましたが、それでも無駄は減らしたいものです。

この記事ではRedashのメモリ使用量の節約について紹介します。

前提条件

以下の環境で検証しました。

コンテナのメモリ使用量確認にはctopを使用します。

github.com

検証準備

$ git clone git@github.com:getredash/redash.git
$ git checkout refs/tags/v3.0.0
$ docker-compose -f docker-compose.production.yml run --rm server create_db
$ docker-compose -f docker-compose.production.yml up

docker-compose.production.yml はRedashのバージョンを以下のように固定しました。

@@ -7,7 +7,7 @@
 version: '2'
 services:
   server:
-    image: redash/redash:latest
+    image: redash/redash:3.0.0.b3147
     command: server
     depends_on:
       - postgres
@@ -23,7 +23,7 @@ services:
       REDASH_WEB_WORKERS: 4
     restart: always
   worker:
-    image: redash/redash:latest
+    image: redash/redash:3.0.0.b3147
     command: scheduler
     environment:
       PYTHONUNBUFFERED: 0

デフォルトのメモリ使用量

ctop で確認します。

   NAME                     CID                      CPU                      MEM                      NET RX/TX                IO R/W                   PIDS

 ◉  redash_nginx_1           e99e574f0b9d                         0%                   1M / 1.95G       816B / 0B                0B / 0B                  2
 ◉  redash_postgres_1        7f190ff29476                         0%                  57M / 1.95G       24K / 14K                0B / 44M                 6
 ◉  redash_redis_1           7423c68518f1                         0%                   1M / 1.95G       26K / 24K                160K / 0B                3
 ◉  redash_server_1          0b2a249270f8                         0%                  348M / 1.95G      3K / 3K                  60K / 0B                 5
 ◉  redash_worker_1          87ee7979b2ad                         0%                  195M / 1.95G      22K / 21K                288K / 12K               4

server が約350MB、 worker が約200MBほどメモリを使用しています。他のコンテナについてはこの記事では扱いません。

ミドルウェアの設定でメモリ使用量を節約する

ミドルウェア周りで調整できそうなものを考えます

これらの設定はRedashの環境変数で変更できるので、以下のように docker-compose.production.yml を変更します。

@@ -7,7 +7,7 @@
 version: '2'
 services:
   server:
-    image: redash/redash:latest
+    image: redash/redash:3.0.0.b3147
     command: server
     depends_on:
       - postgres
@@ -20,10 +20,10 @@ services:
       REDASH_REDIS_URL: "redis://redis:6379/0"
       REDASH_DATABASE_URL: "postgresql://postgres@postgres/postgres"
       REDASH_COOKIE_SECRET: veryverysecret
-      REDASH_WEB_WORKERS: 4
+      REDASH_WEB_WORKERS: 1
     restart: always
   worker:
-    image: redash/redash:latest
+    image: redash/redash:3.0.0.b3147
     command: scheduler
     environment:
       PYTHONUNBUFFERED: 0
@@ -31,7 +31,7 @@ services:
       REDASH_REDIS_URL: "redis://redis:6379/0"
       REDASH_DATABASE_URL: "postgresql://postgres@postgres/postgres"
       QUEUES: "queries,scheduled_queries,celery"
-      WORKERS_COUNT: 2
+      WORKERS_COUNT: 1
     restart: always
   redis:
     image: redis:3.0-alpine

再度コンテナを作り直して、Redashを起動します。

$ docker-compose -f docker-compose.production.yml rm
$ docker-compose -f docker-compose.production.yml run --rm server create_db
$ docker-compose -f docker-compose.production.yml up

ctop で確認します。

   NAME                     CID                      CPU                      MEM                      NET RX/TX                IO R/W                   PIDS

 ◉  redash_nginx_1           a063c735099a                         0%                   1M / 1.95G       992B / 0B                0B / 0B                  2
 ◉  redash_postgres_1        26fdae3b9f2c                         0%                  59M / 1.95G       27K / 18K                0B / 44M                 7
 ◉  redash_redis_1           433f533a2bc3                         0%                   1M / 1.95G       52K / 43K                0B / 0B                  3
 ◉  redash_server_1          71fd4978d9a8                         0%                  101M / 1.95G      1K / 1K                  0B / 0B                  2
 ◉  redash_worker_1          dab363fafcab                         0%                  168M / 1.95G      45K / 51K                0B / 16K                 3

server が約100MB、 worker が約170MBほどメモリを使用しています。実用上どこまで詰めていいかは使いながら調整になりますが、ミドルウェアのプロセス数調整は効果がありそうです。

Redashの設定ファイルを変更してメモリ使用量を節約する

もうすこし切り詰めていきます。

Redashの設定はたいてい環境変数で変更可能ですが redash/settings.py のみで変更できるものもあるので、その設定を変更します。

データソースの種類を減らす

Redashの利点のひとつは、多くのデータソースに対応していることですが、どのデータソースを利用可能にするかは redash/settings.py に定義されています。

試しに、BigQuery、GoogleスプレッドシートMySQLPostgreSQLGoogle Analytics、Query Resultsだけを使用するように設定を変更します。

@@ -199,30 +199,11 @@ ACCESS_CONTROL_ALLOW_HEADERS = os.environ.get("REDASH_CORS_ACCESS_CONTROL_ALLOW_

 # Query Runners
 default_query_runners = [
-    'redash.query_runner.athena',
     'redash.query_runner.big_query',
     'redash.query_runner.google_spreadsheets',
-    'redash.query_runner.graphite',
-    'redash.query_runner.mongodb',
     'redash.query_runner.mysql',
     'redash.query_runner.pg',
-    'redash.query_runner.url',
-    'redash.query_runner.influx_db',
-    'redash.query_runner.elasticsearch',
-    'redash.query_runner.presto',
-    'redash.query_runner.hive_ds',
-    'redash.query_runner.impala_ds',
-    'redash.query_runner.vertica',
-    'redash.query_runner.clickhouse',
-    'redash.query_runner.treasuredata',
-    'redash.query_runner.sqlite',
-    'redash.query_runner.dynamodb_sql',
-    'redash.query_runner.mssql',
-    'redash.query_runner.memsql_ds',
-    'redash.query_runner.jql',
     'redash.query_runner.google_analytics',
-    'redash.query_runner.axibase_tsd',
-    'redash.query_runner.salesforce',
     'redash.query_runner.query_results'
 ]

再度コンテナを作り直し、設定をコンテナにコピーしてからRedashを起動します。

$ docker-compose -f docker-compose.production.yml rm
$ docker-compose -f docker-compose.production.yml create
$ docker cp redash/settings.py redash_worker_1:/app/redash/settings.py
$ docker cp redash/settings.py redash_server_1:/app/redash/settings.py
$ docker-compose -f docker-compose.production.yml run --rm server create_db
$ docker-compose -f docker-compose.production.yml up

ctop で確認します。

   NAME                   CID                    CPU                    MEM                    NET RX/TX              IO R/W                 PIDS

 ◉  redash_nginx_1         f821d84a023a                      0%                 1M / 1.95G      886B / 0B              0B / 0B                2
 ◉  redash_postgres_1      2270aa342a0c                      0%                57M / 1.95G      25K / 15K              0B / 43M               6
 ◉  redash_redis_1         1315adf2f232                      0%                 1M / 1.95G      29K / 26K              0B / 0B                3
 ◉  redash_server_1        53b407a5f23b                      0%                79M / 1.95G      1K / 1006B             0B / 0B                2
 ◉  redash_worker_1        6452b35d9227                      0%                132M / 1.95G     25K / 25K              0B / 12K               3

server が約80MB、 worker が約130MBほどメモリを使用しています。不要なデータソース対応を切り詰めるのもメモリ消費量節約に効果がありそうです。

プロセス数をデフォルトに戻す

データソース対応を減らした状態で、プロセス数はもとに戻してみます。

$ docker-compose -f docker-compose.production.yml rm
$ docker-compose -f docker-compose.production.yml create
$ docker cp redash/settings.py redash_worker_1:/app/redash/settings.py
$ docker cp redash/settings.py redash_server_1:/app/redash/settings.py
$ docker-compose -f docker-compose.production.yml run --rm server create_db
$ docker-compose -f docker-compose.production.yml up

ctop で確認します。

   NAME                   CID                    CPU                    MEM                    NET RX/TX              IO R/W                 PIDS

 ◉  redash_nginx_1         d76e0f2476be                      0%                 1M / 1.95G      816B / 0B              0B / 0B                2
 ◉  redash_postgres_1      808563ad0d67                      0%                57M / 1.95G      24K / 15K              0B / 43M               6
 ◉  redash_redis_1         91ebe6d65268                      0%                 1M / 1.95G      27K / 25K              0B / 0B                3
 ◉  redash_server_1        f0adc13795f5                      0%                269M / 1.95G     3K / 3K                0B / 0B                5
 ◉  redash_worker_1        bebaf0d04026                      0%                159M / 1.95G     23K / 22K              76K / 12K              4

server が約270MB、 worker が約160MBほどメモリを使用しています。

データソース対応を減らすだけでも、デフォルトと比較して server で約80MB、 worker で約40MBほどメモリ使用量を節約できました。

プロセス数などはRedashの利用状況にあわせてチューニングしなければいけない一方、データソース対応は比較的気軽に変更できることが多いので、Redashの導入や設定見直しの際は確認してみることをおすすめします。

まとめ

RedashはRaspberry Piでも動くという記事を書きましたが、メモリ使用量は少ないに越したことはありません。

節約できたぶんをGunicornやCeleryに割り当て、さらに快適にRedashを使うということもできると思います。