Introduction
I've been developing E-learning Solution for years using Dotnetnuke framework (version 6.0). Recently, I faced a big challenge, that is: Allowing 10,000 concurrent users using the system at the same time (take a quiz, study and so on).
I had to dig deep into Dotnetnuke in order to achieve such performance. Below are my tips:
Tips
1. Make Fewer HTTP Requests
At default, DNN automatically includes many stylesheet files: default.css, portals.css, skin.css, ie.css, etc. It's quite convenient BUT it costs! So my solution is to combine all these files into one, minify and put it on static servers.
Just comment these below lines in Default.aspx.cs file to do the trick.
Then put the combined stylesheet at the top of Default.aspx file.
2. Reduce the Number of DOM Elements
As you know, 80% of the end-user response time is spend at the front-end, so minify your DOM element as much as possible.
In DNN (version 6.0 or above), a module is injected into skin by using DIV structure (around 4 or so nested DIV
) to make sure the layout is in a proper shape. In a page with many modules, lots of redundant DIV
s are generated.
My recommendation is placing the usercontrol directly into skin as much as possible.
For example: instead of creating a "Menu module" and injecting it into HeaderPane
, I just declare the usercontrol
:
<%@ Register TagPrefix="ctl" TagName="MENU" Src="~/DesktopModules/YourPath/Menu.ascx" %>
Then, put it directly in the skin like this:
<div class="wrapper">
<ctl:MENU ID="ctlMenu" runat="server"></ctl:MENU>
<div class="clear"></div>
<div class="container-fluid">
...
Beside, this above "classic style" can reduce database hits because there is no need for loading module from database.
Keep in mind:
- Keep the number of DNN modules on page to the minimum.
- Do not use Rad Controls like
RadTreeview
in front-end (it costs a large amount of DOM) - just my observation.
3. Split Components Across Cookieless Domains
Put all your CSS, JS, font, flash, image, etc. files across several cookieless domains (from 2-4 domains to reduce DNS look-up). Consider using CDN to deliver content more efficiently to users.
4. Use Gzip Compression
Do use Gzip compression. In DNN version 6.0 and above, Gzip feature is left out so use IIS compression instead.
Here is the great link to achieve it.
5. Separate Users' Data and Source Code
"~/Portals/0" is where most developers put users' data into (images, videos, flash, etc.).
Don't do this. It's hard for you to maintain later on and you aren't benefitting from using static domains or CDN network.
Try to separate your users' data by using Virtual Directory (pointing to different SAN locations), and then you can deploy whatever you want on that data (cookie-free domains, synchronize among distributed servers, etc.).
Simpy use Server.MapPath("/DATA") to get the desired path.
Rad controls are integrated into DNN since 2009, commonly developers use these controls via DNN wrappers.
These DNN Rad controls do not understand virtual path, I have to make them understand. Here are the solutions for RadEditor:
1. Register Rad Controls
<%@ Register TagPrefix="telerik"
Namespace="Telerik.Web.UI" Assembly="Telerik.Web.UI" %>
Declare:
<telerik:RadEditor id="radContent"
Width="100%" runat="server" Height="500px"></telerik:RadEditor>
2. Register handler in web.config
Under <handlers>
in <system.webServer>
section, register DialogHandler
for RadEditor:
<add name="Telerik.Web.UI.DialogHandler" path="Telerik.Web.UI.DialogHandler.aspx" verb="*" type="Telerik.Web.UI.DialogHandler, Telerik.Web.UI" />
3. Assign path
radContent.ImageManager.ViewPaths = New String() {"/DATA/path1", "/DATA/path2"}
radContent.ImageManager.UploadPaths = New String() {"/DATA/path1", "/DATA/path2"}
6. Optimize Dotnetnuke Configuration
There are many resources on the internet talking about how to configure your DNN site properly. In this small tip, I just want to emphasize some:
- Set Cache Setting option to Heavy: This will boost your performance by caching all your page, module, etc. to memory.
- Page State Persistence: Use Memory option for just small site. For big and complicated site, using Memory option may lead to some unexpected errors. Consider using Page option or you have to build a caching mechanism on your own.
- Scheduler: Change Scheduler Mode to Timer Method and disable any schedule if not needed.
- Event Log: Disable logging when not needed.
- Debug mode: Disable debug mode (by setting
Debug="False"
in web.config)
7. Tuning the Code
- When I use ANTS Profiler to see what is going on under the system, I find DNN hit database everytime I call
UserInfo
instance (I don't know why DNN does not cache it).
My resolution is developing a Redis cache mechanism to store all users, roles, our professional tables, etc.
- Another point is:
Set EnableViewstate="False"
in ASP.NET controls as much as possible. Just be True
when we need to get the value from the control in postback event. This will reduce much traffic rendering to client.
- Always use
SqlHelper
class to access database: It ensures every connection to SQL server is closed properly.
8. Tuning SQL Stored Procedures
Use SQL Profiler and Tuning Adviser to analyse your stored procedures and optimize them.
Try to read Query Execution Plan in order to achieve best performance.
9. Use Cache Server
As mentioned above, try to reduce hits to database. Cache server is the best choice. Consider using Redis or Memcached (I'm using Redis). It's especially useful in case you use clustered servers.
In case Application servers are restarted, the cache is still there!
10. Use SQL Session Server
Use SQL session server because of its consistency.
Tools to Use
- ANTS Profiler
- SQL Profiler & SQL Tuning Adviser
Points of Interest
The above tips are what I find it useful and different from the others' when I deployed my Elearning Solution using DNN framework, so I hope it would help you a bit.
History
- 2nd October, 2014: Initial version