読者です 読者をやめる 読者になる 読者になる

Mercari Engineering Blog

メルカリのエンジニアブログです。技術情報を日々発信していきます。

メルカリのCRMツールをKaizenした話

こんにちは、こんばんは。

サーバーサイドエンジニア(社内ではAPIエンジニアとも呼称します)の@bravewoodと申します。一部の人からはウッディと呼ばれていて気に入っております。 キャリア初期にウノウラボに大変な憧れを抱いていた身としては、ウノウの流れをくむメルカリでこうしてBlogを書くことができ感動しきりです。

さて、本日はCRMツールについてお話しします。技術的な話は少なめで、CRM周りの開発やPlanningについてざっくりとお話しします。

APIエンジニアとは

まず、メルカリ社内においてAPIエンジニアとは、商品や取引などの各種データや機能を各クライアントから呼び出すための「API」を開発することを主としたエンジニアを指します。 クライアントにはiOSやAndroidのアプリとWeb、その他複数のサブシステムがあり、各担当のエンジニアと密に連携を取り、高速かつ安定したAPIを開発・維持することが役目です。 私はこれまで主に、プロモーションやUS向けの機能の開発、CRMツールの開発、Web版の開発などを担当してきました。

今日はそのうち、内製CRMツールについてPostします。

CRMとは

CRMとは、「Customer Relationship Management」の略で、お客様の満足度やロイヤリティを高め、売上や収益の向上を狙う手法のことです。^1

メルカリでは現在、内製・外製両方のCRMツールを使い、プロモーション(日本ではキャンペーンなどとも言います)に関するお知らせ、あるいはお客様に認知を図るための通知などを行っておりますが、その中でも特にメルカリが内製ツールにこだわる理由の1つとして、例えばポイントやアプリ内バナー、プライベートメッセージといったメルカリ独自機能を柔軟にカスタマイズすることにより、より目的に合った施策の実行が可能という点があげられます。

メルカリにおける通知

メルカリでは主に以下のような通知をユーザーに送ることができます。

f:id:bravewood:20160902134632p:plain

  • プッシュ通知
    • スマホのロック画面などにも表示されることから認知性は非常に高い一方、1度クリックすると消えるなど揮発性があります。
  • アプリ内通知
    • アプリアイコンや、アプリ内TOPメニューのバッジ数に連動させることができるため認知性は高く、また情報はメルカリのデータベースに保存しているため揮発性はありません。
  • プライベートメッセージ
    • バッジなどとは連動しないため認知性は低い一方で、文字数などに上限がなく長文を使う案内などに向いています。こちらもメルカリのデータベースに保存しているため揮発性はありません。
  • Eメール
    • ユーザーが利用するメールアドレスに送信するため認知性は高く、HTMLも使うことができるため自由なデザインを行うことができます。

内製CRMツール

現在内製CRMツールでできることの一部を紹介します。

  • プッシュ通知の配信
  • プライベートメッセージの送信(アプリ内通知を連動させて送り、認知性の低さを補っています)
  • Eメールの送信
  • ポイントの付与
  • 文言のABテスト
  • バナーの自動生成
  • 配信状況ダッシュボード(Mackerel APIからデータを取得し簡易表示)

また、特徴としては、 エンジニア以外(特にプロデューサーと言われる企画職の人)でも使えるよう操作画面をWeb UIで実装しています。 また送信関連の機能はUIと疎結合にするためにAPIとして実装しており、これらはPHPのコードで記述することで柔軟かつ高速に開発できるのが特徴です。 この仕組みは、Q4M使ったメッセージキュー、APIエンジニアの@travailが作っているphp-Parallel-PreforkというPHPによるpreforkサーバエンジンを使って実現しています。

CRMツールのカイゼン

CRMツールを使った通知は、主に全ユーザーに向けた大量配信となることが特徴です。 メルカリでは現在JP・USに会員・非会員合わせて数千万単位のユーザーを抱えているため、これらの規模で配信するために行った工夫をいくつか時系列に沿ってご紹介します。

バージョン1: バッチ

バッチ手動実行 + CSV

送信対象をCSVで管理し、これをAPIのリポジトリにコミット、本番サーバーにて手動でバッチを実行します。 送信時にはエンジニアがsshでバッチサーバーにログインし、手動で実行していました。

これには以下のような課題がありました。

  • APIリポジトリに対象ユーザーの一覧をcommitせねばならずレビューやリリースなどの手間がかかる
  • 土日やUS時間に合わせるために深夜などにエンジニアリソースを確保しなければならない
  • プロデューサーなど非エンジニアが気軽に実行できない(対象者が少ない通知や実験的な通知にも手間がかかっていた)

バージョン2: Web UI

かつてはエンジニアが手動で実行していましたが、Web UI化により非エンジニアでも処理を実行することが可能になりました。また、土日や深夜などにエンジニアリソースを確保する必要も無くなりました。

しかし新たに以下のような課題が生じました。

  • ユーザー数の増加により、送信処理の実行時間が数時間にも及ぶようになった
  • 狙った時間にプッシュ通知が着信できない
  • 長時間サーバーやSREチームのリソースを使ってしてしまう

バージョン3: プッシュ通知の高速化

メルカリではプッシュ通知配信のミドルウェアに、SREチームの@cubicdaiyaが開発しているGaurunを使っております。 Gaurun単体ではこの時点で超高速に配信することが可能でしたが、 バージョン2までの配信では1ユーザーに対して1 WorkerでGaurunにHTTPでリクエストを送っていることがボトルネックとなっていました。 そこでGaurunには10件単位でプッシュ通知を配信する、1 Workerで複数のユーザーに通知を行うという処理に変えたところこれまで数時間かかっていたプッシュ通知が数十分で配信できるまでに改善することができました。

この時に私のチームのプロデューサーが言っていたセリフを思い出します。

「全米にボタン1つで手軽にプッシュ通知の配信ができるようになってハッピー!」

大人のスタートアップを標榜するメルカリでは、お客様はもちろん従業員もハッピーでなければならないと私は思うのです。

さらなるKaizen

私の所属するチームは、8月にUS出張を行っており、この際にUSのCRマネージャーとCRMツール周りの企画を行いました。 その後フィードバックを受けて、以下の改善を行いました。

ユーザーの時間帯にあった通知

プッシュ通知は明らかにユーザーの行動を促すという意味で効果のある施策ですが(各種数字をモニターしており、プッシュ通知の配信後、明らかにグラフに変化が起きます)、一方でユーザー視点で言えば、配信されるのに適切な時間があるはずです。 また、一気に大量のプッシュ通知を配信することでユーザーのスパイクが起こりサービスへの負荷となる可能性もあります。 そのための施策として、プッシュ通知の配信時間をユーザー毎ににあった時間帯に変更するという実装を行いました。

配信処理の自動実行

Web UI化されたとはいえ、必ず誰かが実行ボタンを押さなければなりませんでした。 私のチームはUS向けの開発を行っておりますので、時差が問題になっていました (JST -> PDTで 16時間あります)。 そこで、指定の時間に自動で実行される機能を追加しました。

専用Queueの利用

メルカリでは現在CRM以外にも各種Queue/Workerを利用して様々な処理を行っております。 Q4MにおいてJobはFIFOで処理されます。 何も考えずにあらゆるJobが同様のQueueを使うと、重たい処理がQueueを占有してしまい、他のJobが長い間実行されません。 そこでCRM専用のQueue/Workerを作り、CRMの処理が他のJobに邪魔されないようにしました。 また、SRE視点でいうと、Queue/Workerを分けることにより、モニタリングやチューニングを個別に行えるというメリットもあり非常に有益です。

さいごに

このように、われわれのようなスタートアップ企業では、本体サービス・アプリ以外でも、CRMなどの周辺ツールにおいても事業の成長に合わせて様々な改善や機能追加を常に行っています。 このような機能開発にも積極的に加わっていただける仲間を募集しております!

Join Mercari!

WEB+DB PRESS Vol.94にてメルカリSREチームによる連載第3回が掲載されました

SREチームの@siroken3です。WEB+DB PRESSの連載第3回が 本日発売の Vol.94に掲載されました。

gihyo.jp

前回に引き続き @siroken3 が執筆いたしました。

今回はデータベースのバックアップと題して、メルカリの運用をベースにしてMySQLのバックアップについて執筆しました。バックアップの考え方から始まり、採用しているツールについて動作の仕組みも併せて詳細に解説させていただきました。またメルカリでのバックアップ事例に関しても紹介しています。

特にMySQLを使った大量のデータを扱うサービスにおいて、如何にシステムを稼働させつつ、データの整合性を担保してバックアップを実施するかについて力を入れて解説したつもりです。連載第3回もぜひご覧いただければ幸いです。

f:id:siroken3:20160823143608j:plain

nginxによるTCPロードバランサー

SREチームの@cubicdaiyaです。今回はnginxによるTCPレイヤーでのロードバランスについて解説します。

ロードバランサーとしてのnginx

nginxはHTTPやTCP、UDP等の複数のレイヤーでロードバランサーとして稼働させることができます。(TCPロードバランサーは1.9.0以降、UDPロードバランサーは1.9.13以降で利用可能です)

また、ngx_http_ssl_modulengx_stream_ssl_module を利用することでそれぞれのレイヤーでTLSを有効化することも可能です。

TCPロードバランサー用のモジュールを有効にする

HTTPレイヤーでロードバランスするためのモジュールはデフォルトで組み込まれますが、TCP(とUDP)レイヤーでロードバランスするにはnginxのconfigureスクリプトに--with-stream(あるいは --with-stream=dynamic)を付与してビルドする必要があります。

cd nginx-1.11.3
./configure --with-stream
make
sudo make install

以下はTCPロードバランサー向けに明示的に組込む必要があるモジュールの一覧です。

$ ./configure --help | grep with-stream         
  --with-stream                      enable TCP/UDP proxy module
  --with-stream=dynamic              enable dynamic TCP/UDP proxy module
  --with-stream_ssl_module           enable ngx_stream_ssl_module
  --with-stream_geoip_module         enable ngx_stream_geoip_module
  --with-stream_geoip_module=dynamic enable dynamic ngx_stream_geoip_module

nginxの標準モジュールで明示的に組み込む必要があるモジュールについてはこのように --with- で始まるオプションが用意されています。一方デフォルトで組み込まれるモジュールについては --without- で始まるオプションが用意されており、特定のモジュールを無効する際に指定します。

# ngx_stream_geo_moduleとngx_stream_map_moduleを無効にする
./configure \
  --with-stream \
  --without-stream_geo_module \
  --without-stream_map_module
続きを読む

DockerとMakeを利用したRPMパッケージのビルド環境

f:id:cubicdaiya:20160812131620p:plain

SREチームの@cubicdaiyaです。今回はDockerとMakeを利用したメルカリの自作RPMパッケージのビルド環境について紹介します。

メルカリの自作RPMパッケージ事情とVagrant、そしてDocker

メルカリの開発およびプロダクション環境では現在CentOS6と7を利用しており、随時CentOS7へ移行中です。そのため、自作RPMパッケージをビルドする際はCentOS6と7向けにそれぞれビルドしています。ビルドしたパッケージはyumリポジトリサーバにアップロードした後、必要に応じてyumでインストール、Ansibleのplaybook化を行います。

RPMパッケージの作成はSREチームのメンバーが行っており、各自のローカルマシン上において make {パッケージ名} を実行するだけでCentOS6と7向けのRPMパッケージをビルドできる環境をDockerで構築しています。

make nginx       # nginxのRPMパッケージをビルド
make nginx-build # nginx-buildのRPMパッケージをビルド
make gaurun      # gaurunのRPMパッケージをビルド
make slackboard  # slackboardのRPMパッケージをビルド
make cachectl    # cachectlのRPMパッケージをビルド
(etc)

これの良いところはMac上でもCentOS向けにRPMパッケージを作成できる点です。当初はVagrantを利用していましたが、最近Dockerを利用するように変更しました。Vagrant上でビルドするのと比べるとパフォーマンスが良く、特にコンテナの起動や破棄が高速なのが大きなメリットです。また、Cプログラムのコンパイルが以前よりも早く終わるようになりました。(もっとも最近はGoプログラムのRPMパッケージが多いのですが)

続きを読む

PHPカンファレンス関西2016で基調講演してきました

サーバーサイドエンジニアの@Hirakuです。 2016年7月16日(土)、 PHPカンファレンス関西2016 にて基調講演をしてきましたので、その報告と補足をします。

トーク動画は後日公開されると聞いていますので、口頭で補足した内容などはそちらをご期待ください。

内容について

講演内容は今年2月に公開した記事 光遅い問題を克服してcomposerを10倍速くした話 - Mercari Engineering Blog をもう少し詳しく解説したものです。

基調講演ということだったので、Composer自体の細かい話をするよりも、なぜこんなことに時間を費やしてきたのか、自分より若いエンジニアに何か伝えるものがないか、というようなことを考えて、エモ全開の内容になりました。

改善活動だけを話すとComposerを貶す内容になってしまいます。詳しい事情も知らない人にDISの口実を与えるのも嫌だったので、そこはComposerは偉業なのだ、という内容も含めてバランスを取っています。

Composerプラグイン開発のノウハウやComposerのあまり知られていない機能、Packagistのミラーリングのノウハウなど、他にも話せることはあるのですが、それはまた別の機会にできればと思います。

時間も長かったので、伏線を作ってみたりとか、工夫する余地があって楽しかったです。

自分の原点

基調講演というのは、参加者全員がそれを聞いて、盛り上げてウオオオオってするものだと伝え聞きました。なので講演のお誘いを頂いたとき既に、話すことは自分の原点しかないと決まっていました。

私がプログラミングで何かを作ったのは、社会人になってからです。特別な教育を受けたわけでもなく、素早くコードを書くことも苦手で、才能はないんじゃないか、この先プログラマーとしてやっていけるのだろうか、という風にずっと自信が持てませんでした。

そんな時、書籍の「プログラミングPerl」のはじめにの一節を読んで、衝撃を受けました。ちょっと引用します。

最も大切なのは、すべてを学び終えないうちに、役に立つプログラムが書けるという点である。あなたは、Perlを「端っこ」から少しずつ学び始めることができる。あなたは赤ちゃん言葉でPerlのプログラムを書くことができる ―― 私たちはそれを笑ったりしないと約束しよう。 (中略) われわれは、言語公安警察にあなたを尾行させたりはしない。上司からクビにされないうちに仕事を片付けられれば、それは「正しい」Perlスクリプトなのだ。

それまでずっと、周りと自分を比較してウジウジしていた私は、プログラミング言語を作るようなスーパーエンジニアが、拙いコードを書いてもいいと言っていることに非常に感動しました。それこそ「君はヒーローになれる」と言われたような気がしたのです。「自分でも何かできるかもしれない」と思えて、ゆっくりだけどコードが書けるようになったのは、たぶんそれからです。

でも、クソコードしか書けない人がクソコードを書こうと言ったところで何も説得力がないし、勉強しろと叱られるだけです。 だからいつか誰もが認めるような成果を出して、「クソコードでいいのだ」と断言してやるのが私の夢でした。

基調講演で言いたい放題言えて、ちょっと夢が叶ったな、と思いました。コードの話にしてしまうとコードを書かずに解決する場合のことが抜け落ちてしまうので、「問題と向き合うこと」という風に言い換えました。

「問題と向き合っていて孤独に感じないのか?」

そうそう、会場からのこの質問に、若干うまく答えられなかった気がするので、補足しておきます。

問題がすぐ自分で解決できればいいんですが、自分ではどうしようもなく、他にだれも解決しようとしていない場合は孤独でつらいものです。そもそも、答えのない問題も多くあります。

なので、そういうときは仲間を探すといいです。勉強会やカンファレンスに出たり主催したりしてもよいでしょう。インターネットで同じ問題に苦しんでいる人がいないか探し、日本語圏で見つからなければ英語や他の言語でも探してみましょう。会社に話の通じる人がいなければ、いっそのこと転職に踏み切るのもいいかもしれません。

同じ問題で苦しんでいて、解決できなくても「これをなんとかしたい」とあきらめない声を聞くと、勇気が湧いてくるものです。一番良くないのは、感覚が麻痺して問題を問題だと認識できなくなったり、どうせ解けないと問題に慣れてしまうことだと思います。

残念ながら、カンファレンスでありがたい話を聞いても、何か技術書を読んでも、自分が抱えている問題が突然に解消されることはありません。納期の迫っている開発、なぜかたまに起こるエラー、もう辞めてしまった人の残した負債、DBに残された使われていないテーブル。たぶん、世の中にいっぱい問題はあるのでしょう。

問題の大きさにかかわらず、そこに居合わせた人が何かしないと解決しないはずです。別に自分自身で解決しなくても、助けを求める声を上げるだけでも何かのきっかけになるかもしれません。「これは問題だ」と断言するのは誰にでもできますが、英雄的な尊い行為です。

きっと、みんなが少しずつ自分の抱えている問題に向き合っていれば、世の中少しずつよくなるのだと思います。