トラブルシューティングガイド
このページは英語版のページが機械翻訳されたものです。英語版との間に矛盾または不一致がある場合は、英語版を正としてください。
導入
本書では、システムの開発・運用・保守で困ったときの対処法について説明します。 ScalarDB と DL だけでなく、他のすべてのコンポーネントのトラブルシューティング方法についても説明します。 たとえば、上位コンポーネントから「間違った値で更新に失敗したため、ScalarDB または DL に更新を要求してください」というメッセージを含むエラーを受け取った場合、ScalarDL または DB にバグがあるように感じるかもしれませんが、それは単なる問題を意味している可能性があります。 無効なリクエストが送信されました。
最初のセクションでは、ScalarDB の例外とトランザクションの不明なトランザクション状態について説明します。 2 番目のセクションは、ScalarDL 例外に関するものです。 最後のセクションでは、不整合を調査する方法について説明します。
ScalarDB
ストレージの例外
接続例外
この例外は、アプリケーションが Cassandra などのストレージ システムに接続できない場合にスローされます。 この問題は、ストレージのステータスと構成、ScalarDB 構成を確認することで解決できます。 例えば以下のような場合にスローされます。
- Cassandra ノードでポート 9042 を開けない
- プロパティで scalar.database.contact_points のノード アドレスを指定できない
ExecutionException
この例外は非常に一般的です。 リクエストが失敗した場合にスローされます。 この例外の原因は多すぎて特定できません。 最初のケースでは、例外内のメッセージを読んでください。
この例外は必ずしも致命的なエラーを意味するわけではありません。 たとえば、ネットワークの遅延や負荷により、Cassandra でのリクエストが失敗する場合があります。 この場合、再試行するとリクエストが実行される可能性があります。 ストレージ ノードの負荷が高いためにこの障害が頻繁に発生する場合は、ノードのアップグレードを検討する必要があります。
InvalidUsageException
この例外は、対応するリクエストにエラーがあることを示します。 APIの使用状況に応じてリクエストを修正する必要があります。 たとえば、この例外は、get()
リクエストを使用して複数のレコードをリクエストしたときにスローされます。 この場合、scan()
を使用する必要がありました。
MultiPartitionException
これは、 batch
操作が使用される場合の InvalidUsageException
のサブクラスです。 この例外のメッセージにあるように、複数パーティションのバッチは推奨されません。 ストレージのスキーマを変更したり、レコードごとにリクエストを発行したりする必要がある場合があります。
NoMutationException
これは ExecutionException
のサブクラスです。 リクエストの対応するレコードがリクエストの条件を満たしていない場合にスローされます。 たとえば、これは PutIfNotExists()
条件でレコードを配置しようとしたときに、同じキーを持つレコードが存在する場合にスローされます。
ReadRepairableExecutionException
これも ExecutionException
のサブクラスです。 この例外で失敗したリクエストは、実際には成功している可能性があります。 これは、対応するレコードが挿入、更新されたかどうかがわからないことを意味します。 別の読み取りリクエストを発行して、レコードの現在の状態を確認することもできます。
RetriableExecutionException
これも ExecutionException
のサブクラスです。 これは、ストレージがレコードの書き込みに失敗したときにスローされますが、原因は一時的なものであり、致命的なものではありません。 再試行すると正常に実行される場合があります。 この例外が頻繁に発生する場合は、ストレージの負荷を確認すると役立つ場合があります。
StorageRuntimeException
この例外は、指定されたキースペースまたはテーブルが存在しない場合にスローされます。 キースペースまたはテーブルが実際に存在するかどうか、リクエストで正しい名前が指定されているかどうか、または StorageService
のインスタンスが存在するかどうかを確認してください。
UnsupportedTypeException
この例外は、サポートされていない型を使用した場合にスローされます。 サポートされているタイプ を参照してください。
トランザクションに関する例外
CommitConflictException
これは CommitException
のサブクラスです。 別のトランザクションが同じレコードの更新をコミットしようとしており、トランザクションが更新のコミットに失敗した場合にスローされます。 すべての更 新は中止されました。 同じ操作を持つ新しいトランザクションをリクエストすると、それらは正常に実行されます。
CommitException
この例外は、トランザクションが更新のコミットに失敗した場合にスローされます。 この失敗には多くの原因があります。 失敗したトランザクションによってレコードはコミットされないことに注意することが重要です。 多くの場合、トランザクションは再度リクエストされた場合に正常に実行されます。 この例外が頻繁に発生する場合は、ストレージの負荷を確認することをお勧めします。
CoordinatorException
基本的に、この例外は CommitException
によってラップされます。 これは、コーディネーターへの操作が失敗したときに内部的にスローされます。 コーディネーターに直接アクセスする場合は、この例外を処理する必要があります。
CrudException
この例外は基本的な例外です。 トランザクションがレコードの取得に失敗した場合にスローされます。 この失敗は、別のトランザクションがコミットしようとしたレコードの取得、またはストレージからの読み 取り失敗によって発生します。 失敗したトランザクションのすべての更新は中止されているため、新しいトランザクションで読み取りを再試行できます。
CrudRuntimeException
これは、トランザクションが同じトランザクション内で更新されたレコードを取得しようとするとスローされます。 データを更新してからそのデータを読み取ることは、同じトランザクション内では許可されません。
InvalidUsageException
この例外は、トランザクションの使用法が間違っている場合にスローされます。 たとえば、最初にレコードを読み取らずにレコードを削除するブラインド削除では、この例外が発生します。
RequiredValueMissingException
現時点では、この例外はトランザクションによってスローされません。 コーディネーターにアクセスして Coordinator.State
をインスタンス化する場合、この例外が発生する可能性があります。 コーディネーター テーブルには列がない可能性があります。 コーディネーターのスキーマを確認してください。
TransactionException
これは、トランザクションを処理する例外のスーパークラスです。 TransactionException
を拡張する例外は、必ずしも致命的な失敗を意味するわけではありません。 多くの場合、新しいトランザクションでリクエストを再試行すると、トランザクションが正常に実行される可能性があります。
TransactionRuntimeException
これは、 CrudRuntimeException
などの致命的な操作によって発生する例外のスーパークラスです。 この例外は、リクエストにバグがあることを意味します。
UncommittedRecordException
これは CrudException
のサブクラスです。 これは、トランザクションが別のトランザクションがコミットしようとするレコードを取得しようとするとスローされます。 他の多くの例外と同様に、新しいトランザクションで読み取りを再試行できます。
UnknownTransactionStatusException
これは、トランザクションがコミットに失敗したときにスローされる TransactionException
のサブクラスです。 トランザクションがコミットされたのか中止されたのかを知る方法はありません。 ただし、コーディネーターをチェックすることでその状態を確認できます。 この例外はめったにスローされませんが、かなり重要なので、この未知の状態とその確認方法については次のセクションで詳しく説明します。
不明なトランザクション状態
上で述べたように、 UnknownTransactionStatusException
は、トランザクションがコミットに失敗し、トランザクションの更新がコミットされたのか中止されたのかが不明な場合にスローされます。 この場合、コーディネーターを確認することで、トランザクションの更新がコミットされたかどうかを判断できます。
コーディネーターに保存されるトランザクション状態には 2 つの可能性があります。 それらはCOMMITTED
と ABORTED
です。 COMMITTED
状態は、他のトランザクションがそのトランザクションによるすべての更新を取得できることを意味します。 ABORTED
状態は、すべての更新がなくなったことを意味します。
UnknownTransactionStatusException
は、トランザクションが状態レコードをコ ーディネーターに挿入しようとしたが、処理中に例外が発生し、トランザクションが成功したかどうかを判断できなかった場合に発生します。 この場合、ストレージがレコードを挿入している場合もあれば、挿入していない場合もあります。 コーディネーターへのこの挿入は、ScalarDB の遅延回復プロセスによって最終的に完了します。 したがって、トランザクションがコミットしたかアボートしたかを示す状態は、次の方法で確認できます。
UnknownTransactionStatusException#getUnknownTransactionId()
により、この例外からトランザクション ID を取得します。- コーディネータからIDで指定された状態レコードを取得する
- 状態レコードがコーディネーターに存在しない場合は、トランザクションによって更新されたレコードを新しいトランザクションで読み取ってから再試行します。 この読み取りにより、内部で遅延リカバリが開始されます。
- 状態が
TransactionState.COMMITTED
の場合、トランザクションはコミットされています。 状態がTransactionState.ABORTED
の場合、トランザクションは中止されています。
コーディネーターをチェックするコード例は TransactionUtility#checkCoordinatorWithRetry()
です。
ScalarDL
例外
AssetbaseException
これは DatabaseException
のサブクラスであり、一部の例外のスーパークラスでもあります。 これは、コントラクトに put()
と scan()
の両方がある場合にスローされます。 ScalarDL では、scan()
は読み取り専用コントラクトのみに使用されます。
AssetbaseIOException
これは AssetbaseException
のサブクラスです。 これは、Ledger (ストレージ) からのアセットの読み取りが失敗した場合にスローされます。 これは、ScalarDB の CrudException
に似ています。 コントラクトの実行を再試行すると、正常に実行されます。 繰り返し失敗する場合は、ストレージまたは構成を確認する必要があります。
AssetCommitException
これは AssetbaseException
のサブクラスです。 CommitException のようにコントラクト(トランザクション)のコミットに失敗した場合にスローされます。 これはさまざまな状況によって引き起こされます。 コントラクトではアセットがまったく更新されていません。 コントラクトの実行を再試行できます。