SlideShare une entreprise Scribd logo
1  sur  59
Rudi Benkovič rudib@whiletrue.com
While True, d.o.o.
www.whiletrue.com
A very simple read-only MVC application.
As per ASP.NET MVC.NET’s guidelines:
 ASP.NET MVC 1.0
     Also MVCFutures – official addons for MVC
    LINQ-SQL

    IIS7

    SQL Server

Wow! IntelliSense!
We’re testing response time, not overall
throughput – just one concurrent connection.
IIS7             ApacheBench
       ab.exe –n 100 –c 1 http://.../
Response time   Requests / second
        500ms               2
        250ms               4
        100ms               10
         50ms               20
         25ms               40
         15ms              66.6
         10ms              100
         5ms               200




Place your bets!
(Core2 Duo 2.5GHz, 4GB RAM, Win2008 64bit) 8 requests / second




                             Oops
A better “user experience”: responsive web application
1.
     System can respond to many concurrent
2.
     requests
     We can do more things in a single requests:
3.
     richer web applications
JetBrains dotTrace

     Run as Administrator
     IIS worker process: set CPU affinity to a single
     CPU
Expression links
Route itself


Name                  Default values
Expression link

    Html.BuildUrlFromExpression<AccountController>(a => a.UserHome(username))



    Name the action and the controller

    Url.Action(quot;UserHomequot;, quot;Accountquot;, new {username = username})



    Name the route

    Url.RouteUrl(quot;Userquot;, new { username = quot;joeuserquot; })



    Brute force

    string.Format(quot;User/{0}quot;, Url.Encode(username))
Time [ms for 200 links]
      390,0 (!)
20
18
16
                            13.6
14
12
10
                                             7.2
 8
 6
 4
 2
 0
     Expression            Action           Route
Why are variables that much slower?
Different code path for non-constants. We have to compile (!) the expression!
Simple syntax. But, how do we read data from such
objects?
Reading data from an anonymous class into
 RouteValueData (required). Overhead!
Passing multiple parameters can yield a
 significant overhead.
Pass data in a RouteValueDictionary!




Syntax isn’t nearly as nice, but is it worth it?
Time for 200 links [ms]
          390,0 (!)
 20
 18
 16
                          13.6
 14
 12                                         9.8
 10
                                                           7.2
  8
  6                                                                     3.8
  4
  2
  0
        Expression ction, anonymous Action, dictionary anonymous object dictionary
                 A                  class        Route,           Route,



As speed increases, so does the syntax and maintenance overhead!
Results:
8 requests / second => 25.5 requests / second

Replace anonymous classes with
 RouteValueDictionaries:

25.5 requests / second => 27 requests / second
Each LINQ-SQL
query calls
BuildQuery, which
seems to be time
consuming. Why?
Deffered evaluation

    The expression gets transformed into SQL only
    when we call such a method that demands data for
    its work.

    These transformations get cached inside the

    DBContext. Web applications can’t share
    contexts, so there is no effective caching
    getting done.
ToList() triggers the compilation of the query
Compile the expression tree into an SQL

    query and mapping methods. Store them as a
    function that is thread-safe and accepts a
    DBContext and query parameters.
Non-compiled LINQ-SQL query.
Static delegate that
                                              stores the compiled
                                                      query
It’s simple, really...




                         Static DLO


                                                   Return value




                         The original query
Usage: call the static function with the

    current DBContext
Additional feature: join more queries into one!
A lot of overhead source code. Uncompiled

    LINQ-SQL queries are terse, these just aren’t.
    Black magic – the original query won’t always

    work as-is. Exceptions from within LINQ-SQL
    that you can’t really debug.
    A compiled query has to always be called with

    the same instance of
    DataLoadOptions, otherwise it fails!
Simple generic, lambda syntax for queries

    parameters: only for up to three parameters!
    Otherwise you’ll need to declare a class for
    parameters.
Results:
25 requests / second => 52 requests / second

The difference isn’t as big as in real-world
 projects: we don’t have a lot of parameters
 for queries and the expressions are simple.
RenderPartial gets called 41 times from the Index
  view! Let’s optimize that by passing the
  enumeration to the view itself.




Somewhat defeats partial view’s intended usage, but...
41 calls to RenderPartial => three calls.

Results:
52 requests / second => 61.5 requests / second
URLs for MVC applications are typically

    static: they don’t change depending on the
    user/session/request.

    Let’s cache them!



    We wrote our own caching API that uses

    ASP.NET’s builtin memory cache.
Extend ASP.NET MVC’s UrlHelper into UrlHelperCached, add
  new cached methods for Action links.

Join all of data for a single link (action, controller, data) into a
   string and use that as the cache key.
UrlHelper doesn’t implement an interface and it’s methods
  aren’t virtual. We’ll add our own UrlHelperCached as a new
  UrlCached property by extending MVC’s classes:
  MasterPage, ViewPage, ViewUserControl.
Usage: inherit our View class in view’s definition
 and replace Url with UrlCached. That’s all!
Results:
61.5 requests / second => 76 requests / second


Real-world: as routing table gets longer and
 more parameters get passed around, the
 difference is even greater!
We can cache site statistics.

Here’s our little caching API that uses lambda
 syntax for cached values. A lot less code!
Cache stats and top voted news of all time:
76 requests/ second => 153 requests/ second.

Let’s also cache the main news display:
153 requests/ second => 400 requests / second.

Caching all DB data foregoes any SQL-LINQ or SQL
  connection initialization. Even less overhead with
  much faster response times.
Core2 Duo 2.53GHz, 4GB RAM, IIS7        Optimization only   Data caching
 450                                                                400
             Requests per second
 400
 350
 300
 250
 200                                                        153
 150
                                                      76
                                           61.5
 100                               52
                            27
                   25.5
  50     8
   0
Each of these optimization methods is in
 production: fast URL generation, compiled
 queries, URL caching, data caching.
                           The first alpha version
                           without any optimizations
                           ran at ~3 requests / second.
                           Today, the index page can
                           withstand ~800
                           requests/second on a
                           development webserver with
                           real world DB data. HTTP
                           concurrency = 8.
After a few uncomfortable moments of silence...


      Questions?
Ideas for ASP.NET MVC developers:

     Smarter view compiling. Let’s inline partial code
      for views. Or let’s write a new view engine.
     RenderPartials() method that accepts an
      enumeration and can also use a spacer view – like
      RoR.
     Builtin URL caching – why not? Or at least make
      interfaces for HTML and URL helpers.
Thanks to Simone Chiaretta for discovering a gross oversight
  on my part: I’ve done my benchmarks with ASP’s debug
  mode turned on. With regards to ASP.NET MVC 1.0, this
  disables its view engine’s internal cache for resolved paths to
  views. This makes specifying full paths to view irrelevant as
  far as performance is considered.

So, the following change won’t yield any performance yield
  with the debug attribute set to false
  (Web.config, compilation section).
All of the benchmarks have been re-run with debug turned
  off, the change before any optimizations have taken
  place is significant (6 req/s to 8 req/s). Any other
  changes to the performance due to the release mode
  other than view path resolving were basically non-
  existing or within the margin of error.

You can read Simone’s post at
  http://codeclimber.net.nz/archive/2009/04/22/how-to-improve-
  htmlhelper.renderpartial-performances-donrsquot-run-in-debug-mode.aspx

And, of course, run your production websites in
  release mode. :)

Contenu connexe

Tendances

State management
State managementState management
State management
Iblesoft
 

Tendances (20)

JavaScript Functions
JavaScript Functions JavaScript Functions
JavaScript Functions
 
gRPC in Go
gRPC in GogRPC in Go
gRPC in Go
 
Introduction to RxJS
Introduction to RxJSIntroduction to RxJS
Introduction to RxJS
 
Polylog: A Log-Based Architecture for Distributed Systems
Polylog: A Log-Based Architecture for Distributed SystemsPolylog: A Log-Based Architecture for Distributed Systems
Polylog: A Log-Based Architecture for Distributed Systems
 
The Internals of "Hello World" Program
The Internals of "Hello World" ProgramThe Internals of "Hello World" Program
The Internals of "Hello World" Program
 
JavaScript: Events Handling
JavaScript: Events HandlingJavaScript: Events Handling
JavaScript: Events Handling
 
Igor Nicoli: External scripts O poder do Zabbix em suas mãos
Igor Nicoli: External scripts O poder do Zabbix em suas mãosIgor Nicoli: External scripts O poder do Zabbix em suas mãos
Igor Nicoli: External scripts O poder do Zabbix em suas mãos
 
Dot Net Core
Dot Net CoreDot Net Core
Dot Net Core
 
State management
State managementState management
State management
 
01 Php Introduction
01 Php Introduction01 Php Introduction
01 Php Introduction
 
High Availability Content Caching with NGINX
High Availability Content Caching with NGINXHigh Availability Content Caching with NGINX
High Availability Content Caching with NGINX
 
Scala Talk at FOSDEM 2009
Scala Talk at FOSDEM 2009Scala Talk at FOSDEM 2009
Scala Talk at FOSDEM 2009
 
ASP.NET 07 - Site Navigation
ASP.NET 07 - Site NavigationASP.NET 07 - Site Navigation
ASP.NET 07 - Site Navigation
 
C# 101: Intro to Programming with C#
C# 101: Intro to Programming with C#C# 101: Intro to Programming with C#
C# 101: Intro to Programming with C#
 
REST-API introduction for developers
REST-API introduction for developersREST-API introduction for developers
REST-API introduction for developers
 
Php mysql ppt
Php mysql pptPhp mysql ppt
Php mysql ppt
 
Javascript 101
Javascript 101Javascript 101
Javascript 101
 
Php.ppt
Php.pptPhp.ppt
Php.ppt
 
Writing a fast HTTP parser
Writing a fast HTTP parserWriting a fast HTTP parser
Writing a fast HTTP parser
 
Styled Components & React.js
Styled Components & React.jsStyled Components & React.js
Styled Components & React.js
 

Similaire à ASP.NET MVC Performance

Beginning MEAN Stack
Beginning MEAN StackBeginning MEAN Stack
Beginning MEAN Stack
Rob Davarnia
 
Data Handning with Sqlite for Android
Data Handning with Sqlite for AndroidData Handning with Sqlite for Android
Data Handning with Sqlite for Android
Jakir Hossain
 
Drizzle Keynote at the MySQL User's Conference
Drizzle Keynote at the MySQL User's ConferenceDrizzle Keynote at the MySQL User's Conference
Drizzle Keynote at the MySQL User's Conference
Brian Aker
 

Similaire à ASP.NET MVC Performance (20)

Building production websites with Node.js on the Microsoft stack
Building production websites with Node.js on the Microsoft stackBuilding production websites with Node.js on the Microsoft stack
Building production websites with Node.js on the Microsoft stack
 
Scaling asp.net websites to millions of users
Scaling asp.net websites to millions of usersScaling asp.net websites to millions of users
Scaling asp.net websites to millions of users
 
Nodejs + Rails
Nodejs + RailsNodejs + Rails
Nodejs + Rails
 
Best of Microsoft Dev Camp 2015
Best of Microsoft Dev Camp 2015Best of Microsoft Dev Camp 2015
Best of Microsoft Dev Camp 2015
 
NodeJS ecosystem
NodeJS ecosystemNodeJS ecosystem
NodeJS ecosystem
 
Beginning MEAN Stack
Beginning MEAN StackBeginning MEAN Stack
Beginning MEAN Stack
 
Revolutionizing the Data Abstraction Layer with IBM Optim pureQuery and DB2
Revolutionizing the Data Abstraction Layer with IBM Optim pureQuery and DB2Revolutionizing the Data Abstraction Layer with IBM Optim pureQuery and DB2
Revolutionizing the Data Abstraction Layer with IBM Optim pureQuery and DB2
 
Data Handning with Sqlite for Android
Data Handning with Sqlite for AndroidData Handning with Sqlite for Android
Data Handning with Sqlite for Android
 
What's New in .Net 4.5
What's New in .Net 4.5What's New in .Net 4.5
What's New in .Net 4.5
 
Practical WebAssembly with Apex, wasmRS, and nanobus
Practical WebAssembly with Apex, wasmRS, and nanobusPractical WebAssembly with Apex, wasmRS, and nanobus
Practical WebAssembly with Apex, wasmRS, and nanobus
 
Advanced Asp.Net Concepts And Constructs
Advanced Asp.Net Concepts And ConstructsAdvanced Asp.Net Concepts And Constructs
Advanced Asp.Net Concepts And Constructs
 
Mvc
MvcMvc
Mvc
 
How To Scale v2
How To Scale v2How To Scale v2
How To Scale v2
 
Sherlock Homepage - A detective story about running large web services - WebN...
Sherlock Homepage - A detective story about running large web services - WebN...Sherlock Homepage - A detective story about running large web services - WebN...
Sherlock Homepage - A detective story about running large web services - WebN...
 
Vaadin - Rich Web Applications in Server-side Java without Plug-ins or JavaSc...
Vaadin - Rich Web Applications in Server-side Java without Plug-ins or JavaSc...Vaadin - Rich Web Applications in Server-side Java without Plug-ins or JavaSc...
Vaadin - Rich Web Applications in Server-side Java without Plug-ins or JavaSc...
 
Real World Single Page App - A Knockout Case Study
Real World Single Page App - A Knockout Case StudyReal World Single Page App - A Knockout Case Study
Real World Single Page App - A Knockout Case Study
 
Drizzle Keynote at the MySQL User's Conference
Drizzle Keynote at the MySQL User's ConferenceDrizzle Keynote at the MySQL User's Conference
Drizzle Keynote at the MySQL User's Conference
 
Integrate MongoDB & SQL data with a single REST API
Integrate MongoDB & SQL data with a single REST APIIntegrate MongoDB & SQL data with a single REST API
Integrate MongoDB & SQL data with a single REST API
 
SharePoint 2010 Boost your farm performance!
SharePoint 2010 Boost your farm performance!SharePoint 2010 Boost your farm performance!
SharePoint 2010 Boost your farm performance!
 
ASP.net MVC CodeCamp Presentation
ASP.net MVC CodeCamp PresentationASP.net MVC CodeCamp Presentation
ASP.net MVC CodeCamp Presentation
 

Dernier

Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
panagenda
 

Dernier (20)

Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot ModelNavi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 

ASP.NET MVC Performance

  • 1. Rudi Benkovič rudib@whiletrue.com While True, d.o.o. www.whiletrue.com
  • 2. A very simple read-only MVC application.
  • 3. As per ASP.NET MVC.NET’s guidelines:  ASP.NET MVC 1.0  Also MVCFutures – official addons for MVC LINQ-SQL  IIS7  SQL Server 
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 15.
  • 16. We’re testing response time, not overall throughput – just one concurrent connection.
  • 17. IIS7 ApacheBench ab.exe –n 100 –c 1 http://.../
  • 18. Response time Requests / second 500ms 2 250ms 4 100ms 10 50ms 20 25ms 40 15ms 66.6 10ms 100 5ms 200 Place your bets!
  • 19. (Core2 Duo 2.5GHz, 4GB RAM, Win2008 64bit) 8 requests / second Oops
  • 20. A better “user experience”: responsive web application 1. System can respond to many concurrent 2. requests We can do more things in a single requests: 3. richer web applications
  • 21. JetBrains dotTrace   Run as Administrator  IIS worker process: set CPU affinity to a single CPU
  • 23. Route itself Name Default values
  • 24. Expression link  Html.BuildUrlFromExpression<AccountController>(a => a.UserHome(username)) Name the action and the controller  Url.Action(quot;UserHomequot;, quot;Accountquot;, new {username = username}) Name the route  Url.RouteUrl(quot;Userquot;, new { username = quot;joeuserquot; }) Brute force  string.Format(quot;User/{0}quot;, Url.Encode(username))
  • 25. Time [ms for 200 links] 390,0 (!) 20 18 16 13.6 14 12 10 7.2 8 6 4 2 0 Expression Action Route
  • 26. Why are variables that much slower?
  • 27. Different code path for non-constants. We have to compile (!) the expression!
  • 28. Simple syntax. But, how do we read data from such objects?
  • 29. Reading data from an anonymous class into RouteValueData (required). Overhead!
  • 30. Passing multiple parameters can yield a significant overhead.
  • 31. Pass data in a RouteValueDictionary! Syntax isn’t nearly as nice, but is it worth it?
  • 32. Time for 200 links [ms] 390,0 (!) 20 18 16 13.6 14 12 9.8 10 7.2 8 6 3.8 4 2 0 Expression ction, anonymous Action, dictionary anonymous object dictionary A class Route, Route, As speed increases, so does the syntax and maintenance overhead!
  • 33. Results: 8 requests / second => 25.5 requests / second Replace anonymous classes with RouteValueDictionaries: 25.5 requests / second => 27 requests / second
  • 34. Each LINQ-SQL query calls BuildQuery, which seems to be time consuming. Why?
  • 35. Deffered evaluation  The expression gets transformed into SQL only when we call such a method that demands data for its work. These transformations get cached inside the  DBContext. Web applications can’t share contexts, so there is no effective caching getting done.
  • 36. ToList() triggers the compilation of the query
  • 37. Compile the expression tree into an SQL  query and mapping methods. Store them as a function that is thread-safe and accepts a DBContext and query parameters.
  • 39. Static delegate that stores the compiled query It’s simple, really... Static DLO Return value The original query
  • 40. Usage: call the static function with the  current DBContext
  • 41. Additional feature: join more queries into one!
  • 42. A lot of overhead source code. Uncompiled  LINQ-SQL queries are terse, these just aren’t. Black magic – the original query won’t always  work as-is. Exceptions from within LINQ-SQL that you can’t really debug. A compiled query has to always be called with  the same instance of DataLoadOptions, otherwise it fails!
  • 43. Simple generic, lambda syntax for queries  parameters: only for up to three parameters! Otherwise you’ll need to declare a class for parameters.
  • 44. Results: 25 requests / second => 52 requests / second The difference isn’t as big as in real-world projects: we don’t have a lot of parameters for queries and the expressions are simple.
  • 45. RenderPartial gets called 41 times from the Index view! Let’s optimize that by passing the enumeration to the view itself. Somewhat defeats partial view’s intended usage, but...
  • 46. 41 calls to RenderPartial => three calls. Results: 52 requests / second => 61.5 requests / second
  • 47. URLs for MVC applications are typically  static: they don’t change depending on the user/session/request. Let’s cache them!  We wrote our own caching API that uses  ASP.NET’s builtin memory cache.
  • 48. Extend ASP.NET MVC’s UrlHelper into UrlHelperCached, add new cached methods for Action links. Join all of data for a single link (action, controller, data) into a string and use that as the cache key.
  • 49. UrlHelper doesn’t implement an interface and it’s methods aren’t virtual. We’ll add our own UrlHelperCached as a new UrlCached property by extending MVC’s classes: MasterPage, ViewPage, ViewUserControl.
  • 50. Usage: inherit our View class in view’s definition and replace Url with UrlCached. That’s all!
  • 51. Results: 61.5 requests / second => 76 requests / second Real-world: as routing table gets longer and more parameters get passed around, the difference is even greater!
  • 52. We can cache site statistics. Here’s our little caching API that uses lambda syntax for cached values. A lot less code!
  • 53. Cache stats and top voted news of all time: 76 requests/ second => 153 requests/ second. Let’s also cache the main news display: 153 requests/ second => 400 requests / second. Caching all DB data foregoes any SQL-LINQ or SQL connection initialization. Even less overhead with much faster response times.
  • 54. Core2 Duo 2.53GHz, 4GB RAM, IIS7 Optimization only Data caching 450 400 Requests per second 400 350 300 250 200 153 150 76 61.5 100 52 27 25.5 50 8 0
  • 55. Each of these optimization methods is in production: fast URL generation, compiled queries, URL caching, data caching. The first alpha version without any optimizations ran at ~3 requests / second. Today, the index page can withstand ~800 requests/second on a development webserver with real world DB data. HTTP concurrency = 8.
  • 56. After a few uncomfortable moments of silence... Questions?
  • 57. Ideas for ASP.NET MVC developers:   Smarter view compiling. Let’s inline partial code for views. Or let’s write a new view engine.  RenderPartials() method that accepts an enumeration and can also use a spacer view – like RoR.  Builtin URL caching – why not? Or at least make interfaces for HTML and URL helpers.
  • 58. Thanks to Simone Chiaretta for discovering a gross oversight on my part: I’ve done my benchmarks with ASP’s debug mode turned on. With regards to ASP.NET MVC 1.0, this disables its view engine’s internal cache for resolved paths to views. This makes specifying full paths to view irrelevant as far as performance is considered. So, the following change won’t yield any performance yield with the debug attribute set to false (Web.config, compilation section).
  • 59. All of the benchmarks have been re-run with debug turned off, the change before any optimizations have taken place is significant (6 req/s to 8 req/s). Any other changes to the performance due to the release mode other than view path resolving were basically non- existing or within the margin of error. You can read Simone’s post at http://codeclimber.net.nz/archive/2009/04/22/how-to-improve- htmlhelper.renderpartial-performances-donrsquot-run-in-debug-mode.aspx And, of course, run your production websites in release mode. :)