患者向け薬局検索機能のパフォーマンスを OpenSearch 導入により改善した話
こんにちは。かかりつけ薬局支援システム「Pharms」の開発を担当している熊本です。先日、総合医療アプリ「CLINICS」の薬局検索機能のパフォーマンスを OpenSearch の導入により改善しましたので、その経緯と結果について話していきたいと思います。
医療プラットフォームのプロダクト紹介と構成
まずは私が所属する医療プラットフォーム(以下、医療 PF)のプロダクトをご紹介します。オンライン診療をはじめ様々な医療体験を提供する患者・生活者向けのプロダクトと、医療機関における業務効率と患者体験の向上を支援する事業者向けのプロダクトがあります。プロダクト間のデータ連携に関しては、患者統合基盤というプロダクトによって実現しています。
患者情報やその医療情報に関するデータに関しては患者統合基盤で保持していますが、薬局店舗のリストや営業時間など調剤薬局店舗に関するデータに関しては Pharms 側で保持しています。本記事では、この調剤薬局店舗に関するデータを扱う Pharms の API についてお話しします。
CLINICS の薬局検索機能
CLINICS にはお薬手帳や、お薬辞典、薬局検索など薬局に関する機能がいくつか存在します。 本記事ではその内の薬局検索機能についてお話しするため、簡単にご紹介します。
薬局名で検索できるのはもちろんのこと、マップの範囲検索や市区町村、受付日時などで絞り込むことでご自身の都合にあった薬局を探すことが可能です。 病院等で処方箋を受け取った後に、この薬局検索機能を使ってお薬を受け取りたい薬局を探し、その薬局に対して CLINICS から事前に処方箋を送信しておくことができます。待ち時間なくお薬を受け取ることができるので個人的にも愛用しています!
他にも検索条件はいくつかあるのですが、オンラインで服薬指導を受けた際には Uber Eats により当日中にお薬を配達してくれる機能もあるので、当日配達に対応しているかどうかで絞り込むことも可能です。
この検索機能のバックエンドを Pharms の API が担っており、内部的には検索エンジンを使わず RDB による絞り込みで実現していました。
潜在課題の表層化
先ほどご紹介したように薬局検索機能はとても便利なのですが、 Pharms の事業成長に伴い以下のような課題も徐々に出てきました。
- データ量と検索トラフィックが増加してきた
- データ量の増加に伴い検索時のレスポンスが遅くなり患者のユーザビリティが悪化してきた
- 検索条件の増加に伴い SQL クエリが複雑になり、変更難易度が上がり開発・運用の工数が肥大化してきた
潜在的な課題を認識しつつも何とか開発・運用を続けてきたのですが、複雑な組み合わせの検索をクローラーなどにより集中的に実行された場合、処理コストの高い SQL クエリが大量に発行されてしまいレイテンシ悪化が起きるようになってしまいました。
患者側のメトリクスは患者統合基盤チームでもモニタリングしていることもあり、患者統合基盤チームと連携してレイテンシ悪化の原因調査や対応策の検討に取り組み、迅速に一次対応を打つことができました。異なる開発チームでも必要に応じて連携しながら課題解決に取り組めるところは弊社の特徴かなと改めて感じました。
しかし、サーバの強化や SQL クエリの改善で対処していたものの、あくまで暫定的な対応であり、対応工数・インフラコストなども鑑みると恒久対応の優先度が上がってきました。
課題の対応に向けて
上述の課題の他に、開発プロセスの改善や品質向上に向けた取り組みなど、今後の機能開発を見据えて、一度足元の強化が必要という議論が Pharms 開発チームであったため、薬局検索機能のパフォーマンス改善に限らず「開発基盤改善」としてプロジェクトを発足し、集中的にチーム課題に向き合うことになりました。
ここに関しては、プロダクトマネージャーと技術課題に関する目線合わせがスムーズにできたことも、プロジェクトが早いタイミングで発足した一因であると思います。 Pharms の開発チームにおいてはプロダクトマネージャーが事業部出身であるため、開発計画を練る際には プロダクトマネージャー/テックリード がそれぞれ 攻め(KPI の達成を担うもの)/守り(事故リスクを減らすもの) の観点でやりたいことを列挙しフラットに議論する体制をとっています。普段から守りの観点も重視されている上で、既にユーザビリティに悪影響を及ぼしていることや、その影響範囲・対応工数など諸々を鑑みて意思決定が行われました。
対応
パフォーマンス問題への対応は2つの観点で行うこととし、現状課題の根本解決に向けて OpenSearch の導入を、再発防止と継続的な改善に向けてモニタリングの強化を行うことにしました。
OpenSearch の導入
設計・実装
OpenSearch を導入することになるのですが、他いくつかのプロダクトで導入実績があったことや、現状の技術構成に対する親和性、個人的にも過去に別プロダクトで導入経験があったことなどを踏まえて導入自体は非常に早い段階で決定しました。
まずは設計にも関わってくるのでどれくらいのレスポンスを目標とするか等の受け入れ要件を定め、その後 index の設計に移りました。 基本的には既存の検索条件に合わせたシンプルな設計になったのですが、予約枠の表現に関しては頭を悩まされました。 というのも、「準備でき次第」のような検索条件に関しては、営業時間内かどうかに加え、その枠が予約で埋まっていないかどうかも見る必要があり、その表現やリアルタイム性を加味して設計を行いました。
index の設計が終わった後は粛々と既存の検索ロジックを OpenSearch のクエリに置き換え、検索に関連するテーブルが更新される箇所に OpenSearch のドキュメントを更新する処理を追加していきました。
検証
実装後はデグレチェックと負荷耐久性の観点で検証を行いました。 医療 PF 内の QA エンジニアと連携し、各検索条件の組み合わせにおいて期待通りの結果が返却されるかどうかを検証しました。パターンが多かったのでテストケースの作成から実施まで協力してもらい助かりました。おかげさまで私としては Pharms の店舗画面や CLINICS を操作した際に正しく OpenSearch のドキュメントが更新されるかどうかの確認であったり、後述する負荷試験に集中的に取り組むことができました。
負荷試験は、検証環境に本番相当のデータ量を用意した上で、過去に最もレイテンシが悪化した際のリクエスト頻度を少し上回る頻度でリクエストを一定時間かけ続け、AWSのトラブルシューティングなどを参考にして基準を十分にクリアできるかどうかの観点で行いました。
リリース
諸々の検証をクリアしてリリースを迎えるのですが、ここでも少しだけ工夫した点をご紹介します。 一点目は Feature Flag を利用していつでも以前のロジック(OpenSearch を使わない検索)に戻せるようにしていた点です。念入りに検証したものの Pharms としては初めての OpenSearch 導入だったので、不測の自体が起きた場合でもデプロイなしにいつでも切り戻せるようにしていました。
二点目は index のエイリアス設定です。マッピングの変更などに伴い index の再構築を行う際にダウンタイムが発生しないようにエイリアスの設定をしていました。一般的なベストプラクティスだとは思いますが、ここに限らず過去の知見を活かしながら開発進行できたのは良かったかなと思います。
モニタリング強化
これまで OpenSearch 導入の話をしてきましたが、今後も継続してパフォーマンス劣化をより精度高く、迅速に検知できるようにするためにモニタリングも強化しました。
インフラ側は主に CloudWatch を使い、アプリケーション側は主に Datadog を使ってアラート設定を追加しました。 これまでも主要メトリクスに関しては設定していたのですが、今回調査・対応した知見を活かして、より詳細かつ網羅的に整備しました。 また、アラートが上がる前に気づけるようにするための取り組みとして、隔週で各メトリクスのトレンド監視をする会を設けており、CPU使用率などが徐々に悪化していないかを見るようにしています。
結果
結果として、薬局検索機能のパフォーマンスに関してはレイテンシが約90%も改善しました。
パフォーマンスを大幅に改善しユーザビリティを向上させられただけでなく、これまで CloudWatch Logs に流れていた巨大な SQL クエリのログを削減することができたので AWS のコスト改善にも繋がりました。 また、メトリクスのトレンド監視によりアラートが上がるその手前で怪しい動きを見つけることができ、実際に早期対応することができています。
まとめ
今回は CLINICS における薬局検索機能のパフォーマンス改善について、プロジェクト発足の背景からクロージングに至るまでの過程をご紹介しました。
Pharms 開発チームは少数体制なのですが、今回のように QA チームや患者統合基盤チームなど周りを柔軟に巻き込んだ動き方ができて非常に面白いです。また、プロダクトマネージャーなど非エンジニアの方とも建設的にそれぞれの観点で対等に議論ができる点も弊社の大きな特徴です。
メドレーは絶賛エンジニア募集中ですので、弊社の取り組みに興味を持っていただいた方やもっと話を聞いてみたいと思った方は是非ご連絡ください!最後まで読んでいただき、ありがとうございました。