sqliteデータベースで動作するWebアプリケーションがあります。私のバージョンのsqliteは、公式のWindowsバイナリディストリビューションからの最新のものです-3.7.13。
問題は、データベースに大きな負荷がかかると、sqlite API関数(sqlite3_stepなど)がSQLITE_BUSYを返すことです。
接続を初期化するときに、次のプラグマを渡します。
journal_mode = WAL
page_size = 4096
synchronous = FULL
foreign_keys = on
データベースは1ファイルのデータベースです。そして、データベースにアクセスするために、Mono2.10.8とそれに付属するMono.Data.Sqliteアセンブリを使用しています。
私は50の並列スレッドでテストしており、それぞれ50の後続のhttp要求をアプリケーションに送信しています。リクエストごとに、データベースに対して読み取りと書き込みが行われます。IO操作のすべてのセットは、トランザクション内で実行されます。
400番目から700番目のリクエストまですべてうまくいきます。この(ランダムな)瞬間に、API関数はSQLITE_BUSYを永続的に返し始めます(より正確には、再試行の制限に達するまで)。
私の知る限り、WALモードは並列読み取りと書き込みを透過的にサポートします。チェックポイント操作の実行中にデータベースを読み取ろうとしたことが原因である可能性があると推測しました。ただし、自動チェックポイントをオフにした後でも、状況は変わりません。
この状況で何が間違っている可能性がありますか?大量の並列データベースIOを正しく提供するにはどうすればよいですか?
PS
リクエストごとに1つの接続のみが想定されています。WebSessionContextで構成されたnhibernateを使用します。
NHibernateセッションを次のように初期化します。
ISession session = null;
//factory variable is session factory
if (CurrentSessionContext.HasBind(factory))
{
session = factory.GetCurrentSession();
if (session == null)
CurrentSessionContext.Unbind(factory);
}
if (session == null)
{
session = factory.OpenSession();
CurrentSessionContext.Bind(session);
}
return session;
そして、HttpApplication.EndRequestで、次のようにリリースします。
//factory variable is session factory
if (CurrentSessionContext.HasBind(factory))
{
try
{
CurrentSessionContext.Unbind(factory)
.Dispose();
}
catch (Exception ee)
{
Logr.Error("Error uninitializing session", ee);
}
}
私の知る限り、リクエストのライフサイクルごとに接続は1つだけである必要があります。要求を処理している間、コードは順番に実行されます(ASP.NET MVC3)。したがって、ここでは一致が可能ではないように見えます。この場合、接続は共有されていないと結論付けることはできますか?