Twilioで開発を始める前に知っておくこと（レスポンスタイム編）

:::note alert
2023年5月1日を持ちまして、株式会社KDDIウェブコミュニケーションズのTwilioリセール事業が終了したため、本記事に記載されている内容は正確ではないことを予めご了承ください。
:::

# はじめに

みなさん、こんにちは。
Twilioエバンジェリストの高橋です。

今回は、これからTwilioを使う方（使い始めている方にも）に知っておいてほしい、**TwiMLの置き場所**について説明します。
Twilioで開発するときの検討事項として、サーバーをどこに置けばレスポンスタイムが短くすむのか、コンテンツをどこに配置すればよいのかは重要な問題です。とくに、TwilioからのWebhook先（多くの場合、TwiMLの配置先）の選択によっては、処理速度が大きく異なることもありますので、ぜひ覚えておいてください。

# TwiMLについて

TwiMLとは、Twilioを操作するための独自の言語で、XML形式で書かれたテキストファイルです。言い換えれば、Twilioに処理を行わせるためには、みなさんがTwiMLを準備しておく必要があります。
たとえば、次のようなXMLがTwiMLです。

```xml
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Say language='ja-JP' voice='Polly.Mizuki'>こんにちは。私はみずき。この文章を読み上げるのに、追加料金として1円かかります。これからもよろしくお願いいたします。</Say>
</Response>
```

このTwiMLは非常に単純なもので、**「こんにちは。私はみずき。この文章を読み上げるのに、追加料金として1円かかります。これからもよろしくお願いいたします。」**という女性の声で音声合成をおこなうものです。

たとえば、下の画像のようにTwilioで購入した電話番号に設定しておいたWebhook先にTwilioからGETもしくはPOSTリクエストが発生し、上記のようなTwiMLを返すようにしておきます。
処理速度の観点でいうと、TwilioからのWebhookに対していかに早くTwiMLを返せるかが、その後の処理に影響を与えます。

![PhoneNumber_Configure.png](https://qiita-image-store.s3.amazonaws.com/0/86046/2d59f687-6cd5-6a97-c892-473a7b2729fe.png)


# TwiMLの置き場所

前述の通り、TwiMLを返すためには、TwilioからのGETもしくはPOSTリクエストが受け付けられる環境が必要です。
現在、よく利用されるTwiMLの置き場所はおおむね次のとおりです。

- お客様側が構築したWebサーバー
- AWS S3
- AWS Lambda + API Gateway
- Twilio Bins
- Twilio Functions
- Twilio Studio

## お客様側が構築したWebサーバー

この方法の最大のメリットは、完全に自社で管理が可能な環境でサーバーを構築できる点です。ただし、Twilioからはインターネット経由でアクセスが必要になりますので、外部に公開されている必要があります。
そのため、最低限でもHTTPSでアクセスができるようにしておきましょう。また、それ以外のセキュリティ対策については、[こちらの記事](https://jp.twilio.com/docs/usage/security)を参照してください。

## AWS S3

静的なTwiMLであれば、テキストファイルをそのままS3に保存して公開設定してしまう方法もあります。注意点としては、GETでしか取得できない点と、コンテンツが外部に公開されてしまうという点です。とくに後者はTwiMLがすべて見えてしまうことになりますので、あまり推奨はできないやり方です。
CloudFrontなどを組み合わせることでBASIC認証をかけたりすることもできそうですが、実際に試してないのでよくわかりません。

## AWS Lambda + API Gateway

S3が静的コンテンツしか返せないのに対し、動的にTwiMLを生成する場合はAWS Lambdaを利用するケースも多いです。Lambdaは費用が殆どかからないというメリットもありますし、様々な言語がサポートされていることもエンジニアにとっては魅力です。とはいえ、言語によっては起動時間が異なるため、PythonかNode.jsをおすすめします。
逆に欠点といえば、LambdaだけではTwilioからは呼び出しができないため、API Gatewayを連携させなくてはいけないので、設定が複雑になることです。とくに、API GatewayがJSONを返すことを基本としているのに対し、TwiMLはXMLで返さなくてはいけないので、このあたりのコンテンツ変換も面倒です。
セキュリティ的には、X-Twilio-Signatureの対応が可能ですので、ぜひ組み合わせてご利用ください。
[Twilioからのリクエストを検証して、Python Amazon Lambdaアプリケーションをより安全にしましょう。](https://jp.twilio.com/docs/usage/tutorials/secure-amazon-lambda-python-app-validating-incoming-twilio-requests)

## Twilio Bins

ここからは、Twilioの機能として提供されるTwiMLの返却方法になります。
まず静的なTwiMLだけを返すのであれば、もっともシンプルなのが**TwiML Bins**になります。これは、Twilioの管理コンソール上に直接TwiMLを指定することができるので非常に直感的です。また、現在TwiML Binsの利用料は無料です。

![スクリーンショット 2019-04-02 16.27.13.png](https://qiita-image-store.s3.amazonaws.com/0/86046/84b1ee4f-b5f6-894b-f97a-3b22edfeef3d.png)

TwiML Binsでは、設定したTwiML Binに対して個別のURLが割り当てられますが、このURLはTwilioの外からアクセスするためには認証が必要になっているため、前述のS3に比べると安全です。通常は必要ないかと思いますが、もし外部から呼び出すためには、[こちらの記事](https://support.twilio.com/hc/en-us/articles/223132187--Not-Authorized-error-when-trying-to-view-TwiML-Bin-URL)を参考にしてください。

## Twilio Functions

動的にTwiMLを生成したい場合に、比較的簡単で柔軟なコードがかけるのがTwilio Functionsです。
Twilio Functionsは、Twilioの管理コンソールを使ってAWS Lambdaと同じようなサーバーレスアーキテクチャによるプログラミング実行環境を提供します。利用料も月10,000件までのアクセスが無料ですし、10,001件からも0.015円/アクセスで利用できます。
Twilioが提供するNode.js用のSDKを利用することで、コードも簡潔に記述することができます。ただし、現在サポートされている言語はNode.jsのみであることと、デプロイの自動化ができない点が欠点となります。

![スクリーンショット 2019-04-02 17.12.56.png](https://qiita-image-store.s3.amazonaws.com/0/86046/e66f457e-ea2d-3818-5e07-37d14626a668.png)

Saveボタンを押すとデプロイが自動的に実行され、コードを実行するためのPATHが有効になります。このPATHをGETもしくはPOSTすることでコードが実行されます。ただし、画面上にある**Check for valid Twilio signature**をチェックすると、外部からはX-Twilio-Signatureの設定を行わないとアクセスできなくなります。よって、Twilio内部からのみアクセスするのであれば、このチェックをオンにしておくことでセキュアな運用が可能です。

## Twilio Studio

エンジニアでなくてもGUIでコールフローが作成できるTwilio Studioを使う方法もあります。
他の方法に比べると、開発の敷居が最も低く、直感的に作成ができるのが特長です。一方で、Functionsのようにコードを書かなくては実装できない機能などもあるので、商用ベースのサービスでは使い所を考える必要があります。

![スクリーンショット 2019-04-02 17.36.56.png](https://qiita-image-store.s3.amazonaws.com/0/86046/d37de978-5b9d-b50f-72ef-76cc7b5ff11e.png)

今回のような非常に簡単な音声合成をするだけであれば、もっとも簡単な方法がStudioを使う方法です。
なお、Twilio Studioの利用料は、月1,000アクセスまでが無料で、1,001回目からは0.15円/アクセスとなっています。Functionsよりも高いですが、それでも非常に安く利用できます。

# 速度比較

それぞれの方法でレスポンスタイム（ms）を計測したのが以下の表です。
これは、TwilioからのWebhookにおけるレスポンスタイムになります。TwilioのコアサービスはAWS上の複数のリージョンでホストされていますが、とくに障害が発生していない場合はバージニアリージョンからアクセスがくるようです。
テストで使ったLocalServerは、ローカルのMac上にPython（Flask）でサーバーを構築し、ngrokで公開しました。
LambdaはバージニアリージョンのPython3.7を利用しています（環境構築は結構ハマったので、そのうち別記事にします）。

|  | LocalServer | S3（東京） | S3（バージニア） | Lambda(バージニア） | TwiML Bins | Functions | Studio |
|:--|--:|--:|--:|--:|--:|--:|--:|
| 1回目 | 245 | 381 | 33 | 100 | 61 | 279 | 163 |
| 2回目 | 282 | 409 | 43 | 52 | 133 | 251 | 119 |
| 3回目 | 294 | 383 | 44 | 76 | 73 | 151 | 110 |
| 4回目 | 380 | 388 | 41 | 94 | 98 | 1320 | 134 |
| 5回目 | 246 | 389 | 36 | 192 | 223 | 371 | 110 |
| 6回目 | 254 | 396 | 48 | 157 | 69 | 285 | 105 |
| 7回目 | 244 | 358 | 69 | 66 | 73 | 152 | 97 |
| 8回目 | 322 | 385 | 67 | 96 | 95 | 167 | 107 |
| 9回目 | 240 | 350 | 39 | 120 | 64 | 143 | 123 |
| 10回目 | 247 | 378 | 36 | 200 | 56 | 121 | 100 |
| 平均 | 275.4 | 381.7 | 45.6 | 115.3 | 94.5 | 324 | 116.8 |

平均レスポンスタイムがもっとも短かったのが、AWS S3（バージニア）となります。まぁ順当な結果ですね。ただし、同じAWS S3でも東京リージョンはかなり遅いことがわかります。
あと、TwiML Binsが良い結果になるだろうとは予想できましたが、Twilio Studioの健闘ぶりにちょっとびっくりです。一方で、Twilio FunctionsがLambdaよりも遅いという結果が少し残念です。

### 追記 2019/4/3 Twilio Assets

Twilio Functionsと一緒に発表されたTwilio Assetsは、AWS S3のようなストレージサービスを提供します。裏側の詳しいしくみはわからないのですが、コンテンツのキャッシュもされるようなので、TwiMLを配信するには良いかもと思ってテストしました。

結果は以下のとおりです。

|  | Assets |
|:--|--:|
| 1回目 | 100 |
| 2回目 | 139 |
| 3回目 | 108 |
| 4回目 | 115 |
| 5回目 | 118 |
| 6回目 | 220 |
| 7回目 | 107 |
| 8回目 | 113 |
| 9回目 | 144 |
| 10回目 | 137 |
| 平均 | 130.1 |

Twilio Studioと同等か、少し遅いくらいですね。S3同様、コンテンツが外部に公開されてしまうことを考えると、Assetsもあまりおすすめはできません。

### 追記 2019/4/3 S3 + CloudFront

本記事を書いたところ、CDNを使った場合はどうなるのでしょうかというご質問をいただきましたので、早速AWS S3 + CloudFrontを使って計測をしてみました。参考までに、AWS S3はバージニアリージョンを使っています。
結果は以下のとおりです。

|  | S3 + CloudFront |
|:--|--:|
| 1回目 | 136 |
| 2回目 | 77 |
| 3回目 | 20 |
| 4回目 | 57 |
| 5回目 | 19 |
| 6回目 | 20 |
| 7回目 | 53 |
| 8回目 | 110 |
| 9回目 | 17 |
| 10回目 | 22 |
| 平均 | 53.1 |

平均値ではS3（バージニア）にはかなわないものの、やはりかなり高速です。CloudFrontのレポートを見る限り、キャッシュのHit率が41.67%でしたので、テスト結果のうち20ms前後での応答がキャッシュによる効果だと想像できます。今回はHit率のチューニングはしていないのですが、その辺りの知見がある方であれば、平均して相当早いレスポンスタイムを叩き出せそうです。

# まとめ

- Webhook先の選定次第で、応答時間に顕著な差が発生します。
- AWSを利用する場合は、可能であれば東京リージョンよりもバージニアを利用したほうが有利です。
- Twilio Studioでまかなえる処理はStudioを利用しましょう。
- 静的なコンテンツを返すのであればTwiML Binsがおすすめです。
- CDNを使うことで、20ms程度のレスポンスタイムで応答することができます。
- 複雑なコーディングを伴うものや、デプロイ環境も含めた運用を考えると、やはりLambdaを選択するのが良さそうです。

今回の検証は、あくまでレスポンスタイムを基準にした話ですので、実際の運用・構築での参考になれば程度で考えていただけると助かります。

---
### Twilio（トゥイリオ）とは

https://twilio.kddi-web.com
Twilioは音声通話、メッセージング（SMS/チャット）、ビデオなどの 様々なコミュニケーション手段をアプリケーションやビジネスへ容易に組み込むことのできるクラウドAPIサービスです。初期費用不要な従量課金制で、各種開発言語に対応しているため、多くのハッカソンイベントやスタートアップなどにも、ご利用いただいております。