問題
プロジェクトでは分散ロックが使用されており、分散ロックを追加する必要のあるビジネスインターフェイスが複数あることを考慮すると、分散ロックは処理のためにaopに配置され、周囲の通知によって実現されますが、使用されると、問題:
私が追加したアスペクトはこのようなものです
@Component
@Aspect
public class RedisLockAspect {
@Around("@annotation(com.test.RedisLock)")
public Object lockRedisLock(ProceedingJoinPoint pjp) throws Throwable {
1.获取自定义注解中指定的RedisKey,获取到指定的锁超时时间等参数
2.加锁
3.加锁失败的话,return
4.调用业务代码 pjp.proceed();
5.释放锁
}
}
これが疑似コードです。com.test.RedisLockは私がカスタマイズしたカスタムアノテーションです。ロックする前に、カスタムアノテーションで構成されたロック情報を取得しようとします。
この場合、どのインターフェイスをロックする必要がありますか。インターフェース上で、@ RedisLockアノテーションを追加するだけです。
問題は次のとおりです。
外部システムがorderCreate()インターフェイスを呼び出すと、ネットワーク上の理由により、インターフェイスの応答時間がタイムアウトしました。その結果、アップストリームのビジネスシステムがdubboを再試行し、作成インターフェイスを再度呼び出したため、問題。システムには、2つの同一の注文情報があります。
コードをチェックした後、インターフェイスのアップストリームビジネス注文番号に基づいて同一のチェックがあります。つまり、2番目の呼び出しが行われると、同一のチェックは次のようになります。効果的ではない、同一性が効果的でない、それはトランザクションがまだコミットされていないことが原因である可能性があります
私の考えでは、システムはこのようになっているはずですが、実際にログをチェックして問題を発見しました。コードが実行されると、最初にロックされずにトランザクションが開かれますが、逆に、
このモデルには問題。上:
- インターフェイスが初めて呼び出されたとき、タイムアウトしましたが、ビジネスコードはまだ実行されていました
- ダボ再試行メカニズムの直後に、2番目のインターフェイス呼び出しが開始されました。呼び出しが行われると、トランザクションが最初に開かれ、インターフェイスがロックしようとしました。問題はここにあります。2回目にロックしようとすると、最初の2番目の呼び出しが実行され、ロックが解除されましたが、トランザクションはまだコミットされていません
- 2回目のロック呼び出しが成功し、ビジネスコードが実行され、ビジネスコードでべき等判定が実行されます。この時点では最初のトランザクションが送信されていないため、データベースにアップストリームのビジネス注文番号情報がありません。 2回目はべき等チェックに合格し、注文作成などの他の業務に合格します。
- このとき、最初のインターフェース呼び出しがトランザクションを送信しました。2番目の呼び出しが実行された後、トランザクションも送信されました。
トランザクションとRedis分散ロックに対応するアスペクトの実行順序が乱れている理由は、1つのポイントが見落とされているためです。
アスペクト優先の
スプリングトランザクションの最下層もAOPを介して実装されるため、アスペクト優先の問題が発生します。ログ分析から、優先度が指定されていない場合、トランザクションのアスペクトの優先度が高く、分散ロックを処理するために定義したアスペクトの優先度が低くなります。問題がわかっている場合は、デバッグして検証するだけです。
図から、トランザクションが最初に実行され、トランザクションが開かれた後、ロックロジックが再度呼び出されることがわかります。
解決
2つの解決策があります:
1。Redis分散ロックを処理する面で、最高の優先度を指定します
2.トランザクションの範囲を縮小し、トランザクションの外部にべき等検証のロジックを配置し、注文が作成された後にその他の必須ではありませんビジネスロジックはトランザクションの外部に配置されます。
最初のソリューションでは、これを分散ロックの処理の側面に追加するだけで済みます。
@Order(Ordered.HIGHEST_PRECEDENCE)
aopがアスペクトを処理する場合、複数のアスペクトがある場合、優先度は注文のサイズに応じて決定されるため、値が小さいほど優先度が高くなります。
この注釈を追加すると、メモの2番目の画像のモデルになります
- 分散ロックを追加する
- トランザクションを開く
- ビジネスコードを実行する
- トランザクションをコミットする
- ロックを解除する
したがって、1つの文だけです。分散ロックアスペクトの優先度をトランザクションよりも高くします。