質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

Q&A

解決済

1回答

719閲覧

同ユーザーのリクエストが並行処理されることによるデータの不整合

Aqt

総合スコア27

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

0グッド

2クリップ

投稿2022/08/28 01:47

編集2022/08/28 02:16

前提

非同期の Web API を作成しています。同ユーザーが短期間に連続でアクセスした際、並行処理が行われ、データに不整合が発生します。

例えば以下のようなテーブルがあった場合、

iduser_idnumber
0A0
1A1
2A2
3B0
4B1

ユーザーAが新規レコードの追加をほぼ同時にリクエストしたとします。

  1. req1: レコード数のクエリ(count -> 3)
  2. req2: レコード数のクエリ(count -> 3)
  3. req1: レコード追加(number=3)
  4. req2: レコード追加(number=3)

このように並行処理され、結果は以下のようになります。

iduser_idnumber
0A0
1A1
2A2
3B0
4B1
5A3
6A3

質問

楽観的ロックを行えば解決すると思いますが、ネットの情報ではほぼ全て複数ユーザーによるリソースアクセスへの話であって、同じユーザーによる同時アクセスに対して楽観的ロックを行って良いものかと悩んでいます。

また楽観的ロックを行うとしても、同じユーザーによる連続リクエストは全てのエンドポイントにおいても気を付けなければならないため、対応として場当たり的だと感じてしまいます。(おそらく「データを読み込み、そのデータを処理して、書き込む」ような処理すべてに気を使わなければなりません。)

どのように解決するのが妥当なのでしょうか?

補足情報

Python のフレームワーク FastAPI で開発しています。データベースは PostgreSQL, ドライバは asyncpg, ORMは SQLAlchemy です。

Python: 3.9
FastAPI: 0.71.0
asyncpg: 0.25.0
SQLAlchemy: 1.4.29

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2022/08/28 02:00

> データベースも非同期です。 データベースエンジンは何を使っていますか?
Aqt

2022/08/28 02:11

PostgreSQLです。
maisumakun

2022/08/28 02:15

> 同じユーザーによる同時アクセスに対して楽観的ロックを行って良いものかと悩んでいます。 ロックを行った場合、どのような点が問題になると考えているのでしょうか?
Aqt

2022/08/28 02:24

大きな問題はないとは思いますが、ネットの情報では複数ユーザーに対して楽観的ロックの話をしていて、同じユーザーに対して楽観的ロックを行うのは正しい対応なのか不安です。 また、「データを読み込み、そのデータを処理して、書き込む」ような処理すべてに楽観的ロックが必要になるため、複数ユーザーのアクセスは想定していないのに、ほとんどのテーブルにversionカラムを追加しなければならないです。(ORMを利用しているので楽観的ロックの実装は必要ないのですが)
Aqt

2022/08/28 02:26

あくまで楽観的ロックは並行処理のためのもので、ユーザーが1人か複数人かはあまり関係ないのでしょうか?
TakaiY

2022/08/28 03:45

ロックする必要があるのは、DB上の同一データを同時に読み書きするのを防ぐためですので、ユーザーが1人か複数人かはまったく関係ありません。 今回のデータについても、ロックをすればいいと思いますし、楽観的/悲観的のどちらを使うのかについては、それぞれの利/不利を考えて採用すればいいでしょう。 また、トランザクションレベルで管理すれば「「データを読み込み、そのデータを処理して、書き込む」ような処理すべてに気を使わなければなりません」というのも緩和されるでしょう。
Aqt

2022/08/28 04:08 編集

コメント、ありがとうございます。非常に助かります。 > ロックする必要があるのは、DB上の同一データを同時に読み書きするのを防ぐためですので、ユーザーが1人か複数人かはまったく関係ありません。 なるほど、やはりロックはユーザーが複数なのかどうかは無関係の仕組みなんですね。多くの情報はあくまで分かりやすさのために複数人という状況を持ち出していただけでしたか。 > また、トランザクションレベルで管理すれば「「データを読み込み、そのデータを処理して、書き込む」ような処理すべてに気を使わなければなりません」というのも緩和されるでしょう。 ここに関して、トランザクションでは複数のリクエストの並行処理における整合性は担保されないように思うのですが、なにか方法があるということでしょうか?
TakaiY

2022/08/28 04:31

「トランザクションでは複数のリクエストの並行処理における整合性は担保されない」と思う理由がわかりませんが、トランザクションは複数の処理をまとめた1つの処理として扱う仕組みなので、ロック取得>トランザクション実行>ロック解放で処理できます。 パフォーマンスへの影響を少なくするために粒度を下げていくと細かく制御する必要があったりしますが。
Aqt

2022/08/28 04:53 編集

「トランザクションでは複数のリクエストの並行処理における整合性は担保されない」→ 少し言葉が抜けてたかもしれません。トランザクションを張るだけではという意味ですね。 つまりトランザクションは途中で失敗した場合、ロールバックして整合性を担保するものとして話しています。 もしかすると、TakaiYさんの言う「トランザクションレベルで管理する」というのはトランザクション単位で悲観的ロックをかければ良いという話でしたか?
TakaiY

2022/08/28 04:59

[トランザクション単位で悲観的ロックをかければ良いという話でしたか?] はい。▽そうです。
Aqt

2022/08/28 05:02

わかりました。ご丁寧にありがとうございました。勉強になりました
guest

回答1

0

ベストアンサー

結果は以下のようになります。

データベースレベルでuser_idnumberに複合UNIQUE制約をかければ、フロントエンドプログラムをどう実行しようが、このような重複データを入れようとした時点でエラーとなります。

投稿2022/08/28 02:17

maisumakun

総合スコア145183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Aqt

2022/08/28 02:30

なるほど。複数のユニーク制約をかけられる事を忘れていました。 ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問