那啥,最近见了一人叨叨叨的神侃如何处理高并发。居然聊到服务器矩阵。我当时还没回过神,过后细想,服务器矩阵我也知道口里说说,但是中小企业能玩得起?作为一个程序员很多时候只能用手头资源来制定优化方案。(人生哲理:要警惕夸夸其谈者)
我收集了下网上提供的处理方式列在这里。虽然我不会无聊到背下来去唬新人,但加深下映象,有个纲目还是好的。
两大点:
通过服务器处理高并发
调整服务器应用程序池中的最大连接数。
1. 调整IIS 7应用程序池队列长度
由原来的默认1000改为65535。
IIS Manager > ApplicationPools > Advanced Settings
Queue Length : 65535
2. 调整IIS 7的appConcurrentRequestLimit设置
由原来的默认5000改为100000。
appcmd.exe set config /section:serverRuntime /appConcurrentRequestLimit:100000
在%systemroot%/System32/inetsrv/config/applicationHost.config中可以查看到该设置。
3. 调整machine.config中的processModel>requestQueueLimit的设置
由原来的默认5000改为100000。
<configuration>
<system.web>
<processModel requestQueueLimit="100000"/>
4. 修改注册表,调整IIS 7支持的同时TCPIP连接数
由原来的默认5000改为100000。
reg add HKLM/System/CurrentControlSet/Services/HTTP/Parameters /v MaxConnections /t REG_DWORD /d 1000000
完成上述4个设置,就可以支持10万个同时请求
参见http://www.cnblogs.com/dudu/archive/2009/11/10/1600062.html
对于DB服务器同样也可以调整最大连接数来做优化。
在调整优化好最大连接数之后,就只有软硬件负载均衡了。硬件负载均衡能够直接通过智能交换机实现,处理能力强,而且与系统无关,但是价格贵,配置困难,不 能区分实习系统与应用的状态。所以硬件负载均衡适用于一大堆设备,大访问量,简单应用。软件负载均衡是基于系统与应用的,能过更好地根据系统与应用的状况 来分配负载。性价比高。PCL负载均衡软件,Linux下的LVS软件。
程序级别的并发控制:
当两个用户同时访问一个页面,一个用户可能更新的事另一个用户已经删除的记录。或者,在一个用户加载页面跟他点击删除按钮之间的时间里,另一个用户修改了这条记录的内容。
ADO.NET 和 Visual Studio .NET 中的并发控制
因为数据结构基于断开的数据,所以 ADO.NET 和 Visual Studio .NET 使用开放式并发。因此,您需要添加业务逻辑,以利用开放式并发解决问题。
如果您选择使用开放式并发,则可以通过两种常规的方法来确定是否已发生更改:版本方法(实际版本号或日期时间戳)和保存所有值方法。
版本号方法
在版本号方法中,要更新的记录必须具有一个包含日期时间戳或版本号的列。当读取该记录时,日期时间戳或版本号将保存在客户端。然后,将对该值进行部分更新。
处理并发的一种方法是仅当 WHERE 子句中的值与记录上的值匹配时才进行更新。该方法的 SQL 表示形式为:
UPDATE Table1 SET Column1 = @newvalue1, Column2 = @newvalue2 WHERE DateTimeStamp = @origDateTimeStamp
或者,可以使用版本号进行比较:
UPDATE Table1 SET Column1 = @newvalue1, Column2 = @newvalue2 WHERE RowVersion = @origRowVersionValue
如果日期时间戳或版本号匹配,则表明数据存储区中的记录未被更改,并且可以安全地使用数据集中的新值对该记录进行更新。如果不匹配,则将返回错误。 您可以编写代码,在 Visual Studio .NET 中实现这种形式的并发检查。您还必须编写代码来响应任何更新冲突。为了确保日期时间戳或版本号的准确性,您需要在表上设置触发器,以便在发生对行的更改 时,对日期时间戳或版本号进行更新。
保存所有值方法
使用日期时间戳或版本号的替代方法是在读取记录时获取所有字段的副本。ADO.NET 中的 DataSet 对象维护每个修改记录的两个版本:初始版本(最初从数据源中读取的版本)和修改版本(表示用户更新)。当试图将记录写回数据源时,数据行中的初始值将与数 据源中的记录进行比较。如果它们匹配,则表明数据库记录在被读取后尚未经过更改。在这种情况下,数据集中已更改的值将成功地写入数据库。
对于数据适配器的四个命令(DELETE、INSERT、SELECT 和 UPDATE)来说,每个命令都有一个参数集合。每个命令都有用于初始值和当前值(或修改值)的参数。
注意 由于不存在初始记录,添加新记录(INSERT 命令)只需要当前值;移除记录(DELETE 命令)只需要使用初始值来定位要删除的记录。
以下示例显示一个数据集命令的命令文本,该命令更新一个典型的客户表。该命令是为动态 SQL 和开放式并发而指定的。
UPDATE Customers SET CustomerID = @currCustomerID, CompanyName = @currCompanyName, ContactName = @currContactName, ContactTitle = currContactTitle, Address = @currAddress, City = @currCity, PostalCode = @currPostalCode, Phone = @currPhone, Fax = @currFax WHERE (CustomerID = @origCustomerID) AND (Address = @origAddress OR @origAddress IS NULL AND Address IS NULL) AND (City = @origCity OR @origCity IS NULL AND City IS NULL) AND (CompanyName = @origCompanyName OR @origCompanyName IS NULL AND CompanyName IS NULL) AND (ContactName = @origContactName OR @origContactName IS NULL AND ContactName IS NULL) AND (ContactTitle = @origContactTitle OR @origContactTitle IS NULL AND ContactTitle IS NULL) AND (Fax = @origFax OR @origFax IS NULL AND Fax IS NULL) AND (Phone = @origPhone OR @origPhone IS NULL AND Phone IS NULL) AND (PostalCode = @origPostalCode OR @origPostalCode IS NULL AND PostalCode IS NULL); SELECT CustomerID, CompanyName, ContactName, ContactTitle, Address, City, PostalCode, Phone, Fax FROM Customers WHERE (CustomerID = @currCustomerID)
请注意,九个 SET 语句参数表示将写入数据库的当前值,而九个 WHERE 语句参数则表示用于定位初始记录的初始值。
前九个 SET 语句参数对应于参数集合中的前九个参数。这些参数会将其 SourceVersion 属性设置为 Current。
接着的九个 WHERE 语句参数用于开放式并发。这些占位符对应于参数集合中接着的九个参数,这些参数的每一个都将其 SourceVersion 属性设置为 Original。
SELECT 语句用于在发生更新后刷新数据集。它是您在“高级 SQL 生成选项”对话框中设置“刷新数据集”选项时生成的。
注意 上面的 SQL 使用命名参数,而 OleDbDataAdapter 命令则使用问号 (?) 作为参数占位符。
默认情况下,如果您在“数据适配器配置向导”中选择“开放式并发”选项,Visual Studio 将为您创建这些参数。此时将由您根据自己的业务要求来添加错误处理代码。ADO.NET 提供了一个 DBConcurrencyException 对象,它返回违反并发规则的行。有关更多信息,请参见处理并发错误。
通过程序处理高并发
第一,缓存。
System.Web.Caching.Cache缓存 http://www.cnblogs.com/daizhj/archive/2007/08/15/855163.html
Memcached分布式缓存 http://www.cnblogs.com/daizhj/archive/2009/03/23/1386652.html
缓存分层(本地缓存+Memcached) http://www.cnblogs.com/daizhj/archive/2009/11/17/1604436.html
Redis架构设计 http://www.cnblogs.com/daizhj/archive/2011/02/21/1959511.html
LLServer架构设计 http://www.cnblogs.com/daizhj/archive/2011/08/26/discuznt_llserver_arch.html
跨站缓存同步 http://www.cnblogs.com/daizhj/archive/2010/06/18/discuznt_memcache_syncdata.html
小贴士
Memcached是danga.com(运营LiveJournal的技术团队)开发的一套分布式内存对象缓存系统,用于在动态系统中减少数据库负载,提升性能。具体的介绍可以参考:
Memcached深度分析
http://www.cnblogs.com/luluping/archive/2009/01/14/1375456.html
Redis
redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。
http://doc.redisfans.com/
http://www.cnblogs.com/shanyou/archive/2012/01/28/2330451.html
第二,静态文件分开布置
1.将用户上传的附件通过FTP方式传送到另外一台服务器上。http://www.cnblogs.com/daizhj/archive/2008/07/28/1254648.html
2.通过SQUID将静态文件缓存分布
使用SQUID做静态前端,将论坛中的大部分静态文件布署或外链到一个新的HTTP链接上,从而给Web服务器减压,提升性能。
http://www.cnblogs.com/daizhj/archive/2010/06/10/1692758.html
第三,负载均衡
通过以上的方案,Web服务器压力小了,性能也提升了,但是如果遇到更高的并发访问量,单台Web服务器还是不能满足需求,可以采取负载均衡的方案。
使用了LVS+KEEPALIVED、NGINX等。相关文章如下:
Discuz!NT负载均衡解决方案(HA)之---LVS(Linux Virtual Server)
http://www.cnblogs.com/daizhj/archive/2010/06/13/1693673.html
Discuz!NT负载均衡解决方案(HA)之---LVS(Linux Virtual Server)
http://www.cnblogs.com/daizhj/archive/2010/06/13/1693673.html
Discuz!NT负载均衡方案
http://www.cnblogs.com/daizhj/archive/2010/06/24/1667422.html
使用的是nginx,使用nginx作为前端负载均衡,这个确实很有吸引力,有时间能试用下就好。
第四,缓解数据库压力
Discuz!NT数据库读写分离方案
http://www.cnblogs.com/daizhj/archive/2010/06/21/dbsnap_master_slave_database.html
全文搜索方案:
Discuz!NT企业版之Sphinx全文搜索(上)
http://www.cnblogs.com/daizhj/archive/2010/06/28/discuznt_entlib_sphinx_one.html
Discuz!NT企业版之Sphinx全文搜索(下)
http://www.cnblogs.com/daizhj/archive/2010/06/30/discuznt_entlib_sphinx_two.html
处理大数据量:
Discuz!NT千万级数据量上的两驾马车--TokyoCabinet,MongoDB
http://www.cnblogs.com/daizhj/archive/2010/07/22/1781140.html
需要掌握的知识
Memcached、Redis、LLServer、SQUID、NGINX、LVS、Sphinx
有windows版本的,也有linux版本。
没有先后,程序员应该根据需要和当下条件选用。
本地测试高并发的工具
测试方法:
本地模拟测试网站高访问高并发采用的测试工具是大名鼎鼎的Loadrunner,这个工具做测试的一般都知道。在代震军的博客中,有以下几篇介绍了通过Loadrunner进行压力并发测试。
当DiscuzNT遇上了Loadrunner(上)
http://www.cnblogs.com/daizhj/archive/2009/09/25/1573926.html
当DiscuzNT遇上了Loadrunner(中)
http://www.cnblogs.com/daizhj/archive/2009/09/27/1574897.html
当DiscuzNT遇上了Loadrunner(下)
http://www.cnblogs.com/daizhj/archive/2009/09/27/1575091.html