Tôi có một ứng dụng sản xuất (IIS8, MVC5, nHibernate DAL) và tôi nhận thấy mức sử dụng CPU cao vào cuối năm. Đi xe đạp hồ bơi ứng dụng sửa chữa nó nhưng sau khi thực hiện một số chẩn đoán và bãi bộ nhớ từ máy chủ để phân tích vấn đề, tôi nhận thấy một mẫu nhất quán của nhiều chủ đề cố gắng liệt kê cùng một bộ sưu tập. Điểm phổ biến nhất là nơi ứng dụng kiểm tra vai trò của người dùng. Tôi nghi ngờ điều này có thể được nhiều hơn để thực tế là mã này được chạy cho mọi yêu cầu để xác minh quyền, do đó, nó có nhiều khả năng là bộ sưu tập nó bị mắc kẹt trên?nHibernate liệt kê cùng một bộ sưu tập trên nhiều chủ đề
public IList<Role> GetRoles(string username)
{
var login = GetLoginForUser(username);
return !login.Groups.Any() ? new List<Role>() : login.Groups.SelectMany(x => x.Roles).OrderBy(x => x.DisplayName).ToList();
}
Đối tượng CurrentUser của tôi có giao diện đơn giản chứa thông tin chi tiết của người dùng, được chèn từ trình phân giải phụ thuộc. Tôi đã xác minh rằng UserId hiện diện và hợp lệ, tất cả đều khá thẳng về phía trước. Khi tôi xem xét các bãi khi hai yêu cầu này được treo, tôi nhận được cảnh báo rằng nhiều luồng đã liệt kê một bộ sưu tập. Khi tôi kiểm tra hai luồng trong bãi chứa, tôi thấy các dấu vết ngăn xếp giống hệt nhau. (Tôi đã đổi tên một số chi tiết không gian tên trong ngăn xếp ngăn xếp nhưng nó không bị thay đổi). Các userId (và kết quả hồ sơ) trong cả hai yêu cầu là như nhau, do đó, nó xuất hiện đó là do hai chủ đề riêng biệt cố gắng để tải cùng một đối tượng từ cơ sở dữ liệu tại thực tế cùng một lúc.
Dấu vết ngăn xếp bên dưới, nhưng tôi không chắc chắn nên đi đâu từ đây để sửa lỗi này.
System.Collections.Generic.Dictionary`2[[System.__Canon, mscorlib],[System.Nullable`1[[System.Int32, mscorlib]], mscorlib]].FindEntry(System.__Canon)+129
System.Collections.Generic.Dictionary`2[[System.__Canon, mscorlib],[System.Nullable`1[[System.Int32, mscorlib]], mscorlib]].TryGetValue(System.__Canon, System.Nullable`1<Int32> ByRef)+12
NHibernate.AdoNet.ColumnNameCache.GetIndexForColumnName(System.String, NHibernate.AdoNet.ResultSetWrapper)+25
NHibernate.AdoNet.ColumnNameCache.GetIndexForColumnName(System.String, NHibernate.AdoNet.ResultSetWrapper)+25
NHibernate.AdoNet.ResultSetWrapper.GetOrdinal(System.String)+e
NHibernate.AdoNet.ResultSetWrapper.GetOrdinal(System.String)+e
NHibernate.Type.NullableType.NullSafeGet(System.Data.IDataReader, System.String)+29
NHibernate.Type.NullableType.NullSafeGet(System.Data.IDataReader, System.String[], NHibernate.Engine.ISessionImplementor, System.Object)+16
NHibernate.Type.NullableType.NullSafeGet(System.Data.IDataReader, System.String[], NHibernate.Engine.ISessionImplementor, System.Object)+16
NHibernate.Persister.Collection.AbstractCollectionPersister.ReadKey(System.Data.IDataReader, System.String[], NHibernate.Engine.ISessionImplementor)+14
NHibernate.Persister.Collection.AbstractCollectionPersister.ReadKey(System.Data.IDataReader, System.String[], NHibernate.Engine.ISessionImplementor)+14
NHibernate.Loader.Loader.ReadCollectionElement(System.Object, System.Object, NHibernate.Persister.Collection.ICollectionPersister, NHibernate.Loader.ICollectionAliases, System.Data.IDataReader, NHibernate.Engine.ISessionImplementor)+34
NHibernate.Loader.Loader.ReadCollectionElement(System.Object, System.Object, NHibernate.Persister.Collection.ICollectionPersister, NHibernate.Loader.ICollectionAliases, System.Data.IDataReader, NHibernate.Engine.ISessionImplementor)+34
NHibernate.Loader.Loader.ReadCollectionElements(System.Object[], System.Data.IDataReader, NHibernate.Engine.ISessionImplementor)+d2
NHibernate.Loader.Loader.ReadCollectionElements(System.Object[], System.Data.IDataReader, NHibernate.Engine.ISessionImplementor)+d2
NHibernate.Loader.Loader.GetRowFromResultSet(System.Data.IDataReader, NHibernate.Engine.ISessionImplementor, NHibernate.Engine.QueryParameters, NHibernate.LockMode[], NHibernate.Engine.EntityKey, System.Collections.IList, NHibernate.Engine.EntityKey[], Bo+ab
NHibernate.Loader.Loader.GetRowFromResultSet(System.Data.IDataReader, NHibernate.Engine.ISessionImplementor, NHibernate.Engine.QueryParameters, NHibernate.LockMode[], NHibernate.Engine.EntityKey, System.Collections.IList, NHibernate.Engine.EntityKey[], Bo+ab
NHibernate.Loader.Loader.DoQuery(NHibernate.Engine.ISessionImplementor, NHibernate.Engine.QueryParameters, Boolean)+1e7
NHibernate.Loader.Loader.DoQuery(NHibernate.Engine.ISessionImplementor, NHibernate.Engine.QueryParameters, Boolean)+1e7
NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections(NHibernate.Engine.ISessionImplementor, NHibernate.Engine.QueryParameters, Boolean)+7f
NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections(NHibernate.Engine.ISessionImplementor, NHibernate.Engine.QueryParameters, Boolean)+7f
NHibernate.Loader.Loader.LoadCollection(NHibernate.Engine.ISessionImplementor, System.Object, NHibernate.Type.IType)+de
NHibernate.Loader.Loader.LoadCollection(NHibernate.Engine.ISessionImplementor, System.Object, NHibernate.Type.IType)+de
NHibernate.Loader.Collection.CollectionLoader.Initialize(System.Object, NHibernate.Engine.ISessionImplementor)+1c
NHibernate.Loader.Collection.CollectionLoader.Initialize(System.Object, NHibernate.Engine.ISessionImplementor)+1c
NHibernate.Persister.Collection.AbstractCollectionPersister.Initialize(System.Object, NHibernate.Engine.ISessionImplementor)+1e
NHibernate.Persister.Collection.AbstractCollectionPersister.Initialize(System.Object, NHibernate.Engine.ISessionImplementor)+1e
NHibernate.Event.Default.DefaultInitializeCollectionEventListener.OnInitializeCollection(NHibernate.Event.InitializeCollectionEvent)+16d
NHibernate.Impl.SessionImpl.InitializeCollection(NHibernate.Collection.IPersistentCollection, Boolean)+1fa
NHibernate.Collection.AbstractPersistentCollection.Initialize(Boolean)+2f
NHibernate.Collection.AbstractPersistentCollection.Read()+d
NHibernate.Collection.Generic.PersistentGenericBag`1[[System.__Canon, mscorlib]].System.Collections.Generic.IEnumerable<T>.GetEnumerator()+11
System_Core_ni!System.Linq.Enumerable+<SelectManyIterator>d__14`2[[System.__Canon, mscorlib],[System.__Canon, mscorlib]].MoveNext()+10c
System_Core_ni!System.Linq.Buffer`1[[System.__Canon, mscorlib]]..ctor(System.Collections.Generic.IEnumerable`1<System.__Canon>)+d9
System_Core_ni!System.Linq.OrderedEnumerable`1+<GetEnumerator>d__0[[System.__Canon, mscorlib]].MoveNext()+6f
System_Core_ni!System.Linq.OrderedEnumerable`1+<GetEnumerator>d__0[[System.__Canon, mscorlib]].MoveNext()+6f
mscorlib_ni!System.Collections.Generic.List`1[[System.__Canon, mscorlib]]..ctor(System.Collections.Generic.IEnumerable`1<System.__Canon>)+17e
System_Core_ni!System.Linq.Enumerable.ToList[[System.__Canon, mscorlib]](System.Collections.Generic.IEnumerable`1<System.__Canon>)+3b
Company.ApplicationServices.SecurityService.GetRoles(System.String)+ef
Tôi hiện đang mở giao dịch cơ sở dữ liệu của tôi trong một ActionFilter mở giao dịch khi OnActionExecuting()
xảy ra, và sau đó cam kết/rollback giao dịch khi OnActionExecuted()
xảy ra.
Tôi đang sử dụng StructureMap (v2.6.4.1) để tiêm phụ thuộc của tôi và các dòng có liên quan để duy trì dữ liệu của tôi như sau.
var cfg = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008.ConnectionString(c => c.FromConnectionStringWithKey("DatabaseConnectionString"))
.CurrentSessionContext<WebSessionContext>()
// ... etc etc....
.Cache(c => c.ProviderClass<NHibernate.Caches.SysCache2.SysCacheProvider>()
.UseQueryCache()
.UseSecondLevelCache()
.UseMinimalPuts());
For<NHibernate.Cfg.Configuration>().Singleton().Use(cfg);
For<NHibernate.ISessionFactory>().Singleton()
.Use(ctx =>
{
try
{
var config = ctx.GetInstance<NHibernate.Cfg.Configuration>();
return config.BuildSessionFactory();
}
catch (SqlException ex)
{
ctx.GetInstance<IExceptionLogger>().Error(ex);
throw;
}
});
For<NHibernate.ISession>().HybridHttpOrThreadLocalScoped()
.Use(ctx => ctx.GetInstance<NHibernate.ISessionFactory>().OpenSession());
UPDATE: Tôi vẫn đang đối phó với điều này và rất thích một số lời khuyên về nếu điều này là một vấn đề với nhibernate, hoặc làm thế nào tôi có nó được cấu hình? Tôi đã có các khóa ứng dụng đến điểm mà chúng tôi đã phải khởi động lại máy chủ ngày hôm nay vì 19 chủ đề riêng biệt cố gắng liệt kê cùng một bộ sưu tập.
Nó được đề cập dưới đây có thể là một vấn đề với phạm vi cuộc sống của SecurityService, mà tôi đồng ý là một khả năng. Hiện tại tôi có các dịch vụ được cung cấp thông qua tiêm phụ thuộc thông qua Structuremap (phiên bản cuối cùng của phiên bản 2.6 được phát hành, chưa cập nhật lên 3.x). Chi tiết trong đó tôi đã nêu chi tiết một thời gian ngắn dưới đây cho những gì tôi hy vọng là ngắn gọn nhưng vẫn có liên quan.
public class SecurityService : ISecurityService
{
private readonly IRepository<Login> loginRepository;
public IList<Role> GetCurrentUserRoles()
{
var login = GetLoginForCurrentUser();
return GetRoles(login.Name);
}
public Login GetLoginForCurrentUser()
{
//Some logic to derive the current UserId {guid} via some resources injected into this service class.
return loginRepository.GetReference(loginId);
}
}
public class NHibernateRepository<T> : IRepository<T> where T : class
{
protected ISession Session { get; set; }
public NHibernateRepository(ISession session)
{
Session = session;
}
public T GetReference(object id)
{
return Session.Get<T>(id);
}
// Other methods typical of a repository class, nothing special
}
tôi thiết lập phụ thuộc resolver ....
For<ISecurityService>().Use<SecurityService>();
For(typeof (IRepository<>)).Use(typeof (NHibernateRepository<>));
//And then the ISession is commented above.
nHibernate được cấu hình với một bối cảnh nội bộ của WebSessionContext ISessionFactory là Singleton ISession là HybridHttpOrThreadLocalScoped ISecurityService và IRepository đều cả trái t mặc định của Transient
Các vai trò được lưu trong bộ nhớ cache và nếu không được tìm thấy thì hệ thống sẽ thực hiện cuộc gọi đến GetRoles cho tôi trên dịch vụ bảo mật, tôi nghĩ rằng tôi có thể có một vấn đề với nó gọi GetRoles thường xuyên hơn nó cần, nhưng đó là bên ngoài phạm vi của nhiều vấn đề liệt kê đồng thời tôi đang có bây giờ.
CẬP NHẬT: Vì vậy, tôi gặp khó khăn, hôm nay tôi nhận được cùng một sự cố cho cuộc gọi đến GetReference. 18 chủ đề riêng biệt bị mắc kẹt liệt kê cùng một bộ sưu tập, nhưng điều này là nội bộ để nHibernate.
System.Collections.Generic.Dictionary`2[[System.__Canon, mscorlib],[System.Nullable`1[[System.Int32, mscorlib]], mscorlib]].FindEntry(System.__Canon)+129
System.Collections.Generic.Dictionary`2[[System.__Canon, mscorlib],[System.Nullable`1[[System.Int32, mscorlib]], mscorlib]].TryGetValue(System.__Canon, System.Nullable`1 ByRef)+12
NHibernate.AdoNet.ColumnNameCache.GetIndexForColumnName(System.String, NHibernate.AdoNet.ResultSetWrapper)+25
NHibernate.AdoNet.ResultSetWrapper.GetOrdinal(System.String)+e
NHibernate.Type.NullableType.NullSafeGet(System.Data.IDataReader, System.String)+29
NHibernate.Type.NullableType.NullSafeGet(System.Data.IDataReader, System.String[], NHibernate.Engine.ISessionImplementor, System.Object)+16
NHibernate.Type.AbstractType.Hydrate(System.Data.IDataReader, System.String[], NHibernate.Engine.ISessionImplementor, System.Object)+14
NHibernate.Persister.Entity.AbstractEntityPersister.Hydrate(System.Data.IDataReader, System.Object, System.Object, NHibernate.Persister.Entity.ILoadable, System.String[][], Boolean, NHibernate.Engine.ISessionImplementor)+3ce
NHibernate.Loader.Loader.LoadFromResultSet(System.Data.IDataReader, Int32, System.Object, System.String, NHibernate.Engine.EntityKey, System.String, NHibernate.LockMode, NHibernate.Persister.Entity.ILoadable, NHibernate.Engine.ISessionImplementor)+118
NHibernate.Loader.Loader.InstanceNotYetLoaded(System.Data.IDataReader, Int32, NHibernate.Persister.Entity.ILoadable, NHibernate.Engine.EntityKey, NHibernate.LockMode, System.String, NHibernate.Engine.EntityKey, System.Object, System.Collections.IList, NHi+8c
NHibernate.Loader.Loader.GetRow(System.Data.IDataReader, NHibernate.Persister.Entity.ILoadable[], NHibernate.Engine.EntityKey[], System.Object, NHibernate.Engine.EntityKey, NHibernate.LockMode[], System.Collections.IList, NHibernate.Engine.ISessionImpleme+129
NHibernate.Loader.Loader.GetRowFromResultSet(System.Data.IDataReader, NHibernate.Engine.ISessionImplementor, NHibernate.Engine.QueryParameters, NHibernate.LockMode[], NHibernate.Engine.EntityKey, System.Collections.IList, NHibernate.Engine.EntityKey[], Bo+97
NHibernate.Loader.Loader.DoQuery(NHibernate.Engine.ISessionImplementor, NHibernate.Engine.QueryParameters, Boolean)+1e7
NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections(NHibernate.Engine.ISessionImplementor, NHibernate.Engine.QueryParameters, Boolean)+7f
NHibernate.Loader.Loader.LoadEntity(NHibernate.Engine.ISessionImplementor, System.Object, NHibernate.Type.IType, System.Object, System.String, System.Object, NHibernate.Persister.Entity.IEntityPersister)+f3
NHibernate.Loader.Entity.AbstractEntityLoader.Load(NHibernate.Engine.ISessionImplementor, System.Object, System.Object, System.Object)+22
NHibernate.Loader.Entity.AbstractEntityLoader.Load(System.Object, System.Object, NHibernate.Engine.ISessionImplementor)+12
NHibernate.Persister.Entity.AbstractEntityPersister.Load(System.Object, System.Object, NHibernate.LockMode, NHibernate.Engine.ISessionImplementor)+69
NHibernate.Event.Default.DefaultLoadEventListener.LoadFromDatasource(NHibernate.Event.LoadEvent, NHibernate.Persister.Entity.IEntityPersister, NHibernate.Engine.EntityKey, NHibernate.Event.LoadType)+84
NHibernate.Event.Default.DefaultLoadEventListener.DoLoad(NHibernate.Event.LoadEvent, NHibernate.Persister.Entity.IEntityPersister, NHibernate.Engine.EntityKey, NHibernate.Event.LoadType)+1d7
NHibernate.Event.Default.DefaultLoadEventListener.Load(NHibernate.Event.LoadEvent, NHibernate.Persister.Entity.IEntityPersister, NHibernate.Engine.EntityKey, NHibernate.Event.LoadType)+5e
NHibernate.Event.Default.DefaultLoadEventListener.ReturnNarrowedProxy(NHibernate.Event.LoadEvent, NHibernate.Persister.Entity.IEntityPersister, NHibernate.Engine.EntityKey, NHibernate.Event.LoadType, NHibernate.Engine.IPersistenceContext, System.Object)+73
NHibernate.Event.Default.DefaultLoadEventListener.ProxyOrLoad(NHibernate.Event.LoadEvent, NHibernate.Persister.Entity.IEntityPersister, NHibernate.Engine.EntityKey, NHibernate.Event.LoadType)+cb
NHibernate.Event.Default.DefaultLoadEventListener.OnLoad(NHibernate.Event.LoadEvent, NHibernate.Event.LoadType)+120
NHibernate.Impl.SessionImpl.FireLoad(NHibernate.Event.LoadEvent, NHibernate.Event.LoadType)+140
NHibernate.Impl.SessionImpl.Get(System.String, System.Object)+148
NHibernate.Impl.SessionImpl.Get(System.Type, System.Object)+121
NHibernate.Impl.SessionImpl.Get[[System.__Canon, mscorlib]](System.Object)+143
Intellitive.Data.Repositories.NHibernateRepository`1[[System.__Canon, mscorlib]].GetReference(System.Object)+38
Có nhiều điều sau cuộc gọi đến GetReference nhưng nó không thực sự liên quan đến vấn đề từ những gì tôi có thể nói?
Bạn có chắc chắn rằng ActionFilter của bạn không được gọi khi css/js/images được yêu cầu? Nếu đúng như vậy, thì đó có thể là nguyên nhân của phí (tạo giao dịch và nhấn cơ sở dữ liệu để kiểm tra vai trò cho mọi yêu cầu đó). – ialekseev
Tôi tin như vậy, tôi có thiết lập định tuyến của MVC để bỏ qua tất cả nội dung trong đường dẫn Nội dung và Tập lệnh. Và không có phiên đăng nhập cho nhibernate được hiển thị trong nHProf. –
Bạn đang sử dụng phiên bản NHibernate nào? – b2zw2a