Architecture Example ②:WEB接客システム


本記事はMakuake Product Team Advent Calendar 2018の23日目の記事です。
今日は僕の誕生日です。誕生日の7時間をかけて書きました。笑
僕はこのタイプのシステムを人生で2度作るという経験をしました。(3度目の依頼がある) WEBシステムの中でも「大量のアクセスやシビアなシステム間連携からユーザーの属性や行動パターンを元に最適なコンテンツを判別し、出し分ける」というかなりADの配信サーバに似た設計思想になります。 ので、アドテクぽい設計の話は既存の社会資産 に譲るとして、このセクションはアドテクとWEB接客システムの最も違う点にフォーカスします。

CalculatedとProximate、Facedの同居

両者が最も異なる点は、WEB接客は
  • Calculated(大量のデータを元に算出し、サマライズした結果データ。よく混同されますが、BTAやシナリオ配信もこっちに含まれます)
  • Proximate(直近の行動データ)
  • Faced(今、何してる?)
が同居する点です。 最近はネイティブ・アドや動画ADなど、レコメンドの精度を重視するアドテクであればあるほど、訪問してからの感情反応データに着目する様になってきましたが、それを自社でやるというのがWEB接客ですから、Calculatedを来店(WEB訪問)時の前提として取得し、Proximateを観察しながら最終的なFacedに対して施策を出し分けていくというスタイルでのシナリオ設計をします。 この二つのデータは求められる性質が全く異なります。
  • Calculatedへの最重要要求:妥当性
  • Proximateへの最重要要求:正確性
  • Facedへの最重要要求:網羅性
Calculated、Facedへのアプローチはアドテクに習うところがたくさんあります。(というか、そのまま参考になる) が、Proximateへのアプローチは他に例がなく、苦労した点でした。 Proximateへ求められる正確性の例としては「来店者が男性であった場合、2回目の訪問で、初めに見たページがAで、次に見たページがBであった場合に指定したコンテンツを出したい」というものです。 構造は以下のようになっています。
3種類のデータを掛け合わせてActionをFeedbackする。
男性である点、2回目の訪問である点はKVSに保存されたCalculatedで判断できます。 次にページBについて、見たということを「記録する」のと「活用する」のタイミングが一緒に来ます。 なので、data aggregatorを介在して、保存されているProximateとたった今のFacedを統合しないと最終的なユーザーのステータスを判別できません。 Write / Readを使い分ける規模のアプリケーションを組んだことがある人ならばわかると思いますが、AuroraなどのクラウドデータベースはWriterへの書き込みからReaderからの読み取りまで、数ms~数十msのタイムラグがあります。 APIがそのタイムラグを待ってからレスポンスを返していたら、すぐにConnection数がいっぱいになってしまうので、そうならない様にFacedの概念が存在します。
Faced datastoreはbrowser上のcookie等を用います。session storeでも追いつかないからです。
さらに、Proximateが本当に正確かどうかを担保する必要があります。 ユーザーが次のページを見たときに、上記Queueで正確に書かれているかどうかを判別する必要がるのです。 これには二つの確認が必要です。
  • Databaseには既にページAを見たデータが書かれたか(Proximatedに含まれているか)
  • DatabaseにはなぜページAを見たデータが書かれていないか(Proximatedに含まれていない理由)
FacedはProximatedに正常に含まれるまでの揮発性データとしてハンドリングしなければなりません。 この時点で、ユーザーのブラウザはシステムの中のスケーラブル&アンコントローラブルな1アプリケーションとして考える必要があります。

Datastoreが発行するエラーの正確性

ここで着目したいのは、Datastoreが発行するエラーの正確性です。 Memcachedは非常にキャパシティの広いdatastoreですが、アーキテクチャの性質上「書きこめなかったことを正常にエラーで返せなくなる」ことがあります。これは、他のKVSでも同じ傾向が見られます。 対してRDBMSは、書きこめなかったことに対してのエラーバック率が、構造上ほぼ100%です。(落ちた場合も含めて)
2,000万inserts/s を5秒当てた場合のエラードロップ実験
Datastorereqsreceivedwaiterrors
Aurora100,000,00032,343,25563,221,4444,435,301
Memcached100,000,00078,834,12020,556,001609,771
Memcachedの方は数字が合いません。この分はerrorがドロップしているのです。 エラーはリトライすれば良いし、そのリトライが済むまでの間はFacedがProximatedの正確性を補完してくれます。 そのシステムは直前データの可用性担保目標を1,500msに設定していましたから、このデータエラーのドロップゼロは非常に心強く、どんなに書き込みレートが低くとも、そこに最終的に書かれているはず、を期待する先はAurora以外はありえせんでした。 上記は最もシンプルな例ですが、国内で作った方のシステムでは WEBフローティングウィンドウ上でのチャットも機能として実装していましたから、サードパーティのワンライナータグツールでありながら、かなりアプリケーショナブルなFrontendを提供しているサービスでした。

この記事はシリーズです。

一緒に「世界をつなぎ、アタラシイを創る」エンジニアを募集しております。ご興味持っていただけた方は、「各種エンジニア募集! クラウドファンディングMakuake」からご連絡ください。