Sansan Tech Blog

Sansanのものづくりを支えるメンバーの技術やデザイン、プロダクトマネジメントの情報を発信

顧客データHub開発の裏側(中編)

CTO藤倉です。今年3月、法人向けクラウド名刺管理サービス「Sansan」の新機能「顧客データHub」を発表しました。

これは、Sansanがこれまで蓄積してきた技術とノウハウを応用したテクノロジーで、独自の「名寄せエンジン」を用いて社内のあらゆる顧客データを統合できる機能です。

今回は、顧客データHubの開発を牽引したエンジニアである千田智己に話を聞きました。前中後編の3回に分けて紹介します。

中編では、彼の持つ技術や過去に担当したプロジェクトについて語ってもらいました。

入社直後に携わった戦略案件

藤倉:千田さんが最初に担当したのは、「Sansanスマートフォンプラン」のプロジェクトだったね。

千田:それまでのSansanとは違うビジネスモデル・販売モデルの構築を目指していました。このプロジェクトは仕様策定に難航して、ビジネスモデルが最終的に確定したのはリリース1か月前くらいでしたね。

藤倉:Sansanスマートフォンプランは戦略案件だったから、僕も案件の詳細まで細かく確認していた。設計についても、千田さんとよく一緒に議論したよね。

千田:ホワイトボードに書きながら、話しましたね。

藤倉:千田さんが「いまこういう案を考えているんだけど」と言って、ホワイトボードに設計案をバーっと書いてくれて、夜中まで2人でワーワーギャギャー言いながら仕様を詰めていた(笑)。当時から、(代表取締役の)寺田さんは千田さんの働きぶりをすごく評価していたと思う。

トランザクションログからのデータ復旧

藤倉:千田さんの仕事で特に印象に残っているのは、トランザクションログからデータ復旧をしたことかな。

千田:3年前の12月でしたね。

藤倉:バックアップデータから、特定のデータを復元する必要があったんだよね。でも、スナップショットからの復元では完璧な状態のデータに戻せなくて、用途に対して不十分だった。みんなが「どうしようか」と相談し合っていたところに、千田さんが「トランザクションログから戻せばいいじゃん」と言っていたのを覚えてる。

千田:完全な状態でデータをもとに戻すなら、絶対にその方法がいいと思ったんです。他のメンバーには内緒で、年末年始のうちにPostgreSQLのトランザクションログの仕様を調べて。

年が明けてから「こういう手段でトランザクションログからデータ復旧できそうですけど、どうですか?」とあらためて提案しました。

藤倉:トランザクションログはバイナリファイルだけど、PostgreSQLの公式ドキュメントやソースコードを読んで仕様を調べれば、どんなデータ構造になっているかバイナリからでも解析できるんだよね。「C言語のint型は何bitだから、バイナリファイルのこの位置からこの位置まではint型のデータを持っているはず」って感じに。

千田:そうなんです。ソースコードとトランザクションログを突きあわせながら、力技で内容を解析していきました。PostgreSQLは構造体を多用しているので、解析は一筋縄ではいかなかったですけどね(笑)。

藤倉:でも、それで結果的にちゃんとデータ復旧まで持っていくのが、千田さんらしいなあと思う。

f:id:sansantech:20190514163506j:plain

名刺検索のパフォーマンス改善

藤倉:千田さんが印象に残っているプロジェクトはある?

千田:Sansanの名刺検索のパフォーマンス改善ですかね。昔は、名刺検索のパフォーマンスが悪かったんですよね。社員数の多い企業を検索すると、結果が返るまで随分と時間がかかっていました。画面リニューアルのプロジェクトは別途立ち上がっていましたが、完了まで何か月もかかる。待っていられなかったので、検索処理のリファクタリングに自分1人で取り組みました。

藤倉:どんな処理に手を入れたの?

千田:まずはデータベースを非正規化しました。もともと名刺検索の処理では、検索時に複数のテーブルをJOINするようなSQLを投げていたんです。でもSansanはサービスの特性上とてもJOINの数が多いので、どうしてもクエリのパフォーマンスが悪くなってしまいます。

それを解消するために、検索用のJOIN済みテーブルを事前に作っておく設計にしました。実はこの施策で、先ほど話したトランザクションログ解析の経験が活きているんです。

藤倉:お、ここで役立つんだ。

千田:PostgreSQLでは、テーブルに格納される各データはアライメントされていて境界を跨がないようになっています。余ったデータ領域はどうなるかというと、パディングされて容量が調整されるんです。逆にいえば、アライメントを意識してデータを格納すれば、テーブルのデータサイズを最小化できます。

それから、Redisを使って検索結果をキャッシュする仕組みも改善しました。この処理では検索結果のキャッシュを作成・使用するためにシリアライズ・デシリアライズが走ります。名刺の量が数十万枚くらいになるとキャッシュサイズが数MBほどになるので、変換処理がかなり重くなっていたんです。

藤倉:どうやって改善したの?

千田:シリアライズ・デシリアライズそのものを不要にしたんです。構造体で作った最も効率のいいメモリレイアウトを、そのままRedisに転送する設計にしました。キャッシュを使う際には、Redisから取得した構造体の情報をそのままメモリ上に展開します。

藤倉:発想がすごいね。

千田:最終的には、大きなバグもなく狙い通りのパフォーマンス改善ができました。速度が3倍くらい速くなりましたね。

藤倉:ふり返ってみると、千田さんに担当してもらっているのは難易度の高いプロジェクトが多い。他のメンバーがさんざん議論して「これ無理だ。どうしよう」と言っていところに、千田さんが横から「こうやったらいけるじゃん。絶対できるでしょ」と話しかけている場面をよく見かけるよね(笑)。そして、確実に良いアウトプットを出してくる。

千田:あえて難しいプロジェクトに首を突っ込んでいますね(笑)。

藤倉:そういう仕事の方が燃えるんだよね。

千田:そうかもしれません。自分の仕事におけるスタンスは昔からずっと、「自分にしかできないことをやる」なんです。

前編後編

interview:中薗昴
photo:ブランドコミュニケーション部 高橋淳

© Sansan, Inc.