Hack/HHVMの商用運用について
HHVMを商用環境や、または導入にあたり
本番向けのパフォーマンスチューニング等をしておく必要があります。
開発環境とは設定が異なりますので、今回はTypecheckerのオフと、
コンテナを使ってコンパイルしてシングルバイナリで動作させる方法を紹介していきます。
商用ではTypecheckerをオフにしよう
商用環境で動かす場合は、レビューなどを通っていることが前提です。
曖昧な型が入り込む可能性が非常に低いですが、
それは開発時に動作させているTypecheckerのおかげです。
そんなTypecheckerは商用で動作させる必要はありません。
下記の設定をphp.iniに追記してhhvmを起動させましょう。
hhvm.hack.lang.look_for_typechecker = false
もちろん開発時にオフにしてはいけません!
JITコンパイラ
HHVMのJITコンパイラの設定は細かくすることができます。
コンパイル
これはRepo Authoritativeと呼ばれるもので、
ソースコードをコンパイルして動かすモードです。
JITだけで早くするよりは、併用して効果があるものとなっています。
またLL言語でよくある商用環境で直接ファイルを操作するなどの事故もなくなりますので
安全にアプリケーションを運用することができます。
基本的な使い方
特定のディレクトリ配下を全てコンパイルするには下記のコマンドを実行します
$ hhvm --hphp -t hhbc --input-dir /path/to/root
マニュアルにも載っていますが、各フラグは下記の通りです
--hphp | HHVMでHackのコードを実行せずにオフラインで操作するためのフラグ |
-t | ターゲットを指定するもので、この場合はhhbcとなっており、これはHHVMバイトコードを意味します |
--input-dir | コンパイルソールコードがあるディレクトリを指定 |
--output-dir | コンパイルされたファイルの出力先を指定 これがないとtmp配下にランダムな文字列のディレクトリに吐き出します。 |
シンプルなアプリケーションであればこれだけで済みますが、
商用で動かすアプリケーションはそこまでシンプルなものはありません。
もうすこし細かい設定が必要です。
そんなときは下記のものを利用します
$ hhvm --hphp -t hhbc --module src --module vendor --ffile public/index.php
先ほどの例と少し変わりました。
先程の --input-dir
は一つしか指定ができず、
実際には不要なファイルなども含めてしまうため、必要なものだけを含めるのがベストです。
そのため必要なファイルだけ指定するには上記のように細かく指定します。
--module | Hackのコードが含まれるディレクトトリを指定します。これは複数指定できます。 |
--ffile | Hackのソースコードのファイルを指定 |
上記の例では--ffile
でエントリポイントのスクリプトを指定、
アプリケーションの実装コードが含まれるディレクトリ、
composerでインストールしたライブラリが含まれるディレクトリを指定してコンパイルしています。
これで十分そうですね。
静的ファイル?
HHVMでは静的ファイルもコンパイルすることができます。
$ hhvm --hphp -t hhbc --module src --module vendor --ffile public/index.php \
--file-cache /var/www/file.cache \
--cfile public/static/image.png
--cmodule public/images
利用できるものは以下の通りです。
--cfile | コンパイルに含めたい静的ファイルを指定 |
--cmodule | コンパイルに含めたい静的ファイルが含まれるディレクトリを指定 |
--file-cache | ファイルキャッシュを作成します |
これさえ覚えておけばコンパイルできそうです。
コンテナとバイトコード
コンパイルの方法がわかったところで、実際にコンテナと組み合わせてみます。
一般的なエントリポイントがpublic/index.hackで、srcとvendorディレクトリを使用しているアプリケーションを、
HHVM4.87でコンパイルします。
マルチステージビルドを使った例です。
FROM hhvm/hhvm-proxygen:4.86-latest AS dev
RUN apt-get update
RUN DEBIAN_FRONTEND=noninteractive
RUN apt install -y dnsutils iputils-ping net-tools
RUN hhvm --version && php --version
RUN cd $(mktemp -d) \
&& curl https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
COPY . /var/www
WORKDIR /var/www
RUN composer install --no-dev -o
FROM hhvm/hhvm-proxygen:4.87-latest AS build
COPY --from=dev / /
WORKDIR /var/www
RUN hhvm --hphp --target hhbc \
-l3 \
-d hhvm.check_return_type_hints=3 \
--module src \
--module vendor \
--ffile public/index.hack \
--output-dir /var/www \
--file-cache /var/www/file.cache
RUN rm -rf vender \
rm -rf src \
rm -rf *yml \
rm -rf /usr/local/bin/composer
FROM hhvm/hhvm-proxygen:4.87-latest AS prod
COPY --from=dev / /
dev向けには通常通りcomposerでinstallするところまでを含め、
buildではアプリケーションで必要なHackのコードなどをコンパイルします。
コンパイル後はcomposerやソースコードは不要なので削除します。
prodではコンパイル後に生成されるhhvm.hhbcをコピーしています。
実際にコンテナをECRなどに登録する場合はbuildでコンパイルされた状態で十分です。
試しにコンパイルして動かすには前回までに紹介したXHPのサンプルコードなども混ぜてみるといいでしょう。
これで動かす準備が整いました。
次にhhvm.hhbcをHHVMの本番向けiniに記述します。
date.timezone = Asia/Tokyo
hhvm.log.header = false
hhvm.debug.server_error_message = false
display_errors = Off
html_errors = Off
error_reporting = 22527
hhvm.server.fix_path_info = true
hhvm.server.type = proxygen
hhvm.server.port = 18080
hhvm.log.use_log_file = true
hhvm.server.allow_run_as_root = true
hhvm.jit=1
hhvm.server.utf8ize_replace=true
hhvm.log.file=/dev/stderr
hhvm.admin_server.port=19001
hhvm.admin_server.password=SomePassword
hhvm.server.default_document=index.hack
hhvm.server.error_document404=index.hack
hhvm.server.thread_count=20
hhvm.jit_worker_threads=1
hhvm.jit_worker_arenas=1
hhvm.check_return_type_hints=3
hhvm.hack.lang.look_for_typechecker = false
hhvm.repo.authoritative=true
hhvm.repo.central.path=/var/www/hhvm.hhbc
hhvm.server.enable_static_content_from_disk=false
hhvm.server.file_cache=/var/www/file.cache
hhvm.server.source_root=/var/www
hhvm.virtual_host[default][path_translation]=public
コンパイルしたバイトコードを実行するには、hhvm.repo.authoritative
を有効にします。
次にバイトコードのパスを hhvm.repo.central.path
で指定します。
ファイルキャッシュがある場合は hhvm.server.file_cache
で指定しておきましょう。
hhvm.server.source_root
はソースコードのルートで、
hhvm.virtual_host
はアクセスされた時にエントリポイントがあるディレクトリを指定します。
実際にファイルは存在していませんがバイトコード上に情報がありますので、
それと合わせるようにします。
もちろんhhvm.server.default_document
も指定します。
手元で確認したい場合、docker-compose.ymlは下記のようにしておくといいでしょう。
version: '3.8'
services:
hhvm:
build:
context: .
dockerfile: ./docker/hhvm/Dockerfile
target: dev
volumes:
- .:/var/www
- ./docker/hhvm/hh.conf:/etc/hh.conf
- ./docker/hhvm/php.ini:/etc/hhvm/php.ini
- ./docker/hhvm/server.ini:/etc/hhvm/server.ini
command: hhvm --mode server -vServer.AllowRunAsRoot=1
tty: true
container_name: hhvm
ports:
- 19001:19001
restart: always
hhvm-build:
build:
context: .
dockerfile: ./docker/hhvm/Dockerfile
target: build
volumes:
- .:/var/www
- ./docker/hhvm/hh.conf:/etc/hh.conf
- ./docker/hhvm/php-prod.ini:/etc/hhvm/php.ini
- ./docker/hhvm/server.ini:/etc/hhvm/server.ini
tty: true
container_name: hhvm
ports:
- 19001:19001
restart: always
hhvm-prod:
build:
context: .
dockerfile: ./docker/hhvm/Dockerfile
target: prod
privileged: true
volumes:
- ./docker/hhvm/php-prod.ini:/etc/hhvm/php.ini
- ./docker/hhvm/server.ini:/etc/hhvm/server.ini
command: hhvm --mode server -d hhvm.log.level=verbose -vServer.AllowRunAsRoot=1 -vEval.HackCompilerWorkers=1
tty: true
container_name: hhvm
ports:
- 19001:19001
restart: always
web-server:
build:
context: .
dockerfile: ./docker/nginx/Dockerfile
ports:
- 80:80
container_name: web-server
tty: true
$ docker-compose up web-server hhvm-prod
などで手元で起動させてみてください。
バイトコードになったHackのコードがHHVM上で動いているのが確認できると思います。
当然コンパイルされたものですので、ファイルを変更しようが戻そうが反映されないことがわかります。
コンテナ技術が発展した環境では十分すぎるメリットがあります。
LL言語でありながらも静的型付け言語よりなHack/HHVMの利点でもありますので、
是非使ってみてください!