Недавно я провел некоторое тестирование производительности и анализ приложения ASP.NET с использованием состояния сеанса вне процесса - это необходимо при использовании состояния сеанса в веб-ферме, чтобы можно было восстановить состояние на любом из веб-серверов, например если последующие HTTP-запросы поступают на другой сервер, потому что сеансы не являются "липкими" или исходный сервер не работает и т.д.
Что меня удивило, так это то, что когда я запускал веб-серверы при полной загрузке и профилировал использование ЦП, примерно 99% времени процессора тратили на сериализацию и десериализацию состояния сеанса. Впоследствии мы реализовали настраиваемый государственный сервер "кэширования"; это всегда сериализует состояние, но также сохраняет состояние в памяти, так что, если вы используете липкие сеансы, состояние не нужно десериализовать большую часть времени. Это улучшило пропускную способность сервера в 2 раза; Однако сериализация по-прежнему составляет 98% или более от времени процессора.
Мы получили некоторые дополнительные улучшения в скорости путем "обрезки" ненужных ссылок на объекты между объектами в состоянии сеанса до сериализации - исправление ссылок вручную при десриализации. Это улучшило скорость еще на 10-20% или около того. Причиной здесь является то, что некоторые потери производительности связаны с тем, что встроенная сериализация должна идти по графику указателей объектов, что становится более сложной задачей с большим количеством указателей.
Продолжая исследование, мы писали индивидуальные процедуры сериализации для некоторых наших классов, а не полагались на встроенную сериализацию .Net. Мы обнаружили, что производительность значительно улучшена, примерно в 50x. Похоже, что основная часть загрузки процессора вызвана встроенной сериализацией .Net, которая, в свою очередь, медленна из-за использования использования Reflection для перемещения указателей/графиков объектов и извлечения данных поля.
Очень заманчиво увеличить нашу производительность на 50 раз, таким образом, уменьшая требования к аппаратным средствам веб-сервера с большим коэффициентом (и потребностями в энергии меньшим, но все же значимым фактором). Возможные варианты:
1) Напишите индивидуальную сериализацию. Это проблема из-за сложности задачи и затрат на обслуживание, которые она генерирует, то есть любое изменение состояния класса требует изменения в процедурах сериализации/десериализации.
2) Некоторые решения сторонних разработчиков. Возможно, какой-то продукт, который автоматически генерирует код сохранения состояния/загрузки во время сборки, тем самым устраняя необходимость использования Reflection.
Мне было бы очень интересно узнать, знает ли кто-нибудь о стороннем решении или столкнулся с этой проблемой, поскольку я не нашел упоминания об этом из интернет-поиска.
UPDATE: Некоторые из них предложили своеобразное решение на полпути между встроенной сериализацией по умолчанию и чистыми настраиваемыми процедурами сериализации. Идея заключается в том, что вы реализуете персонализированную сериализацию для классов, которые влияют на производительность больше всего, например. преодолевая ISerializable. Это интересный и многообещающий подход; Тем не менее, я все же думаю, что существует возможность полной замены встроенной сериализации без необходимости писать и поддерживать какой-либо пользовательский код - это невозможно сделать во время выполнения, потому что Reflection необходим для запроса объектов и доступа к личным данным. Но теоретически возможно послепродавать уже построенные сборки и внедрять новые методы в качестве дополнительного шага сборки. Некоторые профилировщики используют этот подход для ввода кода профилирования в сборки после того, как они были созданы компилятором С#. Также я/думаю/где-то читал, что .Net-среда поддерживает инъекции методов в классы - таким образом, все беспорядки с IL потенциально позаботятся.