Проблемы производительности WCF + Gzip
У меня есть служба WCF, которая возвращает тип контента "application/x-gzip", который, по сути, выглядит как XML/Json, сжатый с помощью Gzip. Я реализовал GzipMessageEncoder и CustomBinding, как описано по следующей ссылке Карлоса Фигейры:
http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/8c3eafae-b6a1-441f-85ef-90721d941a1a
Для данных, которые возвращает мой сервис, я использую базовую концепцию сетки с JSON, которая разделяет схему и использует строку [] для каждой строки, чтобы сохранить компактность:
[DataContract]
[KnownType(typeof(JsonContract))]
[KnownType(typeof(ColumnDefinition))]
public class JsonContract
{
[DataMember]
public List<ColumnDefinition> Schema { get; set; }
[DataMember]
public List<String[]> Rows { get; set; }
}
public class Service : IGzipTest
{
public JsonContract HttpRequest()
{
// return json data
}
}
Gzip работает нормально, но я думаю, что производительность на моем клиенте низкая / противоречивая, используя ChannelFactory:
private ChannelFactory<T> CreateFactory<T>(CustomBinding binding, string endpoint)
{
EndpointAddress _endpoint = new EndpointAddress(endpoint);
ChannelFactory<T> _factory = new ChannelFactory<T>(binding, _endpoint);
_factory.Endpoint.Behaviors.Add(new WebHttpBehavior());
return _factory;
}
Вот как я запускаю сервис:
static string baseAddress = "http://" + Dns.GetHostName() + ":4050/ZipTest";
static ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
protected void Application_Start(object sender, EventArgs e)
{
ThreadPool.SetMinThreads(Environment.ProcessorCount, 9);
host.AddServiceEndpoint(typeof(IGzipTest),
GzipMapper.GetBinding(), "").Behaviors.Add(new WebHttpBehavior());
host.Open();
}
При загрузке ~512 КБ в ~1 МБ данных (то есть после сжатия), вот мои результаты производительности на отдельных последовательных тестах:
1st Request: 4439ms
2nd Request: 19029ms
..and so on
Кажется, что каждый второй звонок в службу занимает в 4-5 раз больше времени. Даже 4000 мс кажется длинным только для 512 КБ на 1 МБ данных, поэтому мне интересно, что может быть не так.
Например, если я загружаю сам файл.gz из браузера, используя метод [WebGet], это займет не более секунды, потому что в худшем случае я получаю 400-500 Кбит / с.
1 ответ
Я видел подобные колебания, и они были вызваны, по крайней мере, об этом я сейчас думаю, чрезмерным использованием памяти GzipMessageEncoder и буферизованным TransferMode, который используется по умолчанию. Buffered TransferMode использует BufferManager, что может привести к серьезным проблемам с памятью и вызывать исключения OutOfMemoryException для меня.
Каковы бы ни были точные причины, я исправил это, а также значительно сократил потребление памяти и нагрузку на процессор как серверов, так и клиентов.
- Как избавиться от GzipMessageEncoder, см. Wcf условное сжатие
- Переход на потоковый TransferMode см. В разделе Как предотвратить использование памяти BufferManager / PooledBufferManager в моем клиентском приложении WCF?