株式会社クリアコード > ククログ

ククログ

«前月 最新 翌月»
タグ:

Firefoxで外部アプリケーションを起動するだけのアドオンをGo言語で作る方法と注意点

キーワード:golang, バックグラウンド実行, detach

Firefoxのアドオンは、現在はWebExtensionsというAPI群に基づいて開発するようになっています。 このAPI群には「別のブラウザなどの任意のローカルアプリケーションを直接起動する機能」は含まれておらず、そのようなことをしたい場合にはNative Messagingという仕組みで間接的に実現する必要があります。 これは要するに、「コマンドラインオプションやGUIではなく標準入力から与えられる情報を使って、任意のアプリケーションを起動するランチャー」を開発するということです。 関係を図にすると以下のようになります。

+---------------------+
|       Firefox       |   
|+-------------------+|
||Firefox上のアドオン||
|+-------------------+|
|        ↓↑         |
| <WebExtensions API> |
| (Native Messaging)  |
+--------↓↑---------+
     <標準入出力>
         ↓↑
+---------------------+
|      ランチャー     |
+---------------------+
          ↓
   <システムコール>
          ↓
+---------------------+
|外部アプリケーション |
+---------------------+

このNative Messagingの仕組み自体は、細部を除けばGoogle Chrome用拡張機能での仕組みとほぼ同じ仕様です。 そのためFirefoxとChromeに両対応した実装が既にいくつか存在しており、中には上記のようなランチャーとして振る舞う物もあります。 例えばOpen InというプロジェクトではNode.jsベースで開発されたランチャーアプリケーションの実装を使っています。

この記事では、これと似たような物をGo言語で実装する時の注意点を解説します。

起動したい外部アプリケーションが巻き込みで終了されてしまう問題

Go言語では、外部アプリケーションを起動する方法としてexecパッケージを使うのが一般的です。 このパッケージでは同期実行(外部アプリケーションの終了を待ってから次の処理に進む)のexec.Command().Run()と非同期実行(外部アプリケーションを起動した後、すぐに次の処理に進む)のexec.Command().Start()の2つの機能が提供されています。

例えば、FirefoxのWebページ上のコンテキストメニューに「このページをInternet Explorerで開く」のような項目を追加してそこから別のブラウザを起動するというような場合、exec.Command().Run()でIEを起動するとIEを終了するまでの間ずっとランチャーアプリケーションのプロセスが生き続けることになります。 また、そこから起動されるIEのプロセスはFirefoxから見て孫プロセスという扱いになりますので、うっかりその状態でFirefoxを終了すると、孫プロセスになっているIEまでもがまとめて終了されてしまいます。

ということから、このような場面ではexec.Command().Start()の方を使えばよいと考えられるのですが、実際には期待した通りの結果になりません。 こちらで起動した場合でもIEのプロセスは孫プロセスになってしまい、ランチャーがexec.Command().Start()を実行してIEを起動した後でmain()の最後に到達してプロセスが終了すると(Firefoxがランチャーを終了させると)、やはり孫プロセスのIEまで巻き添えで終了されてしまうのです。

プロセスグループを分けての外部アプリケーションの起動

このような現象が発生するのは、Firefox・ランチャー・孫プロセスとして起動されたIEの全てが同じプロセスグループに属しているからです。 言い換えると、ランチャーが起動する孫プロセスについてプロセスグループを分ければ(プロセスをデタッチすれば)、Firefoxやランチャーが終了した後もIEを動作させ続けられると考えられます。 Go言語の場合、一般的にはこれは以下のようにして実現できます。

...
import (
  "os/exec"
  "syscall"
  "log"
)
...

func Launch(path string, args []string) {
  command := exec.Command(path, args...)

  // Windowsの場合
  command.SysProcAttr = &syscall.SysProcAttr{CreationFlags: syscall.CREATE_NEW_PROCESS_GROUP}
  // Linux, maxOS (POSIX)の場合
  // command.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}

  err := command.Start()
  if err != nil {
    log.Fatal(err)
  }
}

システムコールに渡すパラメータを指定する必要があるため、Windowsとそれ以外の環境とでは書き方が変わってきます。

このようにすることで晴れてプロセスグループが分かれてくれて、ランチャー終了後も外部アプリケーションが生き続けるようになってくれる……と思われたのですが、実際にWindows環境のFirefoxで検証してみたところ、残念ながら期待通りの結果は得られませんでした。

上記のようなコードを使って一般的なコマンドラインアプリケーションとして起動する状態にしたランチャーで試す分には、期待通りの振る舞い(ランチャーの終了後も外部アプリケーションのプロセスが残る)を見せました。 しかし、FirefoxのアドオンからNative Messagingの仕組みを経由して起動されるNative Messaging Hostとしてランチャーを動作させると、依然として外部アプリケーションまで終了されてしまうのでした。

Firefoxに固有の事情

これは、Go言語一般の話や、Google Chromeなどと共通の仕組みとしてのNative Messagingではなく、Firefox固有の事情による現象です。

実はWebExtensionsにおけるNative Messagingの説明に記載がありますが、Windowsにおいてこのようなランチャーから外部のプロセスを起動する際は、CREATE_NEW_PROCESS_GROUPではなくCREATE_BREAKAWAY_FROM_JOBという定数で示されるフラグを指定する必要があります。

Go言語の場合はsyscallモジュールにこの定数の定義が含まれていないため、仕様に基づいて0x01000000という数値を直接記述することになります。

func Launch(path string, args []string) {
  command := exec.Command(path, args...)
  // CREATE_BREAKAWAY_FROM_JOB = 0x01000000
  command.SysProcAttr = &syscall.SysProcAttr{CreationFlags: 0x01000000}
  err := command.Start()
  if err != nil {
    log.Fatal(err)
  }
}

WebExtensionsの元になっているGoogle ChromeのNative Messagingの仕様では特にこのような指定は必要ないため、ChromeとFirefoxの両方に対応したNative Messaging Hostを開発する際には注意が必要です。

このようにフラグを指定して実行すると、無事期待する通りの結果を得ることができました。

(この情報は本記事の初版に対するフィードバックで教えていただきました。ご指摘ありがとうございます。)

有効だった回避策(Windows向け)

結論から述べると、この問題は以下のようなバッチファイルで解決できました。

@ECHO OFF

start %*

これは、自身にコマンドライン引数として渡された内容をそのままコマンド列として非同期に実行するというバッチファイルです。 ランチャーから外部アプリケーションを起動する際に、直接起動せずこのバッチファイル(※正確にはcmd.exe)を介して起動するという使い方をします。

この時の各ソフトウェア同士の関係を図にすると、以下のようになります。

+---------------------+
|       Firefox       |   
|+-------------------+|
||Firefox上のアドオン||
|+-------------------+|
|        ↓↑         |
| <WebExtensions APi> |
| (Native Messaging)  |
+--------↓↑---------+
     <標準入出力>
         ↓↑
+---------------------+
|      ランチャー     |
+---------------------+
          ↓
   <システムコール>
          ↓
+---------------------+
|    バッチファイル   |
+---------------------+
          ↓
   <startコマンド>
          ↓
+---------------------+
|外部アプリケーション |
+---------------------+

単純なのですが、これによってバッチファイルから先のプロセスが別のプロセスグループに分かれるようになり、FirefoxからNative Messaging Hostとしてランチャーを起動した場合でも、Firefoxの終了後も外部アプリケーションのプロセスが残り続けるようになりました。 また、このような動作をさせる場合、ランチャーでバッチファイルを起動する際にはcommand.SysProcAttrの指定はあってもなくても結果は変わりませんでした。

なお、バッチファイルを使うとなるとcmd.exe(コマンドプロンプト)のウィンドウが一瞬表示されるのではないかという懸念もありましたが、実際には特にそのようなこともなく自然に外部アプリケーションが起動しました。 これも、Firefoxがランチャーを起動する際に与えている何らかの指定の影響ではないかと考えられます。

まとめ

以上、Go言語で実装したランチャーを経由してFirefoxから外部アプリケーションを起動する際に、Firefoxが終了した後も外部アプリケーションを起動した状態のままとするためには、バッチファイルを使うとよいCREATE_BREAKAWAY_FROM_JOBフラグの指定が必要であるという注意点をご紹介しました。

環境によってはバッチファイルの実行自体が制限されている場合もあるかもしれません。実際に動作するかどうか、はあらかじめ確認を取っていただくことを強くお勧めします。

FirefoxのWebExtensions APIはGoogle Chromeの拡張機能向けAPIを参考に設計されています。そのためChrome用拡張機能の開発でのノウハウの多くを流用することができ、何か詰まった時は「Chrome用拡張機能ではどうするのが普通なのか?」という観点で調べれば解決策が見つかることが多いです。

しかしながら両者は完全に同一のものではなく、前述のようなFirefoxに固有の注意事項というものもあります。本記事の初版公開時には、オフィシャルのドキュメントにある注意書きを見落としたまま先入観からChrome用拡張機能向けの情報だけを調査していた結果、肝心な情報に全く辿り着けないという結果となっていました。検索も万能ではない(検索語句がずれていると必要な情報に辿り着けない)ために頼りすぎる事・その時得られた結果を過信しすぎる事のリスク、先入観に囚われずにオフィシャルの情報を丁寧に読む事の重要性を改めて実感した次第です。

タグ: Mozilla
2017-09-01

Zulip & PGroonga Night - PGroonga & Zulip #zpnight

ZulipPGroongaサポートを実装した須藤です。PyCon JP 2017に参加するためにZulipの開発者の1人であるGregさんが来ていたので、日本PostgreSQLユーザ会(JPUG)さんに主催してもらってZulipとPGroongaのイベント「Zulip & PGroonga Night」を開催しました。

なお、GregさんのPyConJP 2017でのトーク「Clearer Code at Scale: Static Types at Zulip and Dropbox」(動画)はPyConJP 2017のベストトークに選ばれました。すごい!

Zulip & PGroonga NightではPGroongaの紹介とZulipの全文検索インデックスの更新方法の紹介をしました。

関連リンク:

背景

ZulipではPostgreSQL標準のtextsearchを使って全文検索を実現しています。textsearchは言語特化型のインデックスを作るため、同時に複数の言語をサポートすることができません。また、日本語を含むアジア圏の言語のサポートが不十分なため、日本語を全文検索できないという問題もあります。

そこで、私はZulipでPGroongaを使えるようにしました。PGroongaは言語特化型のインデックスも言語非依存のインデックスも作れます。言語非依存のインデックスを作れば同時に日本語も英語もいい感じに全文検索できます。

クリアコードがZulipを選んだ理由

私がZulipにPGroongaサポートパッチを送ったのは自分たちが必要だからです。クリアコードではチャットツールとしてZulipを使っています。その前はSkypeを使っていました。お客さんとの連絡でSkypeを使う必要があったため、その流れでなんとなく使っていました。Skypeはあまり活用していませんでした。

クリアコードはフリーソフトウェアを推進したい会社なのでフリーソフトウェアではないSkypeを使っていることをどうにかしたいと考えていました。そこで、いくつかフリーソフトウェアなチャットツールを検討しました。そのうちの1つがZulipでした。Zulipのネックは日本語全文検索できないことでした。ネックがあるので選択肢から外すという考え方もあると思いますが、私たちは、自分たちで日本語全文検索できるようにして使うことにしました。フリーソフトウェアのよいところは自分たちで改良できることだからです。

Zulipの全文検索インデックスの更新方法

Zulipは書き込み時のレイテンシーを小さくしておくために工夫をしています。チャットアプリケーションでは書き込みがすぐに終わることはよい使い勝手に直結するからです。

書き込み時はデータをPostgreSQLに書き込むだけで、全文検索インデックスの更新は別途バックグラウンドで実行します。このためにトリガーとNOTIFYLISTENを使っています。

具体的な実装を簡単に紹介します。興味のある人はZulipのコードを見てください。既存のコードから学習することができることもフリーソフトウェアのよいところです。

zerver_messageがメッセージ(チャットの書き込み)を保存しているテーブルです。この中に全文検索対象のデータを入れるカラムを定義します。メッセージのテキストそのものとは別に定義することがポイントです。search_tsvectorがそのカラムです。(PGroongaを使うときの実装ではなくtextsearchを使うときの実装です。)

CREATE TABLE zerver_message (
  rendered_content text,
  -- ... ↓Column for full text search
  search_tsvector tsvector
);

この全文検索対象のデータを入れるカラムには全文検索用のインデックスを作ります。(この例ではPGroongaのインデックスではなくtextsearchのインデックスを作っています。)

CREATE INDEX zerver_message_search_tsvector
  ON zerver_message
  USING gin (search_tsvector);

このメッセージ用のテーブルにトリガーを設定します。このトリガーはメッセージが追加・更新されたときに「更新ログ」テーブル(fts_update_logテーブル)にメッセージのIDを追加します。

-- Execute append_to_fts_update_log() on change
CREATE TRIGGER
  zerver_message_update_search_tsvector_async
  BEFORE INSERT OR UPDATE OF rendered_content
    ON zerver_message
  FOR EACH ROW
    EXECUTE PROCEDURE append_to_fts_update_log();

メッセージのIDを追加する関数の実装は次のようになります

-- Insert ID to fts_update_log table
CREATE FUNCTION append_to_fts_update_log()
  RETURNS trigger
  LANGUAGE plpgsql AS $$
    BEGIN
      INSERT INTO fts_update_log (message_id)
        VALUES (NEW.id);
      RETURN NEW;
    END
$$;

「更新ログ」テーブルの定義は次の通りです。全文検索インデックスを更新するべきメッセージのIDを入れているだけです。

-- Keep ID to be updated
CREATE TABLE fts_update_log (
  id SERIAL PRIMARY KEY,
  message_id INTEGER NOT NULL
);

これで後から全文検索インデックスを更新するための情報を保存する仕組みができました。通常通りメッセージテーブルを操作するだけで実現できていることがポイントです。こうすることでアプリケーション側をシンプルにしておけます。残りの処理は、後から全文検索インデックスを更新する、です。

この処理のためにNOTIFYLISTENを使います。NOTIFYLISTENしている接続に通知する仕組みです。LISTENしている接続はNOTIFYされるまでブロックします。NOTIFYLISTENを組み合わせることで、ポーリングしなくてもイベントが発生したことに気づくことができます。

今回のケースでは「更新ログが増えた」というイベントに気づきたいです。このイベントが来たら全文検索インデックスを更新したいからです。

そのために、「更新ログ」テーブルにトリガーを追加します。「更新ログ」テーブルにレコードが追加されたらNOTIFYするトリガーです。

-- Execute do_notify_fts_update_log() on INSERT
CREATE TRIGGER fts_update_log_notify
  AFTER INSERT ON fts_update_log
  FOR EACH STATEMENT
    EXECUTE PROCEDURE
      do_notify_fts_update_log();

NOTIFYする関数の実装は次の通りです。この関数を実行すると、fts_update_logというイベントをLISTENしている接続のブロックが解除されます。

-- NOTIFY to fts_update_log channel!
CREATE FUNCTION do_notify_fts_update_log()
  RETURNS trigger
  LANGUAGE plpgsql AS $$
    BEGIN
      NOTIFY fts_update_log;
      RETURN NEW;
    END
  $$;

全文検索のインデックスを更新するSQLはPythonから発行しています。全文検索のインデックスの更新処理は必要なときだけ(更新ログがあるときだけ)実行したいです。必要がないときも更新処理を実行し続けるとムダにCPUを使ってしまうからです。

必要なときだけ処理を実行するために、LISTENでブロックします。ブロックが解除されたら(NOTIFYされたら)必ず更新ログがあるので、処理を実行します。↓には入っていませんが、処理が終わったら次のNOTIFYがあるまでまたブロックする実装になっています。こうすることで必要なときだけ処理を実行できるためムダにCPUを使わずにすみます。

cursor.execute("LISTEN ftp_update_log") # Wait
cursor.execute("SELECT id, message_id FROM fts_update_log")
ids = []
for (id, message_id) in cursor.fetchall():
  cursor.execute("UPDATE zerver_message SET search_tsvector = "
                   "to_tsvector('zulip.english_us_search', "
                               "rendered_content) "
                 "WHERE id = %s", (message_id,))
  ids.append(id)
cursor.execute("DELETE FROM fts_update_log WHERE id = ANY(%s)",
               (ids,))

このような複数プロセスでの待ち合わせを実現するためにRDBMSとは別の仕組みを使うことも多いでしょう。たとえば、RedisのPub/Subを使えるでしょう。別の仕組みを使うと運用が面倒になります。PostgreSQLにはNOTIFY/LISTENがあるので、PostgreSQLを使っていて待ち合わせを実現しなければいけないときはNOTIFY/LISTENを使うことを検討してみてください。

まとめ

ZulipとPGroongaのイベントでZulipとPGroongaの情報を紹介しました。クリアコードはZulipを使っていて、今ではなくてはならないツールになっています。ぜひみなさんもZulipを使ってみてください。

Zulipは基本的に自分たちで運用しますが、運用を任せる選択肢もあります。Zulipの開発チームがクラウドサービスでの提供を進めているのです。オープンソースコミュニティは無料で使えるそうです。興味のある人はzulipchat.comを確認してください。

PGroongaが気になる人は、11月3日開催のPostgreSQL Conference Japan 2017に来てください。日本PostgreSQLユーザ会(JPUG)が主催のPostgreSQLのカンファレンスです。ここでPGroongaの最新情報を紹介する予定です。

タグ: Groonga
2017-09-07

db tech showcase Tokyo 2017 - MySQL・PostgreSQLだけで作る高速でリッチな全文検索システム #dbts2017

この発表のためにmroonga_query_expand()を実装した須藤です。db tech showcase Tokyo 2017で「MySQL・PostgreSQLだけで作る高速でリッチな全文検索システム」という話をしました。一昔前の全文検索システムはそこそこ速く全文検索してキーワードをハイライト表示できれば普通でしたが、最近の全文検索システムはそれだけだと機能不足で、オートコンプリートやクエリー展開や関連エントリー表示機能などがあって普通というくらいにユーザーの要求レベルがあがっています。これは、GoogleやAmazonなど便利な検索サービスに慣れたユーザーが増えたためです。そんな時代の変化に対応できる全文検索エンジンがGroongaです。GroongaはMySQL・MariaDB・PostgreSQLから使えるためSQLを使って簡単にイマドキの全文検索システムを実装できます。しかも、運用も楽です。そんな話です。

関連リンク:

内容

まず、どういうときにMroonga・PGroongaを使うアプローチを選べばよいかという指針を示しました。

  • 全文検索の知識ナシ
    • 全文検索だけできれば十分
      • データが少ない(数十万件とか):RDBMSでLIKE
      • データが多い:Mroonga・PGroonga
    • イマドキの機能が必要
      • Mroonga・PGroonga
  • 全文検索の知識アリ
    • カリカリにチューニングしたい
      • RDBMS + 全文検索サーバー
    • それ以外
      • Mroonga・PGroonga

次に、以下の機能をMroonga・PGroongaで実現するにはどういうSQLを使えばよいか説明しました。

  • 全文検索
  • キーワードハイライト
  • 周辺テキスト表示
  • 入力補完
  • 同義語展開
  • 関連文書の表示

最後に、次のステップとして構造化データ(オフィス文書・HTML・PDFなど)の対応方法について少し言及しました。Groongaプロジェクトは構造化データからテキスト・メタデータ・スクリーンショットを取得するツールとしてChupaTextを開発しています。コマンドラインでもHTTP経由でもライブラリーとしても使えます。HTTP経由で使う場合はDocker・Vagrantを使うのが便利です。依存ライブラリーを揃える手間がないからです。

まとめ

Mroonga・PGroongaを使ってイマドキの全文検索システムを実装する方法を紹介しました。コンサルティングやチューニングや開発支援などを提供するサポートサービスがあります。社外秘のデータでお困りの場合はお問い合わせください。NDAを結んだ上で対応できます。

Mroongaはインサイト・テクノロジーさんが進めているPinkshiftでも活用されています。MySQL・MariaDB・PGroongaで高速全文検索が必要ならMroonga・PGroongaを試してみてください。

タグ: Groonga
2017-09-08

事前情報:RubyKaigi 2017 - Improve extension API: C++ as better language for extension #rubykaigi

結構Rubyの拡張ライブラリーを書いている方だと思っている須藤です。RubyKaigi 2017で拡張ライブラリー関連の話をする予定です。RubyKaigi 2017で私の話をより理解できるようになるために内容を紹介します。

関連リンク:

背景

たくさんRubyの拡張ライブラリーを書いてきた経験を活かして拡張ライブラリーのC APIをもっとよくできないかについて考えています。バインディングについてはRubyKaigi 2016で紹介したGObject Introspectionベースがよいと思っていますが、バインディングではないただの拡張ライブラリーはC++を活用するのがよさそうだと思っています。なぜC++を活用するのがよいと思うかは私が実現したいことに関わっています。

実現したいこと

私が実現したいことはC/C++のライブラリーを使ってRubyスクリプトを高速化することです。具体的には、xtensorというC++で実装された多次元配列ライブラリーを使ってRubyスクリプトを高速化したいです。

1つ1つの機能に対してバインディングを用意してRubyレベルで組み合わせるやり方もあります。ただ、場合によっては機能を実行する毎にRubyレベルに戻ってくるオーバーヘッドを無視できないことがあります。あると思っています。まだ実際に遭遇したわけではありませんが。

あまりよい例ではありませんが。。。たとえば、GPU上で演算をする機能があって、その機能を実行する毎にGPU上にデータを転送して演算をして演算結果をまた転送しなおすとしたら、オーバーヘッドは無視できません。まぁ、この場合は、拡張ライブラリーで一連の演算をまとめるよりも、必要な間はずっとGPU上にデータを置いておく機能をRubyレベルに用意する方が汎用的でよさそうです。最近、Apache ArrowにGPU上のデータを管理する機能が入ったので、この場合はApache Arrowと連携する機能を用意するのがよさそうです。

C++11を活用するやり方

C/C++で書かれたライブラリーを使った拡張ライブラリーを書くにはRubyが提供するC APIを使います。このC APIは悪くないのですが、Cなので書いているときに書きにくいなぁと感じることがあります。

たとえば、メソッドを定義するときに関数定義とメソッドの登録が離れるのが不便だなぁと感じます。次のようにrb_hello()の定義とrb_define_method()の呼び出しが離れています。

#include <ruby.h>

static VALUE
rb_hello(VALUE self)
{
  return rb_str_new_cstr("Hello");
}

void
Init_hello(void)
{
  VALUE rb_cHello = rb_define_class("Hello", rb_cObject);

  rb_define_method(rb_cHello, "hello", rb_hello, 0);
}

あとは、例外が発生したときにキレイにリソースを開放するためにrb_rescue()rb_ensure()を使うときが面倒です。

他には、RubyのオブジェクトをCの値に変換する各種APIに統一感がないのも地味に使い勝手が悪いです。たとえば、Rubyのオブジェクトをboolに変換するにはRTEST()を使いますし、intに変換するにはNUM2INT()を使います。

C++11以降の最近のC++を使うことで今のC APIをもっと便利にできます。

たとえば、C++11にはラムダ式があります。これを活用することで次のようにdefine_method()で直接メソッドを定義できます。これはExt++というライブラリーを使っています。

#include <ruby.hpp>

extern "C" void
Init_hello(void)
{
  rb::Class("Hello").
    define_method("hello",
                  [](VALUE self) { // ←ラムダ式
                    return rb_str_new_cstr("Hello");
                  });
}

Rubyでdefine_methodを使うと次のような書き方になりますが、少し似ていますね。

class Hello
  define_method(:hello) do
    "Hello"
  end
end

C++11を活用するやり方のメリット・デメリット

このようなC++11を活用するやり方のメリットは次の通りです。

  • より完結に書ける
    • ラムダ式:その場で関数を定義できる
    • auto:型推論を使うことで必要な型だけ書けばすむようになる
    • range-based for loop:従来のfor (int i = 0; i < n; ++i)だけでなく、Rubyのeachのように自分でインデックスを回さなくてもforを使える
  • 既存のRubyのC APIも使える
    • 拡張ライブラリーを書いたことがある人なら徐々に便利APIに移行できる
  • C/C++のライブラリーをそのまま使える
    • (Ruby用のじゃなくてC++用の)バインディングを用意する必要がない
    • たとえば、Rustを使うならバインディングを用意する必要がある
  • デバッグしやすい
    • 普通にGDB/LLDBを使える
  • 最適化しやすい
    • Feature #13434 better method definition in C API」関連のAPIの改良にも使えるかも

簡単に言うと、既存の資産を活用しつつ便利になるよ、という感じです。

一方、デメリットは次の通りです。

  • C++には難しい機能がたくさんあるので油断するとメンテナンスしにくくなる
    • たとえばテンプレート
  • ビルドが遅い
  • C++の例外とRubyの例外は相性が悪い
    • Rubyの例外はsetjmp()/longjmp()で実装されているのでRubyの例外が発生すると、スコープを抜けたC++のオブジェクトのデストラクターが呼ばれない
  • 古い環境だとC++11を使うのが大変
    • たとえば、CentOS 6の標準パッケージのg++では使えない

例外に関してはライブラリーでカバーする方法があるので、基本的にはC++に起因するデメリットになります。

このようなデメリットはあるものの、適切に使えば十分メリットの方が大きくなると思っています。Ruby本体にC++のAPIがあってもいいのではないかと考えていた時期もあったのですが、RubyKaigi 2017の資料をまとめていたら少し落ち着いてきて、今は、もう少し検討してよさそうなら提案しよう、くらいに思っています。

C++11を活用する以外のやり方

以前からもっと便利に拡張ライブラリーを書きたいという人たちがいます。私はC++11を活用するアプローチがよいと思っていますが、他のアプローチも紹介します。

大きく分けて3つのアプローチがあります。

  • Rubyを拡張して拡張ライブラリーも書けるようにする
  • C以外の言語で拡張ライブラリーを書けるようにする
  • C APIを使いつつ便利APIで改良する

最後のアプローチがC++11を活用するアプローチです。

最初の「Rubyを拡張する」アプローチはRubexのアプローチです。Rubyに追加の構文を導入して拡張ライブラリーも書けるようにしようというアプローチです。RubyKaigi 2017で発表があります。

Pythonでは同様のアプローチで成功しているプロダクトがあります。それがCythonです。CythonはPythonでデータ分析をする界隈では広く使われています。(使われているように見えます。)

私はこのアプローチはあまりスジがよくないと感じています。理由は次の通りです。

  • 一見使いやすそうだが結局使いにくいAPI
    • Rubyっぽい構文なのでRubyユーザーにも使いやすいような気がするが、実際はところどころに違いがあって、結局Rubyではない言語なので使いにくさにつながる
    • Rubyっぽく書けるのでCの知識は必要なさそうに思えるが、libffiを使うときのように結局Cの知識は必要になる
    • RubyとCだけでなくRubexの知識も必要になり、結局覚えることは結構多い
  • メンテナンスが大変
    • Rubyが新しい構文を導入したら追従する必要がある
    • Rubyの構文と衝突しないようにRubexを拡張していく必要がある
  • デバッグが大変
    • Rubexが生成したCのコードをベースにデバッグする必要がある

ただ、Cythonが成功している事実と、ちょっとした拡張機能を書く分にはRubyの知識と少しのRubexの知識だけでよい(Cのことはあまり知らなくてよい)という事実があるので、もしかしたらそんなにスジは悪くないのかもしれません。数年後も開発が継続していたら再度検討してみたいです。

2番目の「C以外の言語を使う」アプローチはHelixのアプローチです。Rustで拡張ライブラリーを書けるようにしようというアプローチです。RubyKaigi 2017で発表があります。

私はC/C++のライブラリーを使いたいのでこのアプローチは私の要件にはマッチしないのですが、高速化のために処理を全部で自分で実装する(あるいはRustのライブラリーを活用して実装する)場合はマッチしそうな気がします。

このアプローチのメリットは、Rustを知っているならCで書くよりもちゃんとしたプログラムをすばやく書けることです。デメリットはRubyのC APIのフル機能を使えない(使うためにはメンテナンスを頑張る必要がある)ことです。たとえば、Ruby 2.4からrb_gc_adjust_memory_usage()というAPIが導入されましたが、Rustからこの機能を使うためにはバインディングを用意する必要があります。つまり、RubyのC APIの進化にあわせてメンテナンスしていく必要があります。

C++を活用する方法

最後に現時点でC++を活用する方法を紹介します。

1つがRiceを使う方法です。RiceはC++で拡張ライブラリーを書けるようにするライブラリーです。10年以上前から開発されています。C++でPythonの拡張ライブラリーを書けるようにするBoost.Pythonに似ています。

例外の対応やメソッドのメタデータとして引数のデフォルト値を指定できるなど便利な機能が揃っています。ただし、昔から開発されているライブラリーで現在はメンテナンスモードなため、C++11への対応はそれほど活発ではありません。メンテナーは反応してくれるので自分がコードを書いて開発に参加するのはよいアプローチだと思います。

もう1つがExt++を使う方法です。Ext++もC++で拡張ライブラリーを書けるようにするライブラリーです。私が作り始めました。RiceはRubyのCのオブジェクトをすべてラップしてC++で自然に扱えるようにするようなAPIです。つまり、できるだけRubyのC APIを使わずにすむようにしたいようなAPIです。私は、もっとC APIが透けて見えるような薄いAPIの方が使いやすいのではないかという気がしているので、その実験のためにExt++を作り始めました。薄いAPIの方が使いやすいのか、結局Riceくらいやらないと使いやすくないのかはまだわかっていません。Red Data Toolsのプロダクトで使って試し続けるつもりです。

まとめ

RubyKaigi 2017で拡張ライブラリーを書きやすくするためにC++がいいんじゃない?という話をします。

おしらせ

去年もスポンサーとしてRubyKaigiを応援しましたが、今年もスポンサーとしてRubyKaigiを応援します。去年と違って今年はブースはありません。懇親会などで見かけたら声をかけてください。拡張ライブラリーに興味のある人と使いやすいAPIについて話をしたいです!

あと、RubyKaigi 2017の2日目の午後に通常のセッションと並行して「RubyData Workshop」というワークショップが開かれる予定です。まだRubyKaigi 2017のサイトには情報はありませんが、時期に情報が載るはずです。このワークショップではPyCallRed Data Toolsの最新情報を手を動かして体験することができます。Rubyでデータ処理したい人はぜひお越しください!

つづき: 2017-09-22
タグ: Ruby
2017-09-11

RubyKaigi 2017 - Improve extension API: C++ as better language for extension #rubykaigi

RubyKaigi 2017で拡張ライブラリー関連の話をしてきた須藤です。クリアコードはシルバースポンサーとしてRubyKaigi 2017を応援しました。

関連リンク:

内容

C++11を活用するともっと拡張ライブラリーを書きやすくなるよ、という内容でした。詳細は事前情報を読んでください。

個人的には今後の拡張ライブラリー開発にプラスになるとても実用的な話をしたつもりだったのですが、あまり反響がなかったので、よさを伝えきれなかったのだと思います。残念。

誰も質問してくれなかったので付録の生のC API以外で拡張ライブラリーを書く方法の比較はお蔵入りになりました。聞きたい人はなにかのイベントに呼んでください。

Red Data Tools

発表の反響はあまりなかったですが、Red Data Toolsの反響はありました。

RubyData Workshop in RubyKaigi 2017の1つとしてSpeee@hatappiさんとRed Data Toolsの紹介をしました。(@hatappiさんがメインで説明・進行をして、私はたまに補足するスタイル。)

来週の火曜日(9月26日)の夜にSpeeeさんで開催するRed Data Toolsの開発イベントOSS Gate東京ミートアップ for Red Data Tools in Speeeの参加者が増えました。オンラインで相談する場所はGitterのred-data-tools/jaにあるので、開発イベントに参加できない人も一緒に開発しましょう!

Rubyでデータ処理できるようにしたいみなさん、一緒に開発していきましょう!

自分達は開発できない・開発する時間がないけどお金は出せるという場合は、クリアコードに開発の仕事を依頼するというやり方があるのでお問い合わせください。

OSS Gate

Red Data Toolsと同じようにOSS Gateも反響がありました。RubyKaigi 2017 前夜祭安川さんが紹介してくれたのと、Speeeさん・永和システムマネジメントさん・ドリコムさん・ピクシブさんのブースにチラシを置いてもらったのが大きいです。ありがとうございました!

おかげで広島でもOSS Gateの活動を始められそうです。Gitterのoss-gate/hiroshimaで相談しているので、広島でもOSSの開発に参加する人が増えるとうれしい人は参加してください。

全国のOSS Gateワークショップ開催情報は次の通りです。近隣で開催している場合はぜひビギナー・サポーターとして参加してください。

まとめ

RubyKaigi 2017の発表内容と成果を紹介しました。

タグ: Ruby
2017-09-22

Redmineでもっと高速に全文検索する方法

Redmineで高速に全文検索する方法で紹介したプラグインの新しいバージョンをリリースしてさらに高速化しました。

v0.6.0での変更点

  • 検索結果のハイライトにPGroonga/Mroongaの機能を使用するようにしました
    • 複数キーワードごとに色分けしないようになりました
  • クエリー構文が使えるようになりました
  • 類似チケットの表示をするようにしました

類似チケット

Groongaの類似文書検索の機能を使って類似チケットを表示するようになりました。

例えば、あるソフトウェアのサポートをしているときに似た問い合わせが過去にあれば、その似た問い合わせが類似チケットとして表示されることを期待しています。 現在の実装では、チケットのトラッカー、起票者、担当者、カテゴリなどのメタデータを一切考慮していないので精度はそこそこです。 クリアコード社内で運用しているRedmine*1に入れてみたところ類似チケットの検索には15msくらいしかかかっていないのでRedmineの性能に影響はないと考えてデフォルトでONにしてあります。

なぜ高速化したか

元のRedmineの全文検索では、最大で以下の9つのテーブルを検索し、検索時に全件取得してキャッシュしていました。

  • チケット
  • ニュース
  • 文書
  • 更新履歴
  • Wikiページ
  • メッセージ
  • プロジェクト
  • 添付ファイル
  • チケットのコメント

redmine_full_text_search v0.4.0 までは既存のコードをなるべく活かしていたので、クエリの実行数は同じで全件取得していたのも同じでした。 つまり、上記全てのテーブルから検索すると1回のクエリで100msだとしても 9 * 100ms = 900ms と約1秒かかってしまうことになります。 v0.5.0 では、検索対象のレコードを1つのテーブルにまとめてGroongaの機能を直接使用して全文検索のために実行するクエリを1つにしました。 また、limit と offset を使用して一度に取得するレコード数を減らし、Redmineのキャッシュを使用するのをやめました。

ベンチマーク

  • 環境
    • Google Compute Engine
    • n1-standard-2 (vCPUx2, メモリー7.5GB)
    • OS Debian GNU/Linux stretch
    • Ruby 2.3.3p222
    • Redmine 3.4.2
    • Passenger 5.0.30-1+b1
    • MariaDB 10.1.26-0+deb9u1
    • Mroonga 7.06-1
    • PostgreSQL 9.6.4-0+deb9u1
    • PGroonga 2.0.1-1

redmine_full_text_searchのバージョンはv0.4.0とv0.6.2を使用しました。 内部ネットワークからMechanizeで特定のユーザーでログインして表にあるクエリーで検索しました。 以下にMariaDB(Mroonga)の場合とPostgreSQL(PGroonga)の場合についてそれぞれの測定結果を示します。

データは、以下のメーリングリストのアーカイブを使用しました。 メーリングリストごとにプロジェクトを作成しました。 メールからチケットを作成し、In-Reply-Toで返信だと判断できる場合は、見つかったチケットへのコメントとして登録するようにしました。

これで31142チケットと72392コメントのデータベースを作成しました。redmine_full_text_search v0.6.2向けのテーブルには103537件レコードが存在します。 Wikiやドキュメント等チケット以外のデータはありません。

測定結果の単位は全てミリ秒です。

MariaDB
Redmine v0.4.0 v0.6.2
query 1st 2nd 1st 2nd 1st 2nd
cgi リーク duration 1804.86 56.0048 1028.55 62.8551 140.443 138.351
view_runtime 27.8059 29.7982 30.5287 26.2161 61.5869 55.7791
db_runtime 1758.66 5.93903 969.221 7.09439 64.5651 63.6323
groonga duration 1687.73 82.2862 1053.66 124.609 119.136 115.352
view_runtime 18.7162 19.5571 25.1116 21.4028 42.1369 39.2488
db_runtime 1611.95 5.80468 923.49 12.0304 63.7171 62.6385
mroonga score duration 1712.8 38.6372 1043.22 50.2505 134.332 115.884
view_runtime 19.4748 18.8583 20.4314 21.4807 42.9837 41.9256
db_runtime 1678.16 5.84049 998.232 5.45167 64.2949 61.54
pgrooga score duration 1675.0 25.8263 907.864 38.1889 72.0365 72.458
view_runtime 10.8129 10.5722 12.1855 13.2947 12.3002 12.2505
db_runtime 1653.34 5.25172 877.303 5.14269 52.3137 52.2138
ruby duration 1876.77 1240.81 2858.95 1576.22 182.263 182.67
view_runtime 17.2178 17.4677 20.9058 21.6165 44.5798 46.555
db_runtime 683.701 9.14142 1324.75 19.6118 108.922 106.341
segv duration 1734.57 97.6753 1221.78 125.179 207.27 128.385
view_runtime 51.7349 22.1543 33.8267 31.1135 104.215 49.5876
db_runtime 1610.52 6.07189 1056.77 6.53569 87.9873 62.8314
segv make duration 1815.31 68.4352 958.573 72.8359 119.899 148.094
view_runtime 22.0608 32.7035 35.3729 27.96 42.5002 67.0567
db_runtime 1769.95 5.81216 880.271 6.27881 64.3565 62.977
メモリーリーク duration 1665.0 49.0786 962.625 54.4098 151.751 119.179
view_runtime 21.1638 25.3095 25.1169 23.1611 73.9769 47.4756
db_runtime 1626.61 5.58291 909.367 5.83328 65.4596 60.8111
メモリリーク duration 1668.5 49.7472 1005.86 56.3724 111.954 111.491
view_runtime 22.01 22.3757 18.6613 20.756 41.0274 40.3688
db_runtime 1620.18 5.67121 947.36 5.73328 60.8254 59.7722
ライトニングトーク カンファレンス 開催 duration 1730.69 39.2599 950.232 48.4056 122.699 117.899
view_runtime 18.879 20.1971 24.7018 21.0985 43.9869 42.6021
db_runtime 1697.25 5.37024 901.403 5.60327 65.7128 63.2021
発表者 募集 duration 1540.63 41.1723 1026.68 46.5856 116.767 114.665
view_runtime 18.8667 18.5547 20.2438 19.4315 42.4205 42.7707
db_runtime 1505.5 5.52283 982.723 5.2658 62.3322 60.5112
勉強会 会議 duration 1535.28 39.5411 948.463 47.6093 114.435 137.902
view_runtime 17.7493 19.1658 19.8384 19.5605 41.9521 40.7409
db_runtime 1501.66 5.67893 904.492 5.73054 61.676 60.6336

平均と標準偏差は以下の通りです。

Redmine v0.4.0 v0.6.2
1st 2nd 1st 2nd 1st 2nd
平均 duration 1703.93 152.37 1163.87 191.96 132.75 125.19
view_runtime 22.21 21.39 23.91 22.26 49.47 43.86
db_runtime 1559.79 5.97 972.95 7.53 68.51 64.76
標準偏差 duration 97.12 328.76 516.86 418.29 33.65 25.04
view_runtime 9.66 5.57 6.41 4.36 21.41 12.19
db_runtime 275.78 0.98 117.69 4.05 14.46 12.87

MariaDBの場合はほぼ想定通りの測定結果でした。 プラグインなしの場合は、DBアクセスに初回1500ms以上かかっていたのが2回目は5ms前後になっていてキャッシュが効いています。 プラグインv0.4.0の場合は、DBアクセスに初回1000ms前後にかかってており、2回目は5ms前後になっていました。 プラグインv0.6.2の場合は、DBアクセスに初回、2回目ともに50-100ms程度かかっており、初回の検索から速いのでキャッシュしなくても十分な速度が出ています。

プラグインなしの場合とv0.6.2の場合を比較すると、初回の検索で約24倍高速になっています。

db_runtimeの標準偏差を見ると、v0.6.2のとき最も値が小さくなっており、安定して高速に動作することがわかります。

PostgreSQL
Redmine v0.4.0 v0.6.2
query 1st 2nd 1st 2nd 1st 2nd
cgi リーク duration 5432.23 5708.34 91.9298 91.6952 205.405 207.645
view_runtime 24.3255 26.9705 31.3033 37.1955 39.1355 50.9562
db_runtime 5385.85 5660.76 29.0279 29.6823 145.829 144.418
groonga duration 5060.77 5071.71 669.003 647.418 185.603 182.977
view_runtime 24.3327 20.2376 26.1071 40.4994 30.0942 30.011
db_runtime 4933.86 4929.92 560.77 522.823 146.799 144.304
mroonga score duration 5177.38 5167.46 69.7063 64.5032 181.835 181.996
view_runtime 20.2529 20.5412 26.1367 23.6614 29.0306 28.7275
db_runtime 5139.11 5127.81 22.2003 21.8169 144.434 143.932
pgrooga score duration 5037.87 5056.32 46.4337 43.408 153.975 159.449
view_runtime 11.5761 11.7345 15.6785 14.6403 12.8356 12.9991
db_runtime 5013.34 5031.37 14.6134 14.7022 134.023 138.259
ruby duration 3542.06 3402.16 19749.8 19558.4 238.018 222.578
view_runtime 18.2419 18.4601 18.6485 26.2439 43.0062 29.8173
db_runtime 1511.17 1508.25 18214.4 17921.3 184.03 182.523
segv duration 5270.42 5333.98 522.433 443.14 384.031 190.565
view_runtime 28.5796 26.4264 43.9667 33.4644 90.3281 35.4176
db_runtime 5104.6 5174.81 351.514 309.031 283.627 144.746
segv make duration 5691.51 5691.54 153.903 145.227 190.858 201.922
view_runtime 27.0135 27.8609 44.5491 40.7997 32.3304 43.489
db_runtime 5613.84 5617.51 66.682 64.3612 148.758 147.865
メモリーリーク duration 5789.28 5752.14 75.0013 72.5004 195.717 200.674
view_runtime 23.1544 21.7764 20.2103 21.5645 41.4241 45.2702
db_runtime 5740.95 5709.43 33.8974 31.4955 141.669 143.453
メモリリーク duration 5749.46 5792.81 105.487 102.567 196.678 187.858
view_runtime 23.1136 22.6125 21.9238 23.339 37.9664 35.4135
db_runtime 5696.29 5738.85 57.3894 54.1745 143.913 142.159
ライトニングトーク カンファレンス 開催 duration 5842.91 5811.98 63.857 66.4787 187.346 185.818
view_runtime 20.0885 22.1672 22.3308 23.4369 30.5955 29.236
db_runtime 5804.88 5770.79 22.9653 23.6612 146.704 146.915
発表者 募集 duration 5154.93 5152.25 74.2416 73.2 183.645 181.342
view_runtime 20.5156 19.2945 27.7632 29.5588 31.441 30.5509
db_runtime 5114.81 5112.4 24.3069 23.246 143.74 141.939
勉強会 会議 duration 5028.9 5064.46 65.7615 78.8453 180.065 182.6
view_runtime 19.6628 18.504 21.4198 33.3649 29.5505 30.3836
db_runtime 4989.92 5025.62 24.977 24.7126 142.494 143.389

平均と標準偏差は以下の通りです。

Redmine v0.4.0 v0.6.2
1st 2nd 1st 2nd 1st 2nd
平均 duration 5231.48 5250.43 1807.30 1782.28 206.93 190.45
view_runtime 21.74 21.38 26.67 28.98 37.31 33.52
db_runtime 5004.05 5033.96 1618.56 1586.75 158.84 146.99
標準偏差 duration 590.01 633.07 5413.33 5362.64 56.54 15.34
view_runtime 4.26 4.25 8.84 7.84 17.67 9.38
db_runtime 1096.48 1107.02 5006.48 4927.30 39.38 10.96

PostgreSQLの場合は、プラグインなしのときは初回、2回目ともにDBアクセスに約5秒かかっているのでキャッシュが効いていないことがわかります。 v0.4.0の場合もキャッシュが効いておらず、初回、2回目ともにDBアクセスに約1.5秒かかっています。プラグインなしと比較して、約3倍高速になりました。 v0.6.2ではRedmineのキャッシュを使用しないようにしたので、キャッシュの影響はありません。初回、2回目ともにDBアクセスに約0.15秒かかっています。 プラグインなしと比較すると、約33倍高速になりました。v0.4.0と比較すると約10倍高速になっています。

db_runtimeの標準偏差を見ると、v0.6.2のとき最も値が小さくなっており、安定して高速に動作することがわかります。

MariaDBとPostgreSQLの比較

redmine_full_text_search v0.6.2の場合、MariaDBとPostgreSQLのdb_runtimeの平均を比較するとMariaDBの方が約2.3倍高速という結果でした。 これは、MroongaとPGroongaでGroonga上のテーブル定義やインデックス定義に違いがあるためではないかと考えています。

まとめ

今後は、機能を充実させつつMariaDBとPostgreSQLのどちらを使っても快適に検索できるようにしていきたいです。 やりたいことについてはプロジェクトのissuesも見てください。

*1 チケット数は約4000件

つづき: 2017-09-26
2017-09-25

Redmineのベンチマーク環境構築を自動化する方法

GCP上にインスタンスを立ち上げて、簡単にredmine_full_text_searchを試すことができる環境を構築できるようにしました。

成果物はリポジトリにまとまっています*1

Redmineでもっと高速に全文検索する方法で使用したベンチマーク環境を構築するためのスクリプトです。 今後もredmine_full_text_searchをバージョンアップしたとき、性能の変化を簡単に調べれられるように作りました。

使い方

TerraformAnsibleを入れてコマンドを叩くだけです。

コマンドを実行する前に、APIキーを作成しておく必要があります。

$ git clone https://github.com/okkez/redmine_full_text_search-benchmark.git
$ cd redmine_full_text_search-benchmark
$ terraform init Terraform/
$ terraform apply Terraform/
$ ./generate-hosts.rb

このまま ansible を実行すると、SSHのホスト鍵のチェックが実行されて、対話的な操作が必要になるので対話的な操作が不要になるように準備します。

$ for h in fluentd redmine-mariadb redmine-mroonga redmine-postgresql redmine-pgroonga; do \
    gcloud compute --project "YOUR PROJECT" ssh --zone "YOUR ZONE" "fluentd" --command "echo"; done

また、ansible が使うUserKnownHostsFileにgcloudコマンドが生成するファイルを指定します。 ansible/ansible.cfg に以下の内容でファイルを作成しておきます。

[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o -o UserKnownHostsFile=~/.ssh/google_compute_known_hosts

注意 DBのダンプファイルはリポジトリに含めていないので、各自DBのダンプファイルを用意してください。

  • ansible/roles/mariadb/files/benchmark-mariadb.dump.sql.xz
  • ansible/roles/postgresql/files/benchmark-postgresql.dump.sql.xz

最後に ansible-playbook コマンドを実行します。

$ cd ansible
$ ansible-playbook -i hosts playbook.yml

全部で20分もあれば、環境構築が終わります。

今後やりたいこと

今はベンチマーク用なので内部ネットワークからしかアクセスできないようにしてありますが、httpとhttpsは外部からアクセスできるようにして手元のブラウザからでも簡単に動作を確認できるようにしたいです。 また、ベンチマーク用のデータもどこかにアップロードしたものを簡単に使えるようにしたいです。

測定結果をFluentd経由でPostgreSQLに溜めてあるのですが、これをいい感じに可視化したいです。

*1 DBのダンプファイルはxzで圧縮してもサイズが大きいのでリポジトリに含めていません

2017-09-26

データ分析基盤構築入門

データ分析基盤構築入門という書籍を著者の一人@yoshi_kenさんから「Fluentdのプラグインの件でお世話になっているので〜」ということでいだたきました。ありがとうございます!

この書籍を読むとFluentd,Elasticsearch,Kibanaの体系化された知識を得ることができます。 特にこれからデータ分析基盤を作ろうと考えている人や、データ分析基盤を構築しているけど、自己流なので自信がないなぁという人におすすめの書籍です。

400ページくらいあり分厚いのですが、サンプルコード・実行例・設定例がたくさんあり、まずは真似して始めてみる、ということが大変やりやすくなっています。

第1部 データ分析基盤入門

データ分析基盤を構築する目的はなんなのか、データ分析基盤を構築し、提供する立場ではどういう考え方で行動するべきなのかという心構えから、ビジネスではデータ分析基盤をどのように活用される例があるのかも説明されているので、これから始める人にとってちょうど良い内容になっています。

第2部 Fluentd入門

現在存在する日本語の情報でFluentdについて最もきちんとまとまっている情報です。ドキュメント化されていない情報や見つけにくい情報もまとまっているため、リファレンスとして一冊手元にあるととても便利だと思いました。 またFluentd v0.12とFluentd v0.14の違いについても書かれているため、これから新しくFluentdを使い始める人にとっても役に立つでしょう。

多くの人が最初に使うであろうtailプラグインについては徹底攻略として設定例を含めて約20ページの解説が書かれています。 また、Fluentdノードのデザインパターンとしてよく使用されるであろうノード構成について詳しく解説されています。

第2部の最後に運用Tipsとして、様々な知見が書かれています。これらは実際にFluentdを運用しようとしたときに気になる項目ばかりでした。

第3部 Elasticsearch入門

Elastic社の中の人が書いているので、とても詳しく書いてあります。 Elasticsearchを使ったことがないので、内容の評価はできませんが始めて使う人から、大規模で運用したいと考えている人まで幅広く対応した内容だと思いました。

第4部 Kibana入門

Kibana入門のタイトル通りの内容でした。Kibanaも使ったことがなかったのですが、この書籍を読んで使い始めることができそうという気持ちになりました。

付録

付録というよりも第5部と言った方が適切なくらいの分量がありました。 Fluentd/Embulkのプラグインリストは、日本語でまとめられている情報では質と量で一番です。

まとめ

第1部から第4部までと付録はそれぞれ独立しているので、どこからでも読み始めることができます。 しかし、それぞれのソフトウェアについて独立して書かれているため、FluentdとElasticsearchの連携をするための方法については、あまり詳しく書かれていませんでした。 この書籍が書かれた時期は2017年4月より前だと思うのですが、その時期はfluent-plugin-elasticsearchのメンテンスが滞っていたので詳しく書けなかったのだと思われます。 2017年9月から、クリアコードメンバーがCollaboratorとして開発に参加しているので、FluentdからElasticsearchにデータを送るのにfluent-plugin-elasticsearchを使い続けても安心です。

データ分析基盤構築入門[Fluentd,Elasticsearch,Kibanaによるログ収集と可視化]
鈴木 健太/吉田 健太郎/大谷 純/道井 俊介
技術評論社
(no price)

タグ: Fluentd
2017-09-27

«前月 最新 翌月»
2008|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|
タグ: