VSCOにおけるgRPC
本日のゲスト投稿は、VSCOのRobert SayreとMelinda Luからです。
2011年に設立されたVSCOは、画像と言葉を通じて人々が作成、発見、つながることを支援する、表現のためのコミュニティです。VSCOは、スタックをgRPCに移行中です。
2015年、ユーザーの増加により、VSCOはいつもの問題に直面しました。会社の初期から存在していたモノリシックなPHPアプリケーションは、パフォーマンスの問題を示し、保守が困難になっていました。私たちは、node.js、Go、Javaでいくつかの小さなサービスを試しました。同時に、より大きなメッセージングサービス(メール、プッシュメッセージ、アプリ内通知用)がGoで構築されました。JSONから一歩踏み出し、このシステムのシリアライゼーションフォーマットとしてProtocol Buffersを選択しました。
現在、VSCOは新しいサービスに主にGoを使用しています。ただし、特定の課題に対して成熟したJVMソリューションが利用可能な場合などは例外です。また、VSCOはWebアプリケーションにnode.jsを使用しており、多くの場合、サーバーサイドのReactを使用しています。このような言語、サービスの混合と、後述する将来のデータパイプラインの作業を考慮すると、VSCOはプロセス間通信の最も実用的なソリューションとしてgRPCとProtocol Buffersを採用しました。JSON over HTTP/1.1 APIからgRPC over HTTP/2への段階的な移行が進んでおり、順調に進んでいます。ただし、PHP実装の成熟度が他の言語に比べて低いという問題はありました。
Protocol Buffersは、データエコシステムの構築において特に価値がありました。ここでは、言語に依存しない方法でデータスキーマを標準化し、安全な進化を可能にするためにProtocol Buffersを使用しています。一例として、MySQLとMongoDBのデータベースレプリケーションログからデータを取得し、バックエンドデータベースの変更をKafkaの不変イベントストリームに変換するGoサービスを構築しました。各行またはドキュメントの変更イベントはProtocol Buffersとしてエンコードされます。このデータベースイベントストリームにより、本番トラフィックに影響を与えることなく、他のシステムと調整することなく、必要に応じてリアルタイムのデータコンシューマーを追加できます。すべてのデータベースイベントをKafkaへの経路でProtocol Buffersにエンコードすることで、複数の言語から容易に消費および使用できる統一された形式でデータがエンコードされていることを保証できます。GitHubでMySQL-binary-logおよびMongo-oplogテイラーの実装を提供しています。
データパイプラインの他の部分では、iOSおよびAndroidクライアントからの行動イベントを、Goの取り込みサービスに配信するためにgRPCとProtocol Buffersを使用し始めています。この高ボリュームのユースケースをサポートするために、(1)パフォーマンスが高く、耐障害性があり、言語に依存しないRPCフレームワーク、(2)製品の進化に合わせてデータ互換性を確保する方法、(3)水平スケーラブルなインフラストラクチャが必要でした。gRPC、Protocol Buffers、およびKubernetesで実行されるGoサービスは、これら3つのすべてに適していることがわかりました。これはクライアント向けの最初のGo gRPCサービスだったため、いくつかの新しい摩擦点が発生しました。特に、ロードバランサーのサポートやcurlのようなデバッグ機能は、HTTP/2エコシステムの若さから遅れていました。しかし、gRPC IDLでサービスを定義する容易さ、インターセプターのような組み込みアーキテクチャの使用、Goによるスケーリングは、トレードオフに見合うものでした。
モバイルクライアントへのgRPC導入の第一歩として、iOSおよびAndroidアプリにテレメトリコードをリリースしました。gRPC 1.0以降、このプロセスは比較的簡単です。現時点ではサーバーにイベントを投稿するだけで、gRPCレスポンスをあまり使用していません。以前の実装はJSONベースでしたが、イベントの単一Protocol Buffers定義への移行により、クライアント間の微妙なバグや違いが数多く明らかになりました。
導入時にJSON実装との互換性を維持する必要があったこと、およびベンダーSDKとの統合が必要だったことが、わずかな障害となりました。iOSではキーバリューコーディングで対応できましたが、Androidではより困難になりました。最終的には、適切なパフォーマンスを維持しながら必要なリフレクション機能を取得するために、protobufコンパイラプラグインを作成する必要がありました。その経験を活かし、GitHubでBazelで構築された簡潔な例protocプラグインを提供しています。
Protocol Buffers形式で利用できるデータが増えるにつれて、この統一されたスキーマを基盤として、機械学習および分析システムを拡張する予定です。例えば、KafkaデータベースレプリケーションストリームをAmazon S3にApache Parquet(効率的な列指向ディスクストレージフォーマット)として書き込んでいます。ParquetはProtocol Buffersの低レベルサポートを備えているため、既存のデータ定義を使用して最適化されたテーブルを作成し、必要に応じて部分的な逆シリアライズを行うことができます。
S3からは、Apache Sparkを使用してデータに対して計算を実行しており、Protocol Buffers定義を使用して型を定義できます。また、TensorFlowで新しい機械学習アプリケーションを構築しています。TensorFlowはProtocol Buffersをネイティブで使用し、TensorFlow ServingでモデルをgRPCサービスとして提供できます。
これまでのところ、gRPCとProtocol Buffersは順調です。すべての統合の頭痛の種をなくすわけではありません。しかし、エンジニアが冗長なRPCコードの記述を回避し、より緩いシリアライゼーションフォーマットに伴う、終わりのないデータ品質の問題を回避できることが容易にわかります。