提升 Dotnetnuke 框架性能





4.00/5 (1投票)
如何分析和优化您的 dotnetnuke 网站以获得最佳性能。
引言
我多年来一直使用 Dotnetnuke 框架(版本 6.0)开发在线学习解决方案。最近,我面临了一个巨大的挑战,那就是:允许 10,000 名并发用户同时使用该系统(参加测验、学习等)。
为了实现这样的性能,我不得不深入研究 Dotnetnuke。以下是我的建议:
技巧
1. 减少 HTTP 请求次数
默认情况下,DNN 会自动包含许多样式表文件:default.css, portals.css, skin.css, ie.css 等。这很方便,但却要付出代价!所以我的解决方案是将所有这些文件合并为一个,进行最小化处理,然后放在静态服务器上。
只需在 Default.aspx.cs 文件中注释掉以下几行代码即可实现此功能。
//ClientResourceManager.RegisterDefaultStylesheet(this, Globals.HostPath + "default.css");
//ClientResourceManager.RegisterIEStylesheet(this, Globals.HostPath + "ie.css");
//ClientResourceManager.RegisterStyleSheet(this, ctlSkin.SkinPath + "skin.css", FileOrder.Css.SkinCss);
//ClientResourceManager.RegisterStyleSheet(this, ctlSkin.SkinSrc.Replace(".ascx", ".css"), FileOrder.Css.SpecificSkinCss);
然后将合并后的样式表放在 Default.aspx 文件的顶部。
2. 减少 DOM 元素的数量
众所周知,80% 的最终用户响应时间花在前端,所以请尽可能地最小化您的 DOM 元素。
在 DNN(6.0 或更高版本)中,模块是通过 DIV 结构(大约 4 个嵌套的 DIV
)注入到皮肤中的,以确保布局处于正确的状态。在包含许多模块的页面中,会生成大量冗余的 DIV
。
我的建议是尽可能地将用户控件直接放在皮肤中。
例如:与其创建一个“菜单模块”并将其注入到 HeaderPane
,我只是声明 usercontrol
<%@ Register TagPrefix="ctl" TagName="MENU" Src="~/DesktopModules/YourPath/Menu.ascx" %>
然后,像这样直接将其放在皮肤中
<div class="wrapper">
<ctl:MENU ID="ctlMenu" runat="server"></ctl:MENU>
<div class="clear"></div>
<div class="container-fluid">
...
此外,上述“经典样式”可以减少数据库命中次数,因为无需从数据库加载模块。
请记住
- 将页面上的 DNN 模块数量保持在最低限度。
- 不要在前台使用 Rad 控件,如
RadTreeview
(它会产生大量的 DOM)- 这只是我的观察。
3. 将组件拆分到无 Cookie 的域上
将您的所有 CSS、JS、字体、Flash、图片等文件放在几个无 Cookie 的域上(2-4 个域以减少 DNS 查找)。考虑使用 CDN 来更有效地向用户提供内容。
4. 使用 Gzip 压缩
请务必使用 Gzip 压缩。在 DNN 6.0 及更高版本中,Gzip 功能被省略了,因此请改用 IIS 压缩。
这里是一个实现此目标的绝佳链接。
5. 分离用户数据和源代码
“~/Portals/0”是大多数开发人员存放用户数据(图片、视频、Flash 等)的地方。
不要这样做。这会使您以后难以维护,并且您无法从使用静态域或 CDN 网络中获益。
尝试通过使用虚拟目录(指向不同的 SAN 位置)来分离您的用户数据,然后您就可以在该数据上部署任何您想要的东西(无 Cookie 域、跨分布式服务器同步等)。
Simpy use Server.MapPath("/DATA") to get the desired path.
Rad 控件自 2009 年起就已集成到 DNN 中,开发人员通常通过 DNN 包装器来使用这些控件。
这些 DNN Rad 控件不理解虚拟路径,我必须让它们理解。以下是 RadEditor 的解决方案:
1. 注册 Rad 控件
<%@ Register TagPrefix="telerik"
Namespace="Telerik.Web.UI" Assembly="Telerik.Web.UI" %>
声明
<telerik:RadEditor id="radContent"
Width="100%" runat="server" Height="500px"></telerik:RadEditor>
2. 在 web.config 中注册处理程序
在 <system.webServer>
部分的 <handlers>
下,为 RadEditor 注册 DialogHandler
<add name="Telerik.Web.UI.DialogHandler" path="Telerik.Web.UI.DialogHandler.aspx" verb="*" type="Telerik.Web.UI.DialogHandler, Telerik.Web.UI" />
3. 分配路径
radContent.ImageManager.ViewPaths = New String() {"/DATA/path1", "/DATA/path2"}
radContent.ImageManager.UploadPaths = New String() {"/DATA/path1", "/DATA/path2"}
6. 优化 Dotnetnuke 配置
互联网上有许多资源讨论如何正确配置您的 DNN 网站。在这个小提示中,我只想强调一些要点:
- 将缓存设置选项设置为 Heavy:这将通过将所有页面、模块等缓存到内存中来提高性能。
- 页面状态持久性:对于小型网站,请使用 Memory 选项。对于大型复杂的网站,使用 Memory 选项可能会导致一些意外错误。请考虑使用 Page 选项,或者您需要自己构建缓存机制。
- 调度程序:将调度程序模式更改为 Timer Method,并禁用任何不需要的计划。
- 事件日志:在不需要时禁用日志记录。
- 调试模式:禁用调试模式(通过在 web.config 中将
Debug="False"
)。
7. 调优代码
- 当我使用 ANTS Profiler 查看系统内部情况时,我发现每次调用
UserInfo
实例时 DNN 都会命中数据库(我不知道为什么 DNN 不缓存它)。
我的解决方案是开发一个 Redis 缓存机制来存储所有用户、角色、我们的专业表等。 - 另一点是:尽可能在 ASP.NET 控件中设置
EnableViewstate="False"
。仅在需要从回发事件中获取控件值时将其设置为True
。这将大大减少渲染到客户端的流量。 - 始终使用
SqlHelper
类访问数据库:它确保每次与 SQL Server 的连接都能正确关闭。
8. 调优 SQL 存储过程
使用 SQL Profiler 和 Tuning Adviser 来分析您的存储过程并对其进行优化。
尝试读取查询执行计划以实现最佳性能。
9. 使用缓存服务器
如上所述,尽量减少数据库命中次数。缓存服务器是最佳选择。考虑使用 Redis 或 Memcached(我正在使用 Redis)。如果您使用集群服务器,这一点尤其有用。
即使应用程序服务器重新启动,缓存仍然存在!
10. 使用 SQL 会话服务器
出于一致性的原因,使用 SQL 会话服务器。
使用的工具
- ANTS Profiler
- SQL Profiler & SQL Tuning Adviser
关注点
以上提示是我在使用 DNN 框架部署我的在线学习解决方案时发现有用且与其他不同的地方,希望对您有所帮助。
历史
- 2014 年 10 月 2 日:初始版本