LINE株式会社は、2023年10月1日にLINEヤフー株式会社になりました。LINEヤフー株式会社の新しいブログはこちらです。 LINEヤフー Tech Blog

Blog


LINE BusinessConnectの技術話

LINE技術戦略室のYoichiroです。今回の記事では、先日発表させていただきましたLINE BusinessConnectの技術的な話を少ししてみようと思います。

LINE BusinessConnectとは?

まずは、LINE BusinessConnectとは何かを説明しましょう。簡単に言うと「プログラムで自動応答可能な公式アカウントを作れます」というものです。

今までの公式アカウントやLINE@は、それを運営するスタッフの方々が管理用に提供されているCMSから何かメッセージを投稿することで、そのメッセージがユーザに届けられています。そういう意味では「人間」が発しているメッセージですね。

これに対して、LINE BusinessConnectの場合は、ユーザが送信したメッセージを受け取り、その内容に応じて自動的にそのユーザに返事を送信する、という処理を行うプログラムが作れるようになりました、ということになります。

つまり、公式アカウントがインタラクティブなものになった、ということです。

このように固く表現するよりは、実例からイメージした方が理解が早いかも知れません。実は、今までもインタラクティブな公式アカウントはLINEに存在していました。そうです、翻訳系のアカウントですね。それらは、ユーザが送信したメッセージを受け取り、自動的に翻訳し、その結果を返信します。もちろんこれが人力で行われているわけはありませんよね?メッセージの受信から翻訳処理、そして返信という一連の処理をプログラムが自動的に行っています。ユーザが送信するメッセージは「同じものは全くない」と言って良いほど多種多様です。つまり、返事も多種多様であり、まさにインタラクティブなアカウントの例として最適でしょう。

LINE BusinessConnectでできること

そんなLINE BusinessConnectを「なんだ、人工無能か」や「企業からメッセージがスパム送信できるな」と捉えてしまったら、本当にそれは残念なことです。LINE BusinessConnectは大きな可能性を秘めた仕組みです。もちろんLINE BusinessConnectができることは、メッセージを受け取ってそれに返信する、基本的にそれだけです。しかし、これがLINEを日々使っている方々の生活を変えるかもしれません。

lbc_1

「BusinessConnect」という言葉の通り、LINE BusinessConnectはユーザとビジネスを繋ぎます。LINE社と他社を繋げるのではなく、インターネット上にあるサービスはもちろん、そうではないリアルなサービスとも、LINE BusinessConnectは繋いでくれます。ユースケースの代表例は、「ピザ屋さん」です。

  • ユーザが「○○ピザ屋さん」公式アカウントを友だち登録する。
  • そのユーザが「ピザスタンプ」を送信する。
  • ピザが自宅に届く。

上記はいろいろと省いていますが、簡単に言うと、このようなことが実現します。次に「レンタルビデオ店」であれば、以下のような感じでしょう。

  • ユーザが「○○レンタルビデオ」公式アカウントを友だち登録する。
  • そのユーザが実際の店舗で、何かビデオを借りる。
  • 返却予定日の前の日に「明日は返却日です。忘れずに!」とメッセージが来る。
  • 返しに行く。

もっとすごい例として、タクシーはいかがでしょうか?

  • ユーザが「○○タクシー」公式アカウントを友だち登録する。
  • そのユーザが、ある交差点で現在地を送信する。
  • 数分後にタクシーが来る。

これらは極端な例と思うかも知れませんが、どれも全く極端とは考えていません。ポイントとしてはインターネット上で完結せず、リアルなサービスを利用するためにLINEから何かをしている、ということがあげられます。友だちと会話をする時と全く同じ感覚で、いろいろなことが可能になるのです。

2番目のリマインドメッセージの送信を拡大解釈して「お、ダイレクトメッセージ送信できるのか、しめしめ」と考えてユーザに送信しまくりたくなる方がいらっしゃるかもしれませんが、友だち登録しているユーザのみ送信可能であり、そもそもそんなメッセージ送信をしたら、多くのユーザにブロックや友だち削除されてしまうことでしょう。ユーザが離れていき、悪い印象と共にダメージだけが残る結果になってしまうこと必至です。

LINE BusinessConnectの仕組み

実現できることが何となく見えてきたところで、技術的な話に進んでいきましょう。

LINE BusinessConnectが登場する前までは、LINEのメッセージは「LINE ClientアプリとLINE Server」の間で行ったり来たりするだけのものでした。あるユーザの端末から発信されたメッセージは、LINE Serverを経由して、別のユーザの端末に届けられます。各メッセージは、発信元と宛先の情報を持っています。LINE Serverは、メッセージをユーザ間で配送する役割を担っているというわけです。

lbc_2

この配送の範囲が、LINE BusinessConnectの登場によって広がりました。今までは「ユーザの端末内にあるLINE Clientアプリ」と「LINE Server」という2つのアクターがいましたが、LINE BusinessConnectにより、各企業のサーバが新しいアクターとして追加されることになります。本エントリでは、そのサーバを仮に「BusinessConnectサーバ」と呼ぶことにしましょう。LINE Serverは新たに「BusinessConnect Serverへのメッセージ配送」と「BusinessConnect Serverからのメッセージ配送」という役割が増えました。

lbc_3

実際には、他社サービスとLINEとを繋ぐための「Channel Gateway」と呼んでいるサーバが、BusinessConnect Serverとのやり取りを担当します。
LINE PlatformとBusinessConnect Server間で送受信される情報は、大きく以下の2種類に分けることができます。

  • Message: テキストやスタンプ、位置などの送受信される情報そのもの。
  • Operation: 「友だち追加されたこと」などのイベント関連の情報。

もちろん上記の情報は、LINE ClientアプリとLINE Server間でも送受信されています。つまり、今までLINEの世界の中でのみ送受信されていた情報が、世の中にある様々なサービスにも配送されるということです。

基本的に、LINE ClientアプリとLINE Server間、LINE Server(+ Channel Gateway)とBusinessConnect Server間で送受信される情報の中身に差はありません。もちろんLINEと他社システム間の通信となるため、厳密にはそのために必要な情報が追加されていますが、本質的には同じです。BusinessConnect Serverを作ることになるエンジニアにとっては、LINEの中で行われていることを覗き見している感覚になるかもしれませんね。

LINE PlatformからBusinessConnect Serverへの配送

LINE BusinessConnectとして開設された公式アカウントに対してユーザが友だち追加やメッセージの送信を行った際に、LINE PlatformはそのことをBusinessConnect Serverに配送します。これは「LINE Developers」という開発者向けサイトにて予め登録されたEndpointに対して、JSON形式で書かれたMessageやOperationをChannel Gatewayから送信します。もっと端的にいうと、情報を持つJSON文字列をRequest bodyに持つリクエストをEndpoint URLに向けて送信する、ということです。

もちろん、配送されるメッセージを覗き見されてしまっては困りますので、HTTPSが必須になります。さらに、仮にEndpoint URLの存在が第三者に知られてしまうと、不正に偽のリクエストがその第三者から送信されて思わぬ事故が発生する可能性があります。偽のリクエストだと判断ができるように、Channel GatewayはBusinessConnect Serverに送信するリクエストに署名を持たせています。BusinessConnect Serverは、受け取ったリクエストの内容から自身で署名を計算し、送られてきた署名と一致するかどうか確認をすることで、偽のメッセージかどうかをチェックすることが可能です。

lbc_4

処理時間を短縮するために署名検証を省略したくなるかもしれませんが、実際に事故が起きたときの被害は、その公式アカウントが提供する機能の内容に応じて非常に大きなものになるでしょう。省略すべきではありません。

送信される情報は、先ほどJSON形式であることを述べました。送信されるMessageやOperationは、1回のリクエストで複数含まれる可能性があります。その個数は、配送量やLINE Platform全体の負荷に応じて増減します。具体的には、以下のようなJSON文字列になるでしょう。Channel GatewayからBusinessConnect Serverへの同時リクエスト送信数も、配信量や負荷に応じて変化します。

{
  "result": [
    {
      "from": "送信者のID",
      ...
      "content": {
        "text": "メッセージの本文",
        ...
      }
    },
    { Operation 1 },
    { Message 2 },
    ...
  ]
}

BusinessConnect Serverの責務は、「とにかく受け取った内容を受け取って迅速に200を返すこと」です。メッセージ送信を行ったユーザに対する返信を、このEndpointへのリクエスト送信のレスポンスとして行うことはできません。返信要求は、Channel Gatewayが提供するAPIを使って行います。そのAPIアクセスを、このリクエストを受け持つプロセスやスレッドの中で行った後に200を返すという実装をすべきではありません。非同期に処理を行うことが、スケールするBusinessConnect Serverの条件として必要です。

受け取った内容をどこに保持しておくか、Business Serverの実装に関してここが一つポイントになると思います。例えば、

  • memcachedやRedisといったメモリストレージを準備して一時的に保持する。
  • MySQLなどのRDBMSに書き込む。その際、大量のinsertが発生するため、例えばバルクインサートなどを使って処理速度をできるだけ向上させる。もっと速度を追求するなら、例えばHandlerSocketなどの採用も考える。
  • RDBMSに比べて書き込みコストが低い何らかのKey-Value storeを採用する。
  • RabbitMQなどのMessage queueに入れていく。

といったことを実装することになるでしょう。とにかく書き込み処理を軽くして、できるだけ早く200レスポンスを返す、という工夫が必要になります。

何らかのストレージに格納した情報に対して、別のプロセスやスレッドにて情報を取り出していき、それらに応じて適切な処理を行います。MQのConsumerとして登録しておいて、Pushされたタイミングで次々と処理をしていくこともできるでしょう。または、複数のDaemonプログラムがストレージから情報を取得して処理をし、その結果を書き込んでいく、という流れでも良いでしょう。

LINE Platformからのメッセージ配送を処理する部分の実装については、基本的には多くのSocial Gameのバックエンドサーバで採用されている負荷分散の戦略が適用可能だと思います。数年前であれば一部のWeb Portal siteを運用する企業のみが持っていたKnow-howが、今日では多くの開発企業に浸透しています。そのような開発経験を持っている開発者であれば、効率のよいBusinessConnect Serverを構築することが可能だと思います。

BusinessConnect ServerからLINE Platformへの配送

ユーザに対して何らかのメッセージを返信したい場合は、Channel Gatewayが提供するRESTful APIをBusinessConnect Serverからアクセスします。これは特殊なことはなく、本当に普通にRESTful APIを利用するのみです。もちろん第三者がAPIを利用できてしまってはいけないので、リクエストヘッダにクライアント認証に必要な情報をセットしておきます。具体的には、LINE Developersサイトから入手可能なAccess tokenを指定することになります。メッセージの内容は、例のごとくJSON文字列で指定します。

POST /api/... HTTP/1.1...Access token header...{...}

ここでポイントとなる点は、Access tokenは一定期間で失効する、ということです。最近では多くの開発者がOAuth2などの仕様を利用していますので、Access tokenが失効することについては免疫を持っていると思います。つまり、失効する前に自動的に新しいAccess tokenを再発行する処理を実装することが必要になります。一般的なOAuth2のようなユーザごとにAccess tokenが発行されるのとは違い、BusinessConnect Serverが一つのAccess tokenを持つことになるので、cronなどで定期的にRefreshする処理を行えば良いです。

コード例

「で、結局BusinessConnect Serverのコードはどうなるの?」ということですが、例えば以下のようになるでしょう。

class BusinessConnectServerController < ApplicationController
  def index
    # Check signature
    from = params['result'][0]['content']['from']
    msg = params['result'][0]['content']['text']
    BusinessConnectServerController.delay.send_msg(from, msg)
    head 200
  end
  def send_msg(from, msg)
    json = {to:[from], toChannel:…, eventType:…,
        content: {contentType: 1, toType: 1,
        text: "Echo: #{message}"}}
    header = {…} # Set access token header
    url = URI.parse('http://…/v1/events')
    Net::HTTP.start(url.host, url.port) do |http|
      body = json.to_json
      response = http.post(url.path, body, header)
    end
  end
end

これはRuby on RailsのControllerとして書いたBusinessConnect Serverのコード例です。ユーザが送信したテキストメッセージを受け取り、その送信者にメッセージをそのまま返す、いわゆるエコーサーバです。上記のBusinessConnectServerControllerのindexメソッド内で、受け取ったJSON文字列から一つ目のテキストメッセージの本文と送信者のIDを取り出し、BusinessConnectServerControllerのsend_msgメソッドを呼び出しています。その際、delayメソッドを挟んでいますが、これは「Delayed::Job」という非同期処理を行ってくれるライブラリによって、send_msgメソッド内の処理が別途動作しているプロセスによって非同期に実行するように指令を出しています(具体的には、delayメソッドはsend_msgメソッド内の処理を実行するための情報をDBに書き出す処理が行われます)。

つまり、返信処理を非同期化して、即座にHTTP Statusコード200をレスポンスとして返しているわけです。

(注: サンプルコードとして説明を簡略化するためにDelayed::Jobを使っただけであり、弊社がその利用を薦めているわけではありません)実際には、コメントで「Check signature」と書いている場所で、署名検証をする必要があります。

また、上記では受け取ったメッセージを一つのみ処理していますが、もちろん送られてきた情報全てについて処理を行う必要があります。

send_msgメソッドの中では、ユーザに返信したいメッセージを持つJSON文字列を作成し、APIにそれを渡す処理が行われています。その際、リクエストヘッダにAccess tokenをセットします。

ここで重要なことは、署名の検証処理が省略されていますが、実際にはBusinessConnect Serverで必要となるコード量はそう多くない、ということです。

もちろんこの後ろにある各企業のサービスと繋ぎこむための処理など、実装すべきコードはもっと大きくなるでしょう。しかし、メッセージの送受信というLINE BusinessConnect視点での本質的な処理に関しては、上記のようにシンプルなものになります。行うべきことがシンプルであればあるほど、スケールする可能性も高くなります。

あとは、どのような価値をユーザに提供するか、その点に集中すれば良いでしょう。

まとめ

本エントリでは、LINE BusinessConnectについて、特にメッセージの配送を中心に紹介してみました。ここで取り上げた内容が、LINE BusnessConnectの本質的な実装内容になります。実際にサービスインするためには、Messageだけでなく各Operationに対する処理、例えば友だち追加された際の自動応答メッセージ送信や、LINEのユーザアカウントと各企業のサービス側のアカウントとの紐付けなどの機能を追加していくことになると思います。本エントリの内容が、LINE BusinessConnectを理解する上で少しでも役に立てば幸いです。