C# SSH.NET - одно соединение SSH против нескольких соединений SSH
У меня есть приложение C#, которое использует библиотеку SSH.NET для подключения к серверу. Приложение выполняет команды SQL для базы данных несколькими способами.
Лучше ли иметь одно продолжительное SSH-соединение, которое охватывает все команды SQL, например:
using (var sshClient = getSshClient()))
{
sshClient.Connect();
if (sshClient.IsConnected)
{
using (var portForward = setupPortForward()))
{
sshClient.AddForwardedPort(setupPortForward());
portForward.Start();
// Start SQL commands
if (!sshClient.IsConnected) {
sshClient.Connect();
}
else {
executeSQLCommand1();
}
if (!sshClient.IsConnected) {
sshClient.Connect();
}
else {
executeSQLCommand2();
}
// End SQL commands
portForward.Stop();
sshClient.Disconnect();
}
}
}
Или открыть соединение SSH в начале каждого оператора SQL?
using (var sshClient = setupSshClient()))
{
sshClient.Connect();
if (sshClient.IsConnected)
{
using (var portForward = setupPortForward()))
{
sshClient.AddForwardedPort(portForward);
portForward.Start();
executeSQLCommand1();
portForward.Stop();
sshClient.Disconnect();
}
}
}
using (var sshClient = setupSshClient()))
{
sshClient.Connect();
if (sshClient.IsConnected)
{
using (var portForward = setupPortForward()))
{
sshClient.AddForwardedPort(portForward);
portForward.Start();
executeSQLCommand2();
portForward.Stop();
sshClient.Disconnect();
}
}
}
Известно, что иногда сервер сбрасывает соединения, поэтому я полагаю, что второй метод лучше с точки зрения "более чистой" логики для восстановления соединения? Или есть какие-то другие лучшие способы для повторного подключения?
1 ответ
Часть 1. Минимизируйте время жизни соединения.
Распространенная "лучшая практика" для SQL-соединений заключается в том, что вы хотите минимизировать время открытия соединения - это означает, что вы открываете соединение непосредственно перед выполнением запроса и закрываете его сразу после этого. То же относится и к SSH-соединениям.
У висящих ресурсов, которые вы не утилизируете после их использования, есть имя, и они называются утечками памяти.
Часть 2. Использование транзакций для обеспечения согласованности состояния БД
Если в ваших транзакциях SQL-запросов произойдет сбой одного оператора, транзакция завершится неудачей. Если вы хотите потерпеть неудачу, откатите состояние БД до того, как возникла ошибка ex: соединение разорвалось, и повторите попытку позже.
Если вам не нужна регистрация ошибок, то вы можете использовать set xact_abort on
до того, как ваша транзакция автоматически откатится в случае ошибки, например: timeout или сбросьте соединение.
Для получения дополнительной информации
- http://www.informit.com/articles/article.aspx?p=29312
- https://docs.microsoft.com/en-us/sql/t-sql/statements/set-xact-abort-transact-sql?view=sql-server-2017
- https://social.technet.microsoft.com/wiki/contents/articles/40078.sql-server-set-xact-abort-vs-try-catch.aspx
Часть 3. Создание политики повторных попыток
Как правило, лучшая практика заключается в том, что вы не хотите избегать неудачи, а вместо этого принимаете ее, быстро терпите неудачу и можете попробовать еще раз. Какую политику вы выбираете для повторной попытки, зависит от вас.
Если вы хотите сделать что-то более сложное, чем ручная повторная попытка, тогда я бы порекомендовал вам взглянуть на Rx наблюдаемый (реактивное расширение) или Полли. У этого есть немного кривой обучения, но вы привыкаете к этому.
// Policy to retry 5 times, waiting {2, 4, 8, 16, 32} seconds between retries.
var policy = Policy
.Handle<SqlException>()
.WaitAndRetry(5, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
policy.Execute(() => UpdateDatabase1(obj1));