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

ククログ

タグ:

Firefox ESRの独自ビルドの作成方法(2017年版)

2015年にWindowsでのFirefoxの独自ビルドの作成方法をご紹介しましたが、2017年現在では状況が若干変わっています。この記事では、2017年10月現在においてWindows用にFirefox ESRの独自ビルドを作成する手順をご紹介します。

なお、この記事ではFirefoxの改造の方法は扱っていません。「Firefox」というブランド名を除去した改造版を作成する方法については、過去の記事をご参照ください。

情報のありか

Firefoxのビルドに関する情報は、Build Instructionsから辿ることができます。 Windowsでのビルドなら、Building Firefox for Windowsで必要な情報が手に入ります。

ただ、MDNの情報は様々な場合を考慮して網羅的に書かれているため、各項目に複数の選択肢が示されている場合があり、「とりあえずどこから始めればいいのか?」が若干分かりにくい構成となっています。 そこで、この記事では「Firefox ESRをビルドする」という場面に限定して一通りの流れをご紹介してみます。

ビルド環境の構築

現在新規に導入可能なWindows環境はWindows 10である場合がほとんどです。この記事では、Windows 10 Creators Updateまたはそれ以降のバージョンをビルド環境として想定します。 (検証はWindows 10 Pro 1703 (Creators Update) 15063.632で行っています。)

Firefoxのビルドにあたっては、HDDとメモリに十分な余裕があることが望ましいです。ビルドツール、ライブラリ等のインストール領域用と、リポジトリ自体やビルド中に生成される一時ファイルの分、および仮想メモリのスワップ領域用として、HDDに最低でも15GB程度の空き容量を確保しておくとよいでしょう。また、メインメモリが逼迫しているとビルドに余計に時間がかかります。最低でも4GB程度のメモリがあるとよいでしょう。

Windows上でFirefoxをビルドするために必要なソフトウェアは、すべて無料で入手できます。

  • MozillaBuild
    • 2017年10月現在の最新版は「MozillaBuild 3.0」で、以下の説明はすべてこのバージョンを前提とします。
  • DirectX SDK
    • インストール作業の順番次第では「S1023」という番号を伴ってインストールエラーが表示されることがあります。これは、システムに「Visual C++ 2010 再頒布可能パッケージ」の新しいバージョンが存在する場合に起こることが多いです。一旦「Visual C++ 2010 再頒布可能パッケージ」をアンインストールしてからDirectX SDKをインストールし、完了の後改めて最新の「Visual C++ 2010 再頒布可能パッケージ」をインストールし直して下さい。
    • 古いサポート切れのバージョンのWindows 10においては、「Visual C++ 2010 再配布可能パッケージ」が存在しなくてもエラーコード「S1023」を伴ってインストールに失敗する場合があり、Creators Updateへ更新後は発生しなくなるという結果を得られました。問題との関連性は不明ですが、脆弱性への対応などの観点からも、Windows自体を最新版に更新してから臨むことを強くお勧めします。
  • Windows 10 SDK
  • Visual Studio Community 2015 with Update 3
    • 2017年10月現在のVisual Studioの最新版は「Visual Studio 2017」ですが、公式のビルドはVisual Studio 2015で行われているとのことなので、ここでもVS2015を使うことにします。古いバージョンのダウンロード用ページから、日本語版のインストーラを入手して下さい。(Microsoftアカウントが必要)
    • インストール時の機能の選択で「カスタム」を選択し、「プログラミング言語」→「Visual C++」→「Visual C++ 2015用の共通ツール」にチェックを入れる必要があります。
    • インストールが完了したら、Visual Studioを起動して初期設定を完了させる必要があります。
    • インストールと初期設定を終えたら、累積的なアップデートを適用して更新します。

ソースの入手

Firefoxのソースコードはスナップショットのtarballとしても入手できますが、ここではMercurialのリポジトリをcloneする方法で手順を解説します。

環境構築の際に導入したMozillaBuildはMinGWのコマンドラインコンソールを含んでおり、ビルドの作業はこのコンソールから行います。 C:\mozilla-build\start-shell.bat をダブルクリックしてコンソールを開きましょう。

コンソールを開いたら、リポジトリをcloneするためのディレクトリを用意します。

$ mkdir /c/mozilla-source
$ cd /c/mozilla-source

以下でcloneするリポジトリの中に含まれるファイルは開発用の物のため、Norton Securityなどのウィルス対策ソフトウェアが動作していると、Nortonの誤判定でリポジトリの中のファイルが意図せず削除されてしまうことがあります。ここで作成したディレクトリ(C:\mozilla-source)をウィルス対策ソフトウェアの監視対象にしないように設定しておきましょう。例えばNorton Securityであれば、「設定」→「ウィルス対策」→「スキャンとリスク」→「除外/低危険度」→「スキャンから除外する項目」および「自動保護、SONAR、ダウンロードインテリジェンスの検出から除外する項目」で任意のフォルダをスキャン対象外にすることができます。

次に、Firefoxのリポジトリをcloneします。

Firefoxやその他のMozilla製品のリポジトリはhttps://hg.mozilla.org/で公開されています。 Nightlyの最新版やESR版など、どのバージョンをビルドしたいかによってどのリポジトリをcloneするかが変わります。 ESRを含むリリース版のFirefoxのソースはhttps://hg.mozilla.org/releases/以下にあり、ESRの場合はhttps://hg.mozilla.org/releases/mozilla-esr52のようにバージョン番号を含むパスのリポジトリになっています。

今回はFirefox ESR52.4.1をビルドすることにします。まず https://hg.mozilla.org/releases/mozilla-esr52をcloneします。

$ hg clone https://hg.mozilla.org/releases/mozilla-esr52

リポジトリの規模が数GBと大きいので、cloneにはそれなりの時間がかかります。

Firefox本体のリポジトリをcloneできたら、次は言語リソースのリポジトリをcloneします。 言語リソースのリポジトリは言語ごとに分かれており、ESRを含むリリース版のFirefoxの日本語用言語リソースはhttps://hg.mozilla.org/releases/l10n/mozilla-release/jaです。

$ hg clone https://hg.mozilla.org/releases/l10n/mozilla-release/ja ja

cloneする際に、hgコマンドの3番目の引数としてディレクトリ名を、明示的に言語コード名のjaと指定します。 これは、MozillaBuildでのビルド時には言語リソースが言語コード名に基づいて検索されるためです。

ビルドの準備

ビルドするリビジョンへの切り替え

cloneしたリポジトリは、次のリリースに向けての作業が進行している状態になっています。 Firefox ESR52.4.1のように特定のバージョンをビルドするには、タグに基づいてそのリビジョンに切り替える必要があります。

$ cd /c/mozilla-source/mozilla-esr52
$ hg tags | grep -E -e "FIREFOX_.+_RELEASE" | less

Firefox ESR52.4.1のタグはFIREFOX_52_4_1esr_RELEASEですので、ここにリビジョンを切り替えます。

$ cd /c/mozilla-source/mozilla-esr52
$ hg update FIREFOX_52_4_1esr_RELEASE

言語リソースのリポジトリも対応するリビジョンに切り替える必要がありますが、Firefox 45よりも後のバージョンについては何故か、言語リソースのリポジトリには本体と共通のタグが付けられていません。そこで、Android版FirefoxやThundebrirdのタグ情報を参考にしつつ適切なリビジョンを探すことにします。まず、hg log --graphでコミットグラフを表示します(Webでも同様のコミットグラフを見られます)。

$ cd /c/mozilla-source/ja
$ hg log --graph

Firefox ESRの場合は、ESR版の元になったリリースのタグが属しているコミットグラフの縦線を辿っていき、近いバージョン番号のThunderbirdのタグを探します。すると、THUNDERBIRD_52_4_0_RELEASEというタグの付けられたコミットが見つかります。 これより新しいリビジョンはこの縦線の上には存在しませんので、Firefox ESR52.4.1の日本語リソースはこのリビジョンを使ってビルドしてよいと考えられます。

言語リソースの使用リビジョンを特定できたら、そのリビジョンに切り替えて次の行程に進みましょう。

$ cd /c/mozilla-source/ja
$ hg update THUNDERBIRD_52_4_0_RELEASE
ビルドオプションの指定

ビルド対象のリビジョンをチェックアウトしたら、次は、ビルドオプションを指定します。

ビルドオプションの指定はFirefox本体のリポジトリのトップレベルのディレクトリに.mozconfigという名前のテキストファイルとして保存します。 今回の例ではc/mozilla-source/mozilla-esr52/.mozconfigの位置です。

ビルドオプションは様々な物がありますが、ここでは話を単純化するために、公式のFirefox ESR52.4.1のうちブランディングに関わる部分以外は同一の指定とします。

Firefoxではabout:buildconfigを開くとそのバイナリの元になったビルドオプションの一覧を見ることができます。ただ、実際のmozconfigには、それらに加えて環境変数の指定なども必要です。単にビルドオプションだけを指定した状態だと、Visual Studioのランタイムライブラリがインストーラに含まれないなど、一般ユーザの環境で使用するには不都合があるビルド結果となってしまいます。

ビルド環境が64bit版のWindowsで、Visual Studio Community 2015を使う場合の基本的なビルド設定は、Firefox自体のリポジトリのbuild/win32/mozconfig.vs2015-win64の位置(※今回ビルドしたいのはFirefox ESR52.4.1なので、オンラインで例を見る場合はmozilla-esr52リポジトリの物を参照して下さい)にファイルがあります。

このファイルに書かれている設定内容はMozillaで使用しているビルド環境向けの物なのですが、ここまでの手順通りに必要なソフトウェアを導入した場合、Visual Studioのインストール先パスなどが実際の物と異なっています。 ここまでの手順通りに環境を整えた場合のパスを指定するように改めた上で、Firefox ESR52.4.1のabout:buildconfigに列挙されているオプション群から必要でない物を除外し、ローカライズに必要なオプションを足した物が、以下の例です(行頭の#はコメントアウトです)。

export VSPATH='/C/Program Files (x86)/Microsoft Visual Studio 14.0'

#---------- based on build/win32/mozconfig.vs2015-win64 -------------

if [ -z "${VSPATH}" ]; then
    TOOLTOOL_DIR=${TOOLTOOL_DIR:-$topsrcdir}
    VSPATH="$(cd ${TOOLTOOL_DIR} && pwd)/vs2015u3"
fi

VSWINPATH="$(cd "${VSPATH}" && pwd -W)"

# Windows 10 SDKのインストール先はVisual Studioの配下ではないため、適切なパスを明示的に指定する。
#export WINDOWSSDKDIR="${VSWINPATH}/SDK"
export WINDOWSSDKDIR="/C/Program Files (x86)/Windows Kits/10"
export WIN32_REDIST_DIR="${VSPATH}/VC/redist/x86/Microsoft.VC140.CRT"
# 再配布可能なランタイムライブラリはWindwos 10 SDKに含まれるため、こちらも適切なパスを指定する。
#export WIN_UCRT_REDIST_DIR="${VSPATH}/SDK/Redist/ucrt/DLLs/x86"
export WIN_UCRT_REDIST_DIR="${WINDOWSSDKDIR}/Redist/ucrt/DLLs/x86"

# ビルド過程で使われるツール類の一部はVisual Studio配下ではなくWindows 10 SDKに含まれる。
# また、ランタイムライブラリも一部はWindows 10 SDKに含まれている。
# 前述の通り、Windows 10 SDKの正しいインストール先を参照するように改める必要がある。

# 修正前
#export PATH="${VSPATH}/VC/bin/amd64_x86:${VSPATH}/VC/bin/amd64:${VSPATH}/VC/bin:${VSPATH}/SDK/bin/x86:${VSPATH}/SDK/bin/x64:${VSPATH}/DIA SDK/bin:${PATH}"
#export PATH="${VSPATH}/VC/redist/x86/Microsoft.VC140.CRT:${VSPATH}/VC/redist/x64/Microsoft.VC140.CRT:${VSPATH}/SDK/Redist/ucrt/DLLs/x86:${VSPATH}/SDK/Redist/ucrt/DLLs/x64:${PATH}"

#export INCLUDE="${VSPATH}/VC/include:${VSPATH}/VC/atlmfc/include:${VSPATH}/SDK/Include/10.0.14393.0/ucrt:${VSPATH}/SDK/Include/10.0.14393.0/shared:${VSPATH}/SDK/Include/10.0.14393.0/um:${VSPATH}/SDK/Include/10.0.14393.0/winrt:${VSPATH}/DIA SDK/include"
#export LIB="${VSPATH}/VC/lib:${VSPATH}/VC/atlmfc/lib:${VSPATH}/SDK/lib/10.0.14393.0/ucrt/x86:${VSPATH}/SDK/lib/10.0.14393.0/um/x86:${VSPATH}/DIA SDK/lib"

# 修正後
export PATH="${VSPATH}/VC/bin/amd64_x86:${VSPATH}/VC/bin/amd64:${VSPATH}/VC/bin:${WINDOWSSDKDIR}/bin/x86:${WINDOWSSDKDIR}/bin/x64:${VSPATH}/DIA SDK/bin:${PATH}"
export PATH="${VSPATH}/VC/redist/x86/Microsoft.VC140.CRT:${VSPATH}/VC/redist/x64/Microsoft.VC140.CRT:${WINDOWSSDKDIR}/Redist/ucrt/DLLs/x86:${WINDOWSSDKDIR}/Redist/ucrt/DLLs/x64:${PATH}"

export INCLUDE="${VSPATH}/VC/include:${VSPATH}/VC/atlmfc/include:${WINDOWSSDKDIR}/Include/10.0.15063.0/ucrt:${WINDOWSSDKDIR}/Include/10.0.15063.0/shared:${WINDOWSSDKDIR}/Include/10.0.15063.0/um:${WINDOWSSDKDIR}/Include/10.0.15063.0/winrt:${VSPATH}/DIA SDK/include"
export LIB="${VSPATH}/VC/lib:${VSPATH}/VC/atlmfc/lib:${WINDOWSSDKDIR}/lib/10.0.15063.0/ucrt/x86:${WINDOWSSDKDIR}/lib/10.0.15063.0/um/x86:${VSPATH}/DIA SDK/lib"

. $topsrcdir/build/mozconfig.vs-common

mk_export_correct_style WINDOWSSDKDIR
mk_export_correct_style INCLUDE
mk_export_correct_style LIB
mk_export_correct_style PATH
mk_export_correct_style WIN32_REDIST_DIR
mk_export_correct_style WIN_UCRT_REDIST_DIR

#--------------------------------------------------------------------

# bug 1356493 の回避のため、Windows 10上ではコマンドの探索先パスを追加する。
export PATH="$PATH:$WINDOWSSDKDIR/bin/10.0.15063.0/x64"
# パスを含む環境変数の内容を変更した後は、ビルドツールの1つである
# 「Pymakeが受け付けるパス形式に変換するために、必ず
# 「mk_export_correct_style 環境変数名」を実行する。
mk_export_correct_style PATH

ac_add_options --enable-crashreporter
ac_add_options --enable-release
ac_add_options --enable-jemalloc
ac_add_options --enable-require-all-d3dc-versions
ac_add_options --enable-warnings-as-errors

# 日本語リソースを使うための指定。
mk_add_options MOZ_CO_LOCALES=ja
ac_add_options --enable-ui-locale=ja
ac_add_options --with-l10n-base=c:/mozilla-source

日本語リソースの参照用に--with-l10n-baseで指定するパスは、言語リソースのリポジトリのパスではなく、その1つ上位のディレクトリのパスです。 MozillaBuildは、ここにMOZ_CO_LOCALESで指定した言語コード名を足したパスの /c/mozilla-source/ja に言語リソースがあることを期待します。

ビルドの実施

準備ができたら、いよいよビルドです。 Firefox本体のリポジトリにcdして、./mach buildを実行すればビルドが始まります。

$ cd /c/mozilla-source/mozilla-esr52
$ ./mach build

ビルドに使用するマシンの性能にもよりますが、現在手に入る一般的な性能のPCであれば1時間以内にはビルドが完了すると思われます。 弊社で検証に使用した環境は以下の性能のホストマシン上の仮想マシンで、仮想環境であることのオーバーヘッドがボトルネックとなった結果、ビルド時間はおよそ130分を要しました。

  • Interl Core i7 3.4GHz
  • 16GB RAMのうち8GBを割り当て

ビルドが完了したら、本当に動作するか確かめてみましょう。 以下のコマンドを実行すると、ビルドされたFirefoxが起動します。 アプリケーション名は「Nightly」になっているはずです。

$ ./mach run

正しく動作することを確認できたら、インストーラを作成しましょう。 これは以下のコマンドで行えます。

$ ./mach build installer

できあがったインストーラは、カレントディレクトリから見てobj-i686-pc-mingw32/dist/install/sea/の位置、フルパスではC:\mozilla-source\mozilla-esr52\obj-i686-pc-mingw32\dist\install\sea\の位置に出力されます。

まとめ

以上、Firefox ESR52.4.1を独自にビルドするための手順を簡単に解説しました。

Firefoxは現在様々な部分の刷新を進めており、現時点での最新の開発版においてはビルドに必要なツールとしてRustやLLVM/Clangのセットアップなども必要になってきています。この記事に記載した手順はあくまでESR52でのものなので、残念ながらそのままでは新しいバージョンのFirefoxには適用できませんのでご注意下さい。これについては、次のESRであるFirefox 59ESRがリリースされた後に改めてフォローアップ記事を公開する予定です。

タグ: Mozilla
2017-10-12

RedmineのMarkdownで箇条書きを書きやすく

RedmineのデフォルトのテキストフォーマッタはTextileですが、社内でMarkdownを使いたいという声が大きかったのでMarkdownを使えるようにして運用しています。 しかし、RedmineのMarkdownはRedcarpetを使用しているため3レベル以上のリストを書くときのインデントが辛い感じでした。 Redmineで3レベル以上の箇条書きでも2インデントでよくしたい · Issue #8 · clear-code/statistics

そこで、ククログでも使用しているCommonMarkerを使えるようにしてみました。

インストール方法はリンク先を参照してください。

Redmineを新しい記法に対応させる方法

上記プラグインを実装している過程でRedmineを新しい記法に対応させる方法をソースコードを読んで調べました。 ソースコードはdd9c0a82を使いました。

Redmine::WikiFormatting.map do |format|
  format.register :commonmark # :新しい記法の名前
                  Redmine::WikiFormatting::CommonMark::Formatter # 新しい記法で使うフォーマッタのクラス
                  Redmine::WikiFormatting::CommonMark::Helper # 新しい記法で使うヘルパーのクラス
                  Redmine::WikiFormatting::CommonMark::HtmlParser # 新しい記法で使うHTMLパーサーのクラス
end

という感じで登録すればよいです。 あとは必要なクラスを実装していけば、新しい記法を追加することができます。 一番最後の引数にハッシュを指定すると、追加のオプションを指定できます。調べた時点だと:labelというキーで、設定画面に表示するラベルを変更できるだけでした。*1

新しい記法で使うフォーマッタのクラスは、以下のインスタンスメソッドを実装している必要があります。

  • initialize(text)
  • to_html(*args)
  • get_section(index)
  • update_section(index, update, hash=nil)
  • extract_section(index)

セクションごとの更新が不要であれば、*_section系のメソッドは何もしないようにすることも可能でしょう。

新しい記法で使うヘルパーのクラスは、編集画面で使用するツールバーを読み込むためのヘルパーメソッドを定義します。

  • wikitoolbar_for(field_id)
  • initial_page_content(page)
  • heads_for_wiki_formatter

編集画面にツールバーが不要であれば、何もしないようにすることも可能でしょう。

新しい記法で使うHTMLパーサーのクラスでは、HTMLを新しい記法のテキストに変換するためのルールを定義します。 MarkdownやTextileだとHTMLタグと記法の対応が決まっているので、その対応が定義されていました

CommonMarkと(Redcarpetの)Markdownは、ほぼ同じなのでredmine_common_markではRedmineのMarkdown記法で使われているRedmine::WikiFormatting::Markdown::HelperRedmine::WikiFormatting::Markdown::HtmlParserを流用しました。

非互換

互換性のないところがいくつかあります。

`#prefer_delayed_commit`| `#prefer_buffered_processing`|      結果
:----------------------:|:----------------------------:|:---------------------:
      false             |           false              |     non-buffered
      false             |           true               | buffered synchronous
      true              |           true               | buffered asynchronous
      true              |           false              |      選択不可

上のようなテーブルを書くと、3行目以降が整形済みテキストになってしまいます。 以下のように行頭にパイプを追加することで回避できます。

|`#prefer_delayed_commit`| `#prefer_buffered_processing`|      結果
|:----------------------:|:----------------------------:|:---------------------:
|      false             |           false              |     non-buffered
|      false             |           true               | buffered synchronous
|      true              |           true               | buffered asynchronous
|      true              |           false              |      選択不可

CommonMarkerで使っているgithub/cmarkにオートリンクのバグがありました。既に報告済みで、報告してから11時間くらいで修正されていました。

まとめ

このようにRedmineは、ちょっとした改造なら本体に手を入れなくても、プラグインを作れば実現できてとても便利です。

*1 redmine_common_markで使っています

2017-10-11

PHPカンファレンス2017 - PostgreSQLとPGroongaで作るPHPマニュアル高速全文検索システム - OSS Gate東京ワークショップ #phpcon2017

はじめてPHPカンファレンスに参加した須藤です。午前に「PostgreSQLとPGroongaで作るPHPマニュアル高速全文検索システム」という話をして、午後に「OSS Gate東京ワークショップ2017-10-08 - PHPカンファレンス2017会場編 -」を開催しました。

「PostgreSQLとPGroongaで作るPHPマニュアル高速全文検索システム」のスライドは次の通りです。発表後にオートコンプリートの候補を登録する方法を話し忘れたことに気づいたので追記しました。

動画もあります。

関連リンク:

背景

第115回 PHP勉強会@東京PGroongaのことを話す機会があったので、そのデモのためにPHPのマニュアルをPGroongaで全文検索するアプリケーションを作りました。作ってみたところ、PHPユーザーにも便利そうな気がしてきたので、使ってもらったり開発に参加してもらうとよさそうだなぁと思い、PHPカンファレンス2017でも紹介しました。後述するOSS Gateワークショップの開催も第115回 PHP勉強会@東京のときに相談した結果として実現できたので、とてもよい機会でした。

今回の発表では、第115回 PHP勉強会@東京での内容に次の内容を加えました。

  • 類似マニュアル検索の実現方法
  • 同義語展開の実現方法

今回の発表の成果は悪くないです。このPHPマニュアル検索システムの開発に参加する人は増えていないのですが、この検索システムを運用してもらえることになりました!

PHPユーザーで、(PGroongaではなく)MroongaユーザーでもあるWEICさんが運営することになりました!今月中の運用開始を目指しています。URLは以下になる予定です。

運用が始まったら、おそらくWEICさんのお知らせページで告知されるので、チェックしてください!

簡単に使えるようになったらユーザーも開発者も増えることを期待しています。

そうそう、WEICさんはPHPエンジニアを大募集中だそうです!

OSS Gateワークショップ

午後は2時間45分の枠をもらってOSS Gateワークショップを開催しました。(終了時間を勘違いしていて25分早く終わらせてしまいました。。。)

このワークショップには通常バージョンとショートバージョンがあり、通常バージョンは5,6時間、ショートバージョンは2,3時間です。今回は3時間弱の枠だったのでショートバージョンで開催しました。

ショートバージョンは過去にOSS Gate東京ワークショップ for Mastodon in ピクシブ 2017-06-29で実施していて、今回もそれと同じように進めました。通常バージョンからの差は次の通りです。

  • できるだけ事前に対象OSSを決める
  • ミニふりかえりなし
    • 進行役・サポートメンターが随時まわってミニふりかえり的なことをしていく
  • 「ユーザーとして動かす」と「フィードバック」の時間を一緒にする
    • フィードバックポイントが見つかったらすぐにフィードバックに取り組む

今回、私が終了時間を勘違いしていたため最後のアンケートとふりかえりも省略しました。アンケートとふりかえりをやる時間はあったので失敗でした。

今回は時間内にフィードバックまでいけた人はほとんどいませんでした。フィードバックポイントに気づくところまではほとんどの人が経験していたので、フィードバックをまとめる時間が足りなかったということになります。予想した要因は次の通りです。

  • サポーター1人でビギナー2人だとサポートが手薄
    • ピクシブさんで開催したときはサポーター1人でビギナー1人だった
    • ビギナーの人がもう少しサポートを厚くできると時間を短くできそう

試してみたいことは次の通りです。

  • サポーター2人でビギナー3人をサポート
  • サポーター1人でビギナー2人をサポートするけど、サポーター2人つきサポートメンターが1人サポート
    • 今回はサポーター4人につきサポートメンターが1人サポート

今回、初めてPHP関連のOSS限定のOSS Gateワークショップを開催しました。今回だけで終わりにせずに今回が始まりにしていきたいので、PHP関連のOSSの開発に参加する人が増えるとうれしいという人はぜひ一緒にやっていきましょう!Gitterのoss-gate/tokyo-phpでオンラインで相談しています。まずはここに来てください!現状は、今回ワークショップに参加した人と次回の開催について相談するところです。

まとめ

PHPカンファレンス2017で、PGroongaの話をして、OSS Gateワークショップも開催しました。今回の機会をぜひ今後につなげていきたいです。

タグ: Groonga
2017-10-10

Firefox 57以降での従来アドオン廃止を踏まえたFirefoxの企業利用での対策について

Firefox 57では従来形式のアドオンがすべて無効化され、Firefox 52移行で既に使用可能になっている新方式のアドオンのみが有効になります。 この事がFirefoxの企業・法人利用に与える影響とその対策についてご案内します。

ESR版での影響

Firefoxの製品ラインナップには、約1.5ヶ月ごとに更新されメジャーバージョンが繰り上がっていく一般向けの「通常リリース版」と、1年ほどの間メジャーバージョンが固定されセキュリティアップデートだけが提供され続ける「ESR版」とがあります。

現在の通常リリース版の最新版はFirefox 56.0、ESR版の最新版はFirefox 52.4.0ESRです。 ESR版の次のメジャーアップデートはFirefox 59との同時リリースが予定されており、それまでの間は引き続き52.5.0ESR、52.6.0ESRといったセキュリティアップデートが提供される見込みです。 そのため、ESR版をお使いの場合には今すぐ対策を取る必要はありません。

ただし、Firefox 59ESRでは従来アドオンが無効化されるという事は確定事項なので、いざその時が来ても慌てずに済むように、今のうちから対策を検討しておくのが望ましいです。

アドオンによらないカスタマイズが受ける影響

Firefoxの企業利用においては、管理者が決めた設定を全クライアントに反映するための方法としてMCDが使われる事が多いでしょう。

現時点で判明している限りにおいては、MCDでのカスタマイズはFirefox 57以降のバージョンでも引き続き使用可能と考えられます。

ただし、Firefox 57以降のバージョンでは従来アドオンの無効化に伴い、従来アドオンとの互換性のために残されていたもののメンテナンスの負担となっていた内部的な古い機能・実装の削除が進められています。 MCDでは裏技的に Components.classes[...] といったコードによってFirefoxの内部機能へアクセスすることができていましたが、この方法で呼び出していた内部機能がFirefox 59ESRにおいては削除されている可能性があります。 その場合、代替する方法を調査してMCDの設定ファイルを更新しなくてはなりませんが、場合によっては代替手段がないため設定を諦めなくてはいけないかもしれません。 十分にご注意下さい。

アドオンによるカスタマイズが受ける影響

カスタマイズにアドオンを使用していて、そのアドオンがFirefox 57以降のバージョンに対応していない場合、当然ながらFirefox 59においてもそのアドオンは使用できません。 アドオンをFirefox 57以降の新仕様に対応したバージョンに更新するか、当該アドオンで行っていた変更を代替する他の方法でのカスタマイズに切り替える必要があります。

クリアコードではお客様向けのカスタマイズ用として多数のアドオンを開発・提供しています。 しかしながら、これらの中でFirefox 57以降のバージョンでも使用できるように更新された物はほとんどなく、また更新の可能性も極めて低いと言わざるを得ません。 これは従来のアドオンと新方式のアドオンとの根本的な差異に原因があります。

従来のアドオンはFirefoxの内部に自由に変更を加える事ができ、弊社提供のアドオンの多くは、この性質を使ってFirefoxに「使用を禁止したい機能を無効化・非表示にする」といった変更を加えていました。 (図:従来のアドオンの原理) その一方で、Firefox 57以降で使用可能な新方式のアドオンは、各アドオンを隔離された環境で動作させ、あらかじめ用意されたAPIを経由してのみFirefoxに影響を与えられるという仕組みになっています。 (図:新方式のアドオンの原理) そのため、「行いたい変更を実現するためのAPI」が提供されていない変更は不可能ということになります。

なお、新方式のアドオンで利用できるAPIにはNative Messagingという物もあり、「APIが提供されていない事でもこれを使えば実現できる」という触れ込みとなっています。 ですが、上記の理由でFirefox 57に対応できない弊社製アドオンの多くに対しては、残念ながらこの機能も解決策とはなりません。 Native Messaging Hostはアドオンとローカルアプリケーションとの間で通信ができるという物で、Firefoxの外の世界との連携によってできる事の幅は広がりますが、Firefox内部に対しては依然として何もできないままだからです。

使えなくなるアドオンの代替となるカスタマイズ方法

以上の理由から、アドオンへの依存度が高い場合ほど、Firefox 57以降での変更への対応には注意を要します。 運用上使用を禁止したい機能がある場合には、Firefox上では機能を無効化できないため、別の技術レイヤーで機能を停止・無効化しなくてはなりません。

現在公開中の企業利用向けカスタマイズのまとめでは、目的からカスタマイズの方法を逆引きできる形で資料を整備していますが、中にはカスタマイズにアドオンを必要とする項目も含まれています。 そのため各項目について調査を行い、現時点で代替手法が存在する物についてはその旨を追記し、代替手法が無い物はカスタマイズ項目としては廃止の扱いとするよう内容を更新しました。 (※この資料の内容は随時更新されていますので、必ずその時点での最新版をご参照いただくようご注意下さい。)

ただし、この資料には弊社サポートサービスをご利用になられているお客様の環境で必要となったために調査した範囲のカスタマイズ内容のみが記載されており、それ以外の未知のカスタマイズについては情報がございません。 この資料に記載がないカスタマイズを反映されていて、Firefox 57以降への対応に不安をお持ちの企業担当者様がいらっしゃいましたら、まずはお問い合わせフォームよりご相談下さい。

Firefox 57以降に対応済みのアドオンのご紹介:IE View WE

弊社サポートサービスをご利用のお客様の環境ではアドオン「IE View」の使用頻度が高いものの、このアドオン自体は長らく更新が停止されており、また代替となる他のアドオンでは管理者側で設定を制御できるものが無かったことから、弊社で独自にFirefox 57以降にも対応したクローン版であるIE View WEを開発・公開しています。

従来バージョンのIE Viewとの差異として、URLのリストの形式に互換性が無い点にご注意下さい。 IE View WEでは、URLのリストはFirefoxのアドオンで一般的に使用されるマッチパターンのリストとして解釈されます。 従来バージョンでは http://www.example.com のようにホスト名までのみの指定でも機能しますが、IE View WEではhttp://www.example.com/* のように明示的にワイルドカードを使用してマッチパターンとして記載する必要があります。

Native Messaging Hostのインストール

IE View WEは前述のNative Messaging Hostを使用して外部アプリケーションを起動するという動作を実現しているため、使用にあたっては別途専用のNative Messaging Hostのインストールが必要です。 GitHubのリリース一覧ページからieview-we-host.zipをダウンロードして展開し、install.batを管理者として実行すると実行ファイルがインストールされます。 (一般ユーザーとして実行した場合、そのユーザーでのみ使用可能な状態でインストールされます。ご注意下さい。)

管理者による設定の提供

Firefox 57以降のバージョンで使用可能なManaged Storage機能を通じて、管理者が固定の設定を提供することができます。 GitHubのリリース一覧ページからieview-we-managed-host.zipをダウンロードして展開し、install.batを管理者として実行すると設定ファイルがインストールされます。 (一般ユーザーとして実行した場合、そのユーザーでのみ参照可能な状態でインストールされます。ご注意下さい。) ファイルのインストール前にieview-we@clear-code.com.jsonを編集してdata配下に以下の情報を設定すると、それがそのままIE View WE用の設定となります。

  • ieapp (文字列値, IEの実行ファイルのパス)
  • ieargs (文字列値, IEの起動時に指定する追加の引数)
  • forceielist (文字列値, URLのマッチングパターンの空白文字区切りのリスト)
  • disableForce (真偽値, forceielist`で与えられたリストの無効化)
  • contextMenu (真偽値, コンテキストメニュー項目の有効化)
  • debug (真偽値, デバッグログ出力の有効化)

また、Firefox 56以前のバージョン向けとして、MCDの設定ファイルから設定を読み取る機能もあります。 MCD用設定ファイルの以下の設定項目がある場合、それぞれ対応する設定に反映されます。

  • extensions.ieview.ieapp
  • extensions.ieview.ieargs
  • extensions.ieview.forceielist
  • extensions.ieview.disableForce
  • extensions.ieview.contextMenu
  • extensions.ieview.debug

ただし技術的な制限のため、設定ファイルの配置場所や内容、使用状況によっては設定をインポートできない場合があります。 悪しからずご了承下さい。

まとめ

以上、Firefox 59ESRを見据えたFirefox 57以降のバージョンでのアドオンの仕様変更に伴う企業利用上の注意点とその対策、およびFirefox 57以降でも使用可能なIE ViewのクローンであるIE View WEについてご紹介しました。

クリアコードではFirefoxの企業での利用に際してのカスタマイズのご案内、導入支援、発生したトラブルの原因究明、対策の調査等をサポートサービスとして行っております。 これらの事でお困りの企業担当者様がいらっしゃいましたら、お問い合わせフォームよりご相談下さい。

タグ: Mozilla
2017-10-05

データ分析基盤構築入門

データ分析基盤構築入門という書籍を著者の一人@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

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

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

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

事前情報: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

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

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|
タグ: