Как улучшить производительность служб данных WCF
Я новичок в службах передачи данных WCF, поэтому я играл. После некоторых начальных тестов я разочарован в производительности моей службы тестовых данных.
Я понимаю, что, поскольку WCF DS основан на HTTP, в протоколе есть служебные данные, но мои тесты все еще медленнее, чем я ожидал:
Окружающая среда:
- Все на одной коробке: четырехъядерный 64-разрядный ноутбук с 4 ГБ оперативной памяти, работающий на W7. Достойная машина.
- Малая база данных SQL (SQLExpress 2008 R2) с 16 таблицами... в тестовой таблице содержится 243 строки.
- Хостинг моей службы тестирования в IIS со всеми значениями по умолчанию.
код:
- Я создал модель Entity Framework (DataContext) для этой базы данных (запасной код для VS2010).
- Я создал службу данных на основе этой модели.
- Я создал клиент, у которого есть прямая ссылка на службу (ObjectContext) для этой службы (фондовый код для VS2010)
- В клиенте я также могу напрямую вызвать модель EF, а также использовать собственный SQL (ADO.NET SqlConnection)
План тестирования:
- Каждая итерация соединяется с базой данных (есть возможность повторного использования подключений), запросы для всех строк в целевой таблице ( "СОБЫТИЯ" ), а затем подсчитывает их (таким образом, заставляя любые отложенные выборки выполняться).
- Выполнить для 25 итераций каждый для собственного SQL (SqlConnection/SqlCommand), Entity Framework (DataContext) и служб данных WCF (ObjectContext).
Результаты:
- 25 итераций собственного SQL: 436ms
- 25 итераций Entity Framework: 656ms
- 25 итераций служб данных WCF: 12110ms
Уч. Это примерно в 20 раз медленнее, чем EF.
Поскольку службы WCF Data Services являются HTTP, нет возможности повторного использования HTTP-соединения, поэтому клиент вынужден повторно подключаться к веб-серверу для каждой итерации. Но, конечно, здесь происходит больше, чем это.
EF сам по себе довольно быстр, и один и тот же код/модель EF повторно используется как для службы, так и для клиентских тестов прямого доступа к EF. Там будут некоторые накладные расходы на сериализацию и десериализацию Xml в службе данных, но так много!?! У меня была хорошая производительность с сериализацией Xml в прошлом.
Я собираюсь запустить некоторые тесты с кодировками JSON и Protocol-Buffer, чтобы узнать, могу ли я повысить производительность, но мне любопытно, есть ли у сообщества какие-либо советы для ускорения этого.
Я не силен с IIS, поэтому, возможно, есть некоторые настройки IIS (кеши, пулы подключений и т.д.), которые можно настроить для улучшения этого?
Ответы
Ответ 1
Рассмотрим вместо этого развертывание в качестве службы Windows? У IIS могут быть фильтры ASAPI, правила перезаписи и т.д., Которые он выполняет. даже если ни одна из них не активна, конвейер IIS настолько длинный, что может немного замедлить вас.
служба должна дать вам хорошую базовую информацию о том, сколько времени требуется для запуска запроса, упаковки и т.д. без замедления IIS.
Ответ 2
В приведенной ниже ссылке есть видео, которое содержит некоторые интересные тесты WCF и сравнения между службами данных WCF и Entity Framework.
http://www.relationalis.com/articles/2011/4/10/wcf-data-services-overhead-performance.html
Ответ 3
Попробуйте установить безопасность в "none" в разделе привязки в конфигурации. Это должно значительно улучшить.
Ответ 4
Чтобы устранить большую часть накладных расходов на соединение, вы можете попытаться выполнить все операции с WCF DS, чтобы убедиться, что это имеет существенное значение.
NorthwindEntities context = new NorthwindEntities(svcUri);
var batchRequests =
new DataServiceRequest[]{someCustomerQuery, someProductsQuery};
var batchResponse = context.ExecuteBatch(batchRequests);
Подробнее см. здесь.
Ответ 5
Как вы передаете эти 25 итераций для WCF?
var WCFobj = new ...Service();
foreach(var calling in CallList)
WCFobj.Call(...)
Если вы вызываете это, это означает, что вы вызываете WCF 25 раз, что потребляет слишком много ресурсов.
Для меня я использовал для создания всего в DataTable
и имя таблицы пользователя для хранимой процедуры, которую я вызываю; DataRow
- это параметры. При вызове просто передайте DataTable в зашифрованном виде, используя
var table = new DataTable("PROC_CALLING")...
...
StringBuilder sb = new StringBuilder();
var xml = System.Xml.XmlWriter.Create(sb);
table.WriteXml(xml);
var bytes = System.Text.Encoding.UTF8.GetBytes(sb.ToString());
[optional]use GZip to bytes
WCFobj.Call(bytes);
Дело в том, что вы передаете все 25 звонков одновременно, что может значительно сэкономить производительность. Если возвращаемый объект имеет одинаковую структуру, просто передайте его как DataTable
в форме байта и преобразуйте его обратно в DataTable
.
Я использовал эти методы для GZip для модулей данных импорта/экспорта. Передача большого количества байтов делает WCF несчастливым. Это зависит от того, что вы хотите потреблять; вычислительных ресурсов или сетевых ресурсов.
Ответ 6
WCF DataServices предназначены для предоставления вашим разрозненным клиентам протокола OpenData; так как вам не нужно писать/рефакторировать несколько методов веб-службы для каждого запроса на изменение. Я никогда не советую использовать его, если вся система основана на технологии Microsoft. Это предназначено для удаленных клиентов.
Ответ 7
Я увеличил производительность нашего API службы данных WCF на 41%, просто включив сжатие. Это было действительно легко сделать. Следуйте этой ссылке, которая объясняет, что делать на вашем сервере IIs: Включение динамического сжатия (gzip, deflate) для фидов данных WCF, OData и других настраиваемых сервисов в IIS7
Не забывайте iisReset после вашего изменения!
На стороне клиента:
// This is your context basically, you should have this code throughout your app.
var context = new YourEntities("YourServiceURL");
context.SendingRequest2 += SendingRequest2;
// Add the following method somewhere in a static utility library
public static void SendingRequest2(object sender, SendingRequest2EventArgs e)
{
var request = ((HttpWebRequestMessage)e.RequestMessage).HttpWebRequest;
request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
}
Ответ 8
вещи, которые нужно попробовать:
1): кодирование результатов: используйте бинарное кодирование вашего канала WCF, если это возможно, см. http://msdn.microsoft.com/en-us/magazine/ee294456.aspx - поочередно используйте сжатие: http://programmerpayback.com/2009/02/18/speed-up-your-app-by-compressing-wcf-service-responses/
2) измените поведение вашего экземпляра службы, см. http://msdn.microsoft.com/en-us/magazine/cc163590.aspx#S6 - попробуйте InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple - if вы можете проверить, что ваша служба построена поточно-безопасным способом.
Что касается вашего теста, я думаю, что вы должны моделировать более реалистичную нагрузку (включая одновременных пользователей) и игнорировать выбросы, первый запрос IIS будет очень медленным (он должен загружать все DLL)