PLAID Advent Calendar 2017 6日目。
プレイド @otolabです。
3日目はやっぱり読みづらかったので、後で直します。orz
今回は、Engineer Blogの記事「日本語を理解するチャットボットに挑戦した話【デモあり】」の続きです。
大きな変更があったわけではないのですが、構成をマイクロサービス的に変更してちょっとだけ使いやすくなりました。
halumi-coreとは
自由入力された日本語をjumanpp + knpで解析し、登録した簡単なパターンにマッチするかを判定して返すエンジンです。
今年の春の開発合宿で社内の労務botを更新するプロジェクトの一環として作成しました。
裏のテーマとしては、用意するのが面倒なツールのDocker Image化の可能性を探ることです。今回のcoreのマイクロサービス化、はるみさん全体のSwarm化で一定のノウハウは得られたかなという感じです。
hal(はるみさん)とは
弊社PLAID社内で活躍しているslackボットです。
皆でmaster直コミット上等のノリで開発しており、Github、Google Spreadsheet、Google Calendar、Salesforceなどと連携する多機能なハブになっています。
重要な機能の一つに休暇申請の機能がありますが、入力の自由度が低かったことから、日本語の解析を使う機能拡張を試みたという経緯です。
いまのところはるみさんのコードを公開する予定はないですが、整理して公開するのも結構面白いのではないかなと個人的には思っています。
後述しますが、Docker Swarmで稼働するようになりました。
前回記事からのアップデート
本質的な機能はまったく変わっていないのですが、hal本体の開発に適用したことで調整したほうが良いところがいろいろ見えてきました。
配布イメージの縮小
実行時に使う形式の辞書が大きすぎて、10GB近いDocker Imageになり、デプロイ時に時間が掛かるなど不便だったので、辞書構築を起動時に行うように変更しました。
また、ツールのビルドと配布のイメージを分けるDockerfileの新しい機能を利用して、余分な開発ツールが入らないように変更しています。無理やり一行におさめていたコードもばらせるようになるので、この機能はかなり便利です。
全体としては1.8GB程度とだいぶ小さく...なってない気もしますが、少しはましになりました。反面、初回起動時の辞書構築の時間とリソース消費が結構高いので、まだちょっと考え直さないといけないかなぁという感じです。(volumeとして保存されるので、辞書のビルドは初回起動時のみです)
辞書の構築作業のタイミングが変わり、ユーザ辞書の追加も楽になったので、もうちょっと考えてみたいところですね。
また、Docker ImageのビルドはDocker HubとGithubを連携させて行うようになりました。便利。
マイクロサービス化
もともとは構築の面倒なコマンドラインツールを含んだDocker Imageを作り、その中にアプリの実行環境をつくることを目指していました。
そのため、コマンドを含む実行環境+ライブラリのキットとして構築していたのですが...この構造だとhal本体と日本語分析機能が密結合になってしまうため、必須でないはずのhalumi-coreが外せなくなってしまうなど、不便さが目立つようになりました。
またjuman、knpは辞書データなどのリソース要求量(主にメモリ)が多く、軽量で頻繁に更新されるhal本体と一体化していると、いろいろ無理があるなということがわかりました。将来的にはhal本体はDockerの操作のためにSwarmのmanager nodeに載せたいという理由もあります。
というわけで、マイクロサービス化して分離する運びとなりました。
コンテナ間の接続にはsocket.ioをベースとした弊社開発のライブラリbolt-rpcを使い、利用側は通常の非同期メソッドとして簡単に解析機能を使えるようになっています。
デモ用にサンプルコードを作りました。接続先の指定こそ必要ですが、使う際にはコンテナの構造をあまり意識せず使うことが出来ます。
はるみさんのDocker Swarm化
無事、halumi-coreとhal本体のコンテナ化ができたので、もともとはMacBookで動かしていたはるみさんをDocker Swarmに載せかえることにしました。
Docker CloudをAWSと連携してSwarmクラスタを構築、Docker for Macから端末を開きdockerコマンドを使って操作する手順になります。Docker for Mac、便利です。
デプロイ(更新)のコマンドと、設定ファイル(docker-cloud.yml
)はだいたいこんな↓感じ。
$ docker stack deploy -c docker-cloud.yml --with-registry-auth halumi
version: '3'
services:
halumi-core:
image: otolab/halumi-core
environment:
TZ: 'Asia/Tokyo'
SERVER_MODE: "rpc"
deploy:
replicas: 1
resources:
limits:
memory: 2G
reservations:
memory: 500M
restart_policy:
condition: on-failure
delay: 10s
placement:
constraints:
- node.role == worker
halumi:
image: plaid/hal-******
environment:
TZ: 'Asia/Tokyo'
deploy:
replicas: 1
resources:
limits:
memory: 500M
reservations:
memory: 10M
restart_policy:
condition: on-failure
delay: 10s
placement:
constraints:
- node.role == worker
halumi-core
とhalumi
の2つのサービスを作り、それぞれのリソース量割り当ての設定などを行なっています。実際のファイルではlog出力先の設定も行なっていますが、割愛しました。
今後の展望
優れたツール・ライブラリが増える中、この先どのくらい進めてみるかなかなか微妙なところですが、改善したいところというのは常にいろいろあるもので...
まず、応答が遅い時があります。OSのキャッシュが効くと早いようなのですが、辞書の読み込みに時間が掛かっている場合に発生するようです。jumanpp、knp共にサーバモードを持っているので、そちらに移行したいところ。
また、現在はhalumi-coreとしてパターンのマッチのAPIのみを持っていますが、単純にjumanpp + knpのマイクロサービスImageとしての機能を提供したほうが、需要が大きいんじゃないかと思い始めました。サーバモードのサポートや、単語追加の機能などがあると結構便利そうです。
...もっとも、pythonで稼働する高速なjumanpp + knpパッケージを作成した方がいらっしゃるので、そちらを使う方が良いのかもしれないなぁ。という気もしております。(こちらの記事です 「Juman(Juman++) & KNPの動作を高速化するパッケージを作った話」)
Engineer Blog記事中のデモに関するお礼
ご協力、ありがとうございまいした。m(_ _)m
現行の仕組みとして、決まりきったごく少数の言葉にした応答できないので、大半の入力に追いつけませんでした。期待して入力してもらったのに申し訳ない...。
応答可能な内容について、入力時にもう少し分かりやすくしたほうが良かったかなと反省です。
デフォルト入力で「意図した応答である」、自由記述で「意図した応答でない」と回答してくれた方も結構居ました。
雑談モード欲しい
自分も欲しいんですが、まだ付いていません。いろいろ面白そうなサービスが世の中にはあるようですので、そのあたりを試しがてら何か書く...かも?