Performance Tuning Technique: Ultra-Fast ASP.Net 书摘
Posted on 2012-03-11 20:36 chelsea 阅读(885) 评论(1) 编辑 收藏 举报
性能受到系统架构的巨大影响, 而本书并没有涉及在高性能做为一个必需的设计约束时有哪些典型的场景以及可选的架构方案. 本书将内容限定在具体的产品和调优技术上, 或者, 技巧上. 架构决定性能的级别, 需要尽早确定必需的性能级别.
书中提议不要把web应用看成单个application, 而是"分布式组件集合". 通常讲性能调优的书, 都是按照应用的不同层来分别讲述, 比如客户端性能, 服务端性能, 数据库调优等. 本书也不例外, 涉及HTML, ASP.Net, IIS, SQL Server等. 但实际上尽管每一层都有自己特定的问题和技巧, 手段却无外乎几类, 比如减少往返, 减少传输负载大小等.
因此我们可以试着从另一个角度来重新组织本书的几百条建议. 而这些角度是与实现技术无关的, 即使我们碰到的是不同的技术栈, 我们依然可以从这些角度出发举一反三, 得到自己的方案.
而这些新的角度可以使我们更容易看清其中的权衡和取舍, 比如减少往返和减少传输负载大小都可以提高性能, 但使用批处理等技术减少往返时往往会增加负载大小. 压缩会减少负载, 却会增加CPU负担, 等等. 而有些技术可以同时优化多个维度. 比如缓存, 它可以减少占用网络传输带宽, CPU周期和内存等所有资源.
常见的手段
- 减少往返: 缓存, 批量处理等
- 减少传输负载大小: 压缩等
- 减少不必要的处理: 延迟加载等
- 优化资源使用: 并发, 非阻塞, 异步, 使用高速资源如内存代替低速资源如磁盘等
- 选择正确工具: 为不同的任务挑选不同的工具, 挖掘手头工具合适的用法等.
- 增加计算能力: Scale Up, Scale Out, CDN等
- 提高感知性能: 优先处理高优先级内容等.
下面我们把书里的建议按照上述维度重新组织一下.
减少往返
这是对性能调优最为明显的角度. 往返通常包括客户端到服务端以及服务端到数据库. 常见的两种技术分别是缓存和批量处理. 对于HTTP Client和Server, 则还可以合并请求等, 比如js, css, image等的合并. 当然批处理和合并通常都会增加负载, 影响first experience (首次访问的体验).
- Minimize the number of different script files you’re using. If you can’t avoid having multiple files, combine them into a small number of files on the server.
- Replace spacer GIFs and text images with CSS.
- Merge multiple CSS files into one.
- Consider using CSS instead of images for transparency, borders, color, and so on.
- Consider varying CSS transparency instead of using separate rollover images.
- Consider using image maps instead of multiple images for things like menus (although a text and CSS-based menu is even better).
- Validate form fields on the client before submitting them to the server.
- Combine multiple images used on one page into a single file, and use CSS image sprites to display them.
- Leverage DHTML to avoid a server round-trip for things like showing and hiding part of the page, updating the current time, changing fonts and colors, and eventbased
- actions.
- Enable Cache-Control: max-age for your static content, with a far-future expiration date.
- Review all pages of your dynamic content, and establish an appropriate caching location and duration for them: client-only, proxies, server-side, cache disabled,
- and so on.
- Use cache profiles in web.config to help ensure consistent policies.
- If your site has a large quantity of static content, consider using a CDN to offload some of it.
- Change the name of your static files (or the folders they’re in) when you version them, instead of using query strings, so that they remain cacheable by http.sys.
- Enable output caching for your user controls, where appropriate.
- If you have pages that you can’t configure to use the output cache, consider either moving some of the code on the pages into a cacheable user control or using
- substitution caching.
- Consider precaching SQL Server data pages into RAM by issuing appropriate queries from a background thread when you can anticipate the user’s next
- request.
- If you have many images that are larger on the server than the client needs them to be, consider using a dynamic image-resizing control that resizes and caches
- them on the server before sending the smaller files to the client.
- Minimize the use of redirects. Use Server.Transfer() instead when you can.
- Structure your stored procedures to help minimize database round-trips.
- Use dynamic SQL, triggers, or cursors only when there is no other way to solve a particular problem.
- When you have to use dynamic SQL, always use it with parameterized queries.
- Use command batching, table-valued parameters, and multiple result sets to help minimize database round-trips.
- Due to its support for native async commands, command batching, multiple result sets, and table-valued parameters, you should prefer ADO.NET to ORM systems such as LINQ to SQL and the Entity Framework or NHibernate, particularly for large projects.
- Configure the network that connects your web tier with your data tier to use jumbo frames.
- Configure the network from your database servers to the local switch to use link aggregation.
减少传输负载大小
- Hide, remove, or filter comments from your HTML, CSS, and JavaScript.
- Install the Web Deployment Projects add-in for Visual Studio, and use it to run a JavaScript minifier such as jsmin to reduce the size of your JavaScript and to build
- a precompiled site for easy and fast deployment.
- Consider using CSS instead of images for transparency, borders, color, and so on.
- Consider varying CSS transparency instead of using separate rollover images.
- Use image tiling to keep your images sizes to the bare minimum, such as for backgrounds.
- Crop or resize images to the minimum size.
- Use the smaller of GIF or PNG format for lossless images, and use JPEG for complex images without sharp edges in them (such as photos).
- Increase the level of compression on JPEG images to the maximum that’s reasonable for your application.
- Use the lowest bit depth on your images that you can (8-bit images are smaller than 24-bit images).
- Specify an image’s native size or larger in an <img> tag. If you need to use a size that’s smaller than native, you should resize the source image instead.
- Remove unused and duplicate CSS classes.
- Remove unused JavaScript.
- Use script or Silverlight to generate repetitive HTML, which reduces HTML size.
- Use script or Silverlight to add repetitive strings to property values in your HTML.
- Minimize the total size of your cookies by using short names, optimized encoding, merging multiple cookies into one, and so on.
- Group pages and other content that need cookies into a common folder hierarchy, to help optimize the cookie path setting.
- Optimize your CSS by merging and sharing class definitions, leveraging property inheritance, eliminating whitespace, using short specifiers, property cascading, and so on.
- Disable ViewState by default at the page level. Only enable it on pages that post back and where you explicitly need the functionality it provides.
- Create and use a custom template in Visual Studio that disables ViewState, disables AutoEventWireup, and sets a base class for your page, if you’re using one.
- Configure IIS to remove the X-Powered-By HTTP header.
- Install an HttpModule to remove the Server and ETag HTTP headers.
- Modify your web.config to remove the X-Aspnet-Version HTTP header.
- Enable site-wide static file compression.
- Add support for the deflate compression option to applicationHost.config.
- Specify staticCompressionLevel="10" and dynamicCompressionLevel="5" in applicationHost.config.
- Turn off the feature that disables compression if the server’s CPU use exceeds a certain threshold.
- Modify applicationHost.config to allow the <urlCompression> tag to be specified in web.config.
- Use the <urlCompression> tag in web.config to selectively enable dynamic compression.
- Enable dynamicCompressionBeforeCache so that your content is cached after it’s compressed rather than before.
- Use short strings for control IDs, because the strings can appear in your HTML.
- Consider using control adapters to help optimize generated HTML.
- Use whitespace filtering to minimize the size of your HTML (although you must disable dynamicCompressionBeforeCache if you do).
减少不必要的处理
- Use lowercase for all your URLs.
- Use a single, consistent URL for each resource, with matched case and a single domain name.
- Use lowercase HTML tags and property names.
- Include a <!DOCTYPE> tag at the top of your HTML.
- Check Page.IsPostBack to see whether you can avoid repeating work that is already reflected on the page or stored in ViewState.
- Before performing any time-consuming operations on a page, check the Response.IsClientConnected flag to make sure the client still has an active network connection.
- Disable debug mode for the version of your site that runs in production.
- Group multiple INSERT, UPDATE, and DELETE operations into transactions to help minimize database log I/O pressure.
- Optimize the data types you choose for your tables; prefer narrow, alwaysincreasing keys to wide or randomly ordered ones.
- Avoid using wildcards in your XML queries.
- Set a large enough file size for your database data and log files that they should never have to autogrow.
- Don’t shrink or autoshrink your database files.
- Minimize the number of different databases you need.
- Deploy your web site in precompiled form.
- Don’t enable submit buttons until all form fields are valid.
- Use script to avoid or delay submitting a form if the new parameters are the same as the ones that were used to generate the current page.
优化资源使用
这是一个很大的主题. 但目的只有一个, 压榨计算资源消除瓶颈避免浪费. 而可以利用的资源除了带宽, CPU, 内存, 还有时间. 常见的模式有并发, 异步等. 尽量使用高速资源比如内存, 减少慢速资源使用如磁盘IO. 用非阻塞操作代替阻塞操作.
有一种资源分配策略也很常见, 但经常被忽略, 就是区分用户群体, 按其重要性分配不同资源. 比如企业的CRM系统通常有两类用户: 企业客户和企业自己的员工. 他们共享企业的计算资源, 但为保证企业客户的体验, 其资源分配应向客户倾斜.
- Put one or more requests for resources in the first 500 bytes of your HTML.
- Use from two to four subdomains to optimize parallel loading of your static files.
- Try to start a request for one image or CSS file before loading a script file from the same domain so that the requests happen in parallel.
- Reference your static content from subdomains that never use cookies.
- Use Ajax to make partial-page updates.
- Use asynchronous pages for all pages that do I/O, including accessing the database, web service calls, filesystem access, and so on.
- Add a background worker thread to your application, and use it for tasks that don’t have to be executed in-line with page requests, such as logging.
- Because HttpModules run in-line with every request, try to offload long-running tasks (such as logging to a database) onto a background worker thread when you can.
- Use an async HttpModule or HttpHandler if your code needs to access the database or do any other I/O.
- Avoid caching content that is unique per user.
- Avoid caching content that is accessed infrequently.
- If you’re using multiple AppPools, consider using WSRM to help ensure optimal resource allocation between them when your system is under load.
- Use Log Parser to check your IIS logs for HTTP 404 Not Found errors and other similar errors that may be wasting server resources.
- Consider using IIS bandwidth throttling to help smooth the load on your servers, particularly during peak periods.
- Modify the <applicationPool> section in your Aspnet.config file to reflect the load you anticipate on your servers.
- Use code rather than the runtime to enforce concurrency limits where the load on a remote system is an issue, such as with some web services.
- If you have an existing site that uses synchronous calls, you’re seeing low CPU use and high request latencies, and your code is compatible with load balancing, consider temporarily using multiple worker processes while you migrate to async pages.
- If you do need session state, configure the runtime to store it in SQL Server, so that you can use load balancer.
- Make sure your database data and log files are on separate disks from one another.
- If you can anticipate the next database-related action a user will take, consider using a background thread to issue a query that precaches the data you need at the database tier.
- For sites that require consistent performance and 24 × 7 uptime, consider using table partitioning to ease ongoing maintenance issues.
- Use Resource Governor to help maintain the relative priorities of certain types of database traffic, such as low-priority logging compared to your VIP users or purchase transactions.
- For read-heavy workloads, consider using several load-balanced read-only database servers.
- Monitor the relevant Windows and SQL Server performance counters to help identify bottlenecks early and for long-term trend analysis and capacity planning.
- Partition your application into one or more AppPools, using the Integrated pipeline mode.
- Configure AppPool recycling to happen at a specific time each day when your servers aren’t busy.
- Identify client requests that are page refreshes, and limit or minimize the processing to create a new page when appropriate.
- When you use redirects, be sure to end page processing after issuing the redirect.
- For pages with long-running tasks and where Ajax wouldn’t be appropriate, consider flushing the response buffer early to help improve perceived page-load time.
- Use data paging to help limit rows displayed on a page to a reasonable number.
- Use Service Broker to offload or time-shift long-running tasks to a background thread or to a Windows Service.
- Use Service Broker to queue requests to send e-mails, rather than sending them in-line.
- Use Cache.SetVaryByCustom() for pages that vary their content based on HTTP headers such as Accept-Language.
- Use the VaryByCustom function to cache multiple versions of a page based on customizable aspects of the request such as cookies, role, theme, browser, and so on.
- Associate data that you store in Cache with a dependency object to receive a notification that flushes the cache entry if the source data changes.
- Configure cached pages that depend on certain database queries to drop themselves from the cache based on a notification that the data has changed.
- Use a cache validation callback if you need to determine programmatically whether a cached page is still valid.
- Use HttpApplicationState, Cache, and Context.Items to cache objects that have permanent, temporary, and per-request lifetimes, respectively.
选择正确工具
- Use stored procedures as your primary interface to the database.
- Optimize the indexes for your tables, including clustered vs. nonclustered indexes and including extra columns to allow the indexes to cover queries.
- Try to structure your queries and indexes to avoid table and index scans.
- Prefer full-text search to wildcard searches using the T-SQL LIKE clause.
- Consider SQL CLR for functions, types, or stored procedures that contain a large amount of procedural code or to share constants or code between your web and data tiers
- Avoid using the relational database for aggregation queries such as sums and counts; whenever possible, use SSAS for that instead.
- Download and install ADOMD.NET so that you can query your cubes from your web site.
- Use SSMS to test your MDX queries.
- Use both Visual Studio and Excel to peruse your cube and to make sure the data is organized as you intended.
- As with relational queries, be sure to cache the results of MDX queries when it makes sense to do so. Keep in mind that cubes are updated less often than your tables.
- For sites with SQL Server Standard, use SSIS and SQL Agent to automate the process of updating your cubes.
- For sites with SQL Server Enterprise, configure proactive caching to update your cubes when the relational data changes.
- Consider using a staging database in between your OLTP database and SSAS.
- Populate the staging database with SSIS, and allow it to be used for certain types of read-only queries.
- Minimize NTFS fragmentation by putting your database files on fresh filesystems by themselves.
- For filesystems where you add and delete files regularly, periodically run a disk or file defragmentation tool and use a cluster size that reflects your average file size.
- For sites with up to eight web servers, consider using NLB for load balancing. For more than eight servers, use a hardware load balancer.
- Enable Service Broker in your database.
增加计算能力
技术上的手段用完了, 还有最后一招, 花钱.
- Use the 64-bit versions of Windows Server and SQL Server.
- Make sure your database server has plenty of RAM, which can help improve caching.
- Consider using a web garden.
- To increase database write performance, add more spindles to your log volumes.
- Optimize your data volumes for read performance (IOPS) by adding more spindles.
- Make sure you have enough RAM, and add more if you don’t (helps improve read performance).
- Prefer scaling up your database servers first, before scaling out.
- Optimize your disk subsystem by using disks with a high rotation speed, narrow partitions, an appropriate RAID type, matching controller capacities with the achievable throughput, having enough drives, using a battery-backed write cache, and so on.
- Prefer SAS or SCSI drives to SATA when maximizing throughput or data reliability are important.
- Keep an eye on SSD technology; SSDs are much faster than rotating disks and may soon be stable enough to deploy in production environments.
- Consider using a SAN in environments where building and maintaining your own disk arrays isn’t practical, or where data reliability is paramount.
- Use a high-speed back-end network: at least 1Gbps, and 10Gbps if you can.
- Consider running your own DNS server or subscribing to a commercial service that provides high-speed DNS.
- Prefer DNS A records to CNAME records whenever possible.
提高感知性能
花钱也不管用, 还可以借助心理学, 包括高优先级内容优先显示. 用户的首次访问性能也是体验的重要组成部分.
- Use image slicing to improve the perceived performance of large images.
- Warm up the cache after a restart on both your web and database servers.
- If you can anticipate the next page that a user will request, use script to precache the content and DNS entries that page will use.
- Make the position of objects on the page independent of download order, with early- and late-loading techniques (load large objects as late as you can).
- Use the page onload handler to request objects that aren’t needed until after everything else on the page, such as rollover images or images below the fold.
- Enable progressive rendering on large PNG and JPEG images, to improve perceived performance.
- Prefer CSS to <table>.
- When you can’t avoid <table>, consider using <col>, and make sure to set the size properties of any images the <table> contains.
监控
书里面除了介绍了多种调优技术, 还提到部分如何诊断性能的实践, 包括各种监控
- Use custom performance counters to instrument and monitor your application.
- Minimize the different types of web and application servers that you use in your production environment. If necessary, use WSRM to help balance the load among
- different AppPools.
- Test your servers to determine how they behave under heavy load, including determining their maximum CPU use. Use that information in your capacity planning analysis.
- Enable Windows Firewall on all your servers.
- If you have access to your router, configure it to do port filtering and to protect against things like SYN floods and other DDOS attacks.
- If you aren’t using DNS as part of a failover scheme, set your default TTL to around 24 hours.
- Establish staging environments for testing both in development and in preproduction.
- Establish a deployment procedure that allows you to complete deployments quickly. It may be manual for smaller sites or automated using WDS for larger sites.
- Establish a procedure for upgrading your data tier.
- Consider deploying a system to monitor your servers proactively, such as System Center Operations Manager
- Use Failed Request Tracing to validate caching behavior and to find pages that fail or run too slowly.
- Regularly review the HTTP requests and responses that your pages make, using the Fiddler web proxy debugger.
- Make frequent use of SQL Profiler to observe the activity on your database,including the queries that your application is issuing and how long they take to run.
(本书中文版由前同事横刀天笑翻译)