狠狠撸

狠狠撸Share a Scribd company logo
HHVM/Hack を本番投入した話
2018/4/20@KenjiroKubota
Pro le
Kenjiro Kubota
istyle.inc
favorite: PHP Javascript ...Hack!
この中で贬补肠办を书いている触书いたことがある人
この中で贬贬痴惭环境を本番で使ってる人
アイスタイルでHHVM/Hackを採用した経緯
いくつかの社内サービスAPIをまとめるProxyのようなサーバーサイ
ドアプリケーションが必要だった。
アイスタイルでHHVM/Hackを採用した経緯
いくつかの社内サービスAPIをまとめるProxyのようなサーバーサイ
ドアプリケーションが必要だった。
Golangは社内事例が既にいくつもあった。
アイスタイルでHHVM/Hackを採用した経緯
いくつかの社内サービスAPIをまとめるProxyのようなサーバーサイ
ドアプリケーションが必要だった。
Golangは社内事例が既にいくつもあった。
開発担当者(私)がPHPer。PHP愛にあふれていた
アイスタイルでHHVM/Hackを採用した経緯
いくつかの社内サービスAPIをまとめるProxyのようなサーバーサイ
ドアプリケーションが必要だった。
Golangは社内事例が既にいくつもあった。
開発担当者(私)がPHPer。PHP愛にあふれていた
でもPHPで並列でAPIをコールするのがつらそう
あ、贬补肠办なら并列で础笔滨コールできるはず
アイスタイルでHHVM/Hackを採用した経緯
いくつかの社内サービスAPIをまとめるProxyのようなサーバーサイ
ドアプリケーションが必要だった。
Golangは社内事例が既にいくつもあった。
開発担当者(私)がPHPer。PHP愛にあふれていた
でもPHPで並列でAPIをコールするのがつらそう
部長が二つ返事でOKだったので採用
あとは部長が社内的にパワープレイで???
フレームワーク選定
とくにこだわりもなく、HHVM上で動くものならなんでもよかっ
た。
とはいえあまり大げさなFWは不要
Lumen, Silex, Slim3, ZendExpressive
SymfonyはHHVMのサポートやめたって聞いたのでLumen除外
ZendExpressiveは何回か書いたことあるのですぐに作れそう
ZendExpressiveを採用
最新版のZendExpressiveがHHVM上で動かない
開発当初のv2系がHHVM上で動作しませんでした。
v1系に落としたところ問題なく動作したので開発続行
IDE
HackはPHPer愛用のPHPStormでは一切補完が効かない
Facebook社製AtomPluginのNuclideかVisualStudioCodeの
HackPluginがオススメ
-(というかそれしか選択肢が無い)
後者の場合はローカルにHHVMをインストールしないとコードジャ
ンプできません。(たぶん)
Windowsで開発するのがだいぶ辛いです。
Dir構成
├─config
│ └─autoload
├─data
│ └─cache
├─public
│ └─apidoc
├─src
│ ├─Action
│ ├─Client
│ ├─Entity
│ ├─Exception
│ ├─Foundation
│ ├─Middleware
│ ├─Repository
│ ├─Service
│ ├─UseCase
│ └─ValueObject
├─storage
│ └─logs
└─test
処理の流れとしては
Middleware -> Action -> Service or UseCase -> Repository -> Client
ActionClass層以下はほぼほぼAsync関数で実装していて、各APIコール
のレスポンス時間を無駄にしない。
Action Class
<?hh
final class ExampleAction
{
public function __construct(
private ExampleService $exampleService
) {}
public function __invoke(
ServerRequestInterface $request,
ResponseInterface $response,
?callable $next = null
): JsonResponse {
$query = (array) $request->getQueryParams();
$example = HHAsiojoin($this->exampleService->get((string)$query['hoge']));
$res = [
'count'=> $example->count(),
'hoge' => $example->toArray()
];
return new JsonResponse($res);
}
}
public function __construct(
private ExampleService $exampleService
) {}
はPHPの以下に相当
private $exampleService;
public function __construct(ExampleService $exampleService) {
$this->exampleService = $exampleService;
}
Async function
$example = HHAsiojoin($this->exampleService->get((string)$query['hoge']));
$this->exampleService->get()
この関数はasync関数となっていて、Awaitable型が返却される。
async function get(string $hoge): Awaitable<Map>
その際には HHAsiojoin() で受け取ることで非同期から同期的な処理に
することができる。
感覚としてはjavascriptのPromiseっぽい?
Collection
$example = HHAsiojoin($this->exampleService->get((string)$query['hoge']));
$res = [
'count'=> $example->count(),
'hoge' => $example->toArray()
];
Hackが独自で持っている配列の拡張
Vector , ImmVector , Map , ImmMap , Set , ImmSet , Pair
上の例では $example は Map 型になるので ->count() や ->toArray() 関数を持
っている。(便利)
落とし穴その壱
foreachによるイテレートはブロッキングする
foreachの中でawaitで受け取るパターン
$lists の一つ一つの値を使って並列にAPIをコールしたとする。
foreach($lists as $list) {
$array[] = await $this->getDetail($list);
}
一見非同期的に getDetail() が実行されるかと思いきや、1回ループが
回るたびにawaitを待つような挙動になるのでPHPと変わらず遅い
そういう場合は以下のようにするとブロッキングしない
async function getLists(Vector $lists): Awaitable<Map> {
$handle = $lists->map($list ==> $this->getDetail($list));
return await HHAsiom($handle);
}
(追記)
多分以下でも大丈夫
(Lamdaの書き方がかっこよかったので使ってみたかったマン)
foreach($lists as $list) {
$array[] = $this->getDetail($list);
}
return await HHAsiom($array);
落とし穴その弐
HHAsiocurl_execでHHVMがクラッシュ
贬贬痴惭/贬补肠办を本番投入した话
どうなっていたのか(再掲)
HHAsiocurl_exec が内部で利用している curl_multi_await という
HHVM(C++)関数でレスポンスが遅いエンドポイントがある場合に
Abortするバグがあった。
PHPのリクエスト、レスポンスの処理とは違い、HHVMではレスポン
スを返した後もこの関数が実行され続けてしばらくすると落ちる挙動に
なっていた
このため、どのタイミングでHHVMがクラッシュするのかの把握が遅
れた???
1/5に修正される(再掲)
c++で実装していた curl_multi_await をhack実装に変更
async function curl_multi_await(
resource $mh,
float $timeout = 1.0,
): Awaitable<int> {
$finish_by = microtime(true) + $timeout;
do {
$result = curl_multi_select($mh, 0.0);
if ($result !== 0) {
return $result;
}
await HHAsiolater();
} while (microtime(true) < $finish_by);
return 0;
}
現在の最新ver3.25.2には修正反映済み
PHPerkaigi2018時点では反映されてませんでした。
Hackの良かったところ
Collection型が地味に便利
enumがある!(PHPには言語的にはない)
Pipe Operatorがいい!
f() |> g($$) |> h(5, $$) === h(5, g(f()))
無名関数をしゅっとかけるLamdaが良い
<?hh
$user = 'Joel';
$greeting = () ==> 'Hello '.$user; // Hello Joel
Hackを導入してみて...
PHPに似ているのはPHPerにとっては学習コストがほぼゼロ
(ゼロとは言ってない)
PHPでもう少しこう書けたらいいな、みたいなことができて良い
PHP + JavascriptみたいなノリでAPIの並列コールができてしまっ
た。
バグを踏み抜くと辛い
どんどん新しい要素が盛り込まれていくので楽しみではある
thanks:)

More Related Content

贬贬痴惭/贬补肠办を本番投入した话