LayerX エンジニアブログ

LayerX の エンジニアブログです。

AI-OCRを支える非同期処理アーキテクチャ

こんにちは!LayerXエンジニアの高際 @shun_tak です!

この記事では、LayerX インボイスの請求書AI-OCRを支える非同期処理の仕組みについて解説したいと思います。

いきなりサマリーですが、今回お伝えしたいのは以下の2点です。

  • 請求書は突然大量にアップロードされるので(大歓迎です!)、Amazon SQSとGoの machinery を活用して非同期処理しているよ!
  • AI-OCRの処理は重たいけど、AWS Lambdaを活用してシステム全体の負荷を分散し、スケーラビリティと可用性を確保し、コストも抑えることができたよ!

では早速ですが、前回のブログ LayerX インボイスにおける請求書AI-OCRの概要 の復習です。LayerX インボイスの請求書AI-OCRは、以下の図のように複数の処理によって構成されています。

AI-OCR処理フロー

図にするとあっさりしてますが、前処理も後処理も複数の処理で構成され、その中にはOCRの処理だけでなく、重たい画像処理等も含まれています。そのため、もちろん速度改善に努力してはいるものの、全部の処理が終了するまで請求書1件あたり数秒かかります。

このような重たい処理をアップロード処理と同期的におこなってしまうと様々な弊害が現れるため、処理の一部をメッセージキューとジョブワーカーを活用した非同期処理に分離しています。

ちなみにLayerX インボイス関連サービスにおいては、メッセージキューとしてAmazon SQSを、メッセージの送受信やジョブワーカーの管理にはGoの machinery というライブラリを利用しています。このあたりはまた別の記事で解説したいと思います。

アーキテクチャ概要

以下の図は、AI-OCRにまつわる処理を管理する様子を簡単に示したものです。

AI-OCRアーキテクチャ概要

この図には、APIサーバーとジョブワーカーの2種類のサーバーが存在します。これら2つのサーバーはともにSQSにメッセージを送信します。

一方で、メッセージを受信して処理するのはジョブワーカーだけです。APIサーバーはユーザーアクション起因で動きますが、ジョブワーカーはイベント駆動で動きます。

APIサーバーはストレージへの請求書アップロードが成功すると、メッセージをキューに送信し、一旦クライアントに成功レスポンスを返します。ジョブワーカーは受信できるメッセージがないかキューを監視しており、メッセージを受信すると該当のタスクを実行します。

最初のタスクには処理の最後に新たなメッセージをキューに送信するような実装をしておくことで、AI-OCRを構成する処理が次々と動くようになっています。最後のタスクはキューにメッセージを送信しないため、そこで一連の処理も終了します。

より詳しいAI-OCRの処理の様子を次節で紹介します。

AI-OCRの処理を支える具体的な構成

以下の図はAI-OCRの処理をさらに具体的に図示したものです。アイコンがたくさんあって複雑に見えるかもしれませんが、やってることは先程の概要図で示したものの繰り返しです。

AI-OCRアーキテクチャ詳細

1クライアントから大量の請求書が同時にアップロードされることは日常茶飯事で、ジョブワーカーは大量のタスクを管理しなければなりません。そのタスクの管理だけでも相当負荷が上がります。

一方で、請求書のアップロードタイミングやそのボリュームは分単位では予測不可能なため、ジョブワーカーに重たい処理を担わせるとオートスケーリングでも負荷分散が間に合わなくなります。

そのため、汎用OCRの実行やデータベースへの結果の保存など、ジョブワーカーでタスクが完結することもありますが、前処理、ラベル検出、一部の後処理はAWS Lambdaにオフロードしています。

データベースアクセスなしで動く重たい機能(特に画像処理)は、並列起動が可能で可用性が高く使った分だけ課金されるAWS Lambdaを利用することで、システム全体の負荷削減、スケーラビリティ向上、可用性の確保、コストの最適化を実現することができます。一石四鳥!

エンジニア募集中!

AI-OCRはうまく運用できてるように見えるかもしれないですが、まだまだ改善したいことがたくさんあります。

Go machinery じゃなくてAWS Step Functions使えばいいじゃんって思ったそこのあなた!ぜひ下記のリンクからご応募ください!面接やカジュアル面談にてディスカッションさせてください!

jobs.layerx.co.jp

 

 

最後までお読みいただきありがとうございました!