Более быстрая загрузка NHibernate в мультитенантной среде - PullRequest
2 голосов
/ 17 июня 2019

Мне нужен доступ к сотням SQL-серверов с одинаковым набором схем с использованием NHibernate.У каждого клиента есть несколько разных баз данных для разных функций.Каждый клиент хранит свои собственные строки подключения для своих баз данных в таблице DatabaseEntity, а также в одной глобальной таблице, которая обеспечивает начальное подключение.Мне нужно использовать это для сервиса и функциональности сайта.Загрузка NHibernate для доступа к этим базам данных занимает недопустимое количество времени.

Использование этой статьи https://patrickhuber.wordpress.com/2011/10/25/change-connectionstring-nhibernate/ Я обнаружил, что использование одного SessionFactory и изменяемого соединения приведет к потере кеша второго уровня, а также появлениюс другими вопросами.Используя пример из этой статьи, я также попытался кэшировать конфигурацию и изменить соединение, однако config.BuildSessionFactory () по-прежнему занимает несколько секунд.Умножается на сотни клиентских БД, это проблема.

Альтернативой является использование отложенной загрузки для загрузки только информации о соединении с клиентом при поступлении запроса. Однако это будет означать, что клиент будет ждать несколько секунд в течение нескольких секунд.при первом входе в систему это недопустимо.

Другой вариант - это одновременная загрузка всей информации базы данных при запуске.Я пытался использовать await / async для предварительной загрузки информации базы данных и объектов SessionFactory при запуске с помощью функций NHibernate, таких как ListAsync () и Task.WaitAll, но, похоже, это плохо работает с NHibernate (или я что-то упустил).

Ниже приведен очень упрощенный асинхронный код, который начал синхронно загружать информацию при создании переменных задач.Пожалуйста, предложите альтернативы или исправления для любого из этих параметров.

// Usage
IDictionary<long, IList<DatabaseEntity>> databaseList = await LoadDatabasesAsynchronously();

// Database entity contains connection information, schema and unique SessionFactory
// One database entity per customer should return a list of database entities per customer from the DatabaseEntity table
private static async Task<IDictionary<long, IList<DatabaseEntity>>> LoadDatabasesAsynchronously()
{
    // Each database entity has it's own SessionFactory
    IDictionary<long, IList<DatabaseEntity>> databaseDictionary = LoadDatabasesSynchronously(); // Key = Customer ID, Value = List of database entities in customer (one each to start with)
    var tasks = databaseDictionary.ToDictionary(k => k.Key, v => GetDatabases(v.Value.First())); // Load NHibernate query tasks
    Task.WaitAll(tasks.Select(kvp => kvp.Value).ToArray()); // Does not reach here
    return tasks.ToDictionary(k => k.Key, v => v.Value.GetAwaiter().GetResult());
}

private static async Task<IList<DatabaseEntity>> GetDatabases(DatabaseEntity database)
{
    using (TransactionRequired transaction = new TransactionRequired(database.Session))
    {
        return await database.Session.QueryOver<DatabaseEntity>().Where(x => x.Type == someType).ListAsync();
    }
}

Обязательным является идентификатор IDictionary>, заполняемый одновременно с использованием NHibernate на основе синхронно загруженного IDictionary>, который начинается с одного подключения DatabaseEntity для каждого клиента.

1 Ответ

0 голосов
/ 25 июня 2019

Вы можете сериализовать / десериализовать конфигурацию nhibernate. Десериализация может быть быстрее, чем сборка конфигурации. Попробуйте это

private bool IsConfigurationFileValid
        {
            get
            {
                var assemblies = _configurationParameters.MappingAssemblies
                    .Where(mapAssembly => !string.IsNullOrEmpty(mapAssembly.Location))
                    .ToList();
                if (assemblies.Count == 0)
                {
                    return false;
                }

                var serializedConfigFileInfo = new FileInfo(SerializedConfigurationFilePath);
                return assemblies
                    .Select(mapAssembly => new FileInfo(mapAssembly.Location))
                    .Aggregate(true, (current, mapAssembly) => current & (mapAssembly.CreationTime <= serializedConfigFileInfo.CreationTime && mapAssembly.LastWriteTime <= serializedConfigFileInfo.LastWriteTime));
            }
        }

        private void SaveConfigurationToFile(NHibernate.Cfg.Configuration configuration)
        {
            try
            {
                using (var file = File.Open(SerializedConfigurationFilePath, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite))
                {
                    var bf = new BinaryFormatter();
                    bf.Serialize(file, configuration);
                }
            }
            catch (Exception e)
            {
                _log.Fatal("Cant save serialized configuration", e);
            }
        }

        private NHibernate.Cfg.Configuration LoadConfigurationFromFile()
        {
            if (!IsConfigurationFileValid)
                return null;
            try
            {
                using (var file = File.Open(SerializedConfigurationFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                {
                    var bf = new BinaryFormatter();
                    var configurationFromFile = bf.Deserialize(file) as NHibernate.Cfg.Configuration;

                    if (configurationFromFile == null)
                        return null;

                    var currentConnectionString = configurationFromFile.GetProperty(NHibernate.Cfg.Environment.ConnectionString);

                    return currentConnectionString == _configurationParameters.ConnectionString
                        ? configurationFromFile
                        : null;
                }
            }
            catch (Exception ex)
            {
                _log.Info("LoadConfigurationFromFile failed", ex);
                return null;
            }
        }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...