日历归档 |
|
<< < 2024 - 11 > >> | Su | Mo | Tu | We | Th | Fr | Sa | | | | | | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 |
|
|
|
About Me |
|
|
ZhangSichu |
|
Male |
|
32 |
|
ZhangSichu@gmail.com |
|
ZhangSichu@hotmail.com |
|
ZhangSichu.com |
|
weibo.com/zhangsichu |
|
|
|
个人推荐 |
|
|
|
|
分类归档 |
|
|
|
|
My Friends |
|
|
|
|
由Server Too Busy Exception看到的问题
|
有一个Asp.Net页面在访问次数增多时,就会产生Server Too Busy Exception。整个站点就被拖累死了,访问哪个页面都是这个错误。奇怪的是访问量小不会出错,访问量一大就会频繁出现这个错误。在出错的时候,打开 Task Manager 看此时的Cpu 占用率和内存的使用情况都比较正常。Cpu没有一直100%被w3wp进程占用。只有20%-30%被占用。内存也剩余了很多。为什么会出这个问题。Google和Baidu都没有找到一个比较合适的答案。只是说要优化,不要频繁使用Server.CreateObject,不去设置IIS的访问个数限制。在这个Asp.Net页面中没有调用Server.CreateObject, IIS也没有设置访问个数。真是不解为什么会出这个错误。
错误如下图:
又一次重新读了一遍代码。一开始想要解决数据库被频繁查询,在里面加了一个HashTable做为缓存。(这段程序是使用用户的IP从数据库中查询出用户所在的城市)
…… //ipAddr 用户的Ip long ipAddr = IpToLong(GetUserIp()); if(ipAddr == 0) return null; if(IpTable[ipAddr] != null) return (string)IpTable[ipAddr]; //IpTable static HashTable 缓存用户ip和城市的对应关系。 string city; object temp = GetCityFromIp(ipAddr); city = (temp == null ? "" : temp.ToString()); IpTable.Add(ipAddr, city); return city;
|
程序看起来没有什么问题。突然想起来,原来没有加HashTable做缓存,程序可以正常跑,有时候会出现数据库查询错。数据库忙,connection.Open()错。加了HashTable数据库没有错了。出现了ServerTooBusy错。应该是在用HashTable做缓存上错了。反射了HashTable。 发现 public static Hashtable IpTable = new Hashtable(); 会自动创建一个长度为11的bucket数组。bucket是一个struct结构体。
public Hashtable(int capacity, float loadFactor) { if (capacity < 0) { throw new ArgumentOutOfRangeException("capacity", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); } if ((loadFactor < 0.1f) || (loadFactor > 1f)) { throw new ArgumentOutOfRangeException("loadFactor", Environment.GetResourceString("ArgumentOutOfRange_HashtableLoadFactor", new object[] { 0.1, 1.0 })); } this.loadFactor = 0.72f * loadFactor; double num = ((float) capacity) / this.loadFactor; if (num > 2147483647.0) { throw new ArgumentException(Environment.GetResourceString("Arg_HTCapacityOverflow")); } int num2 = (num > 11.0) ? HashHelpers.GetPrime((int) num) : 11; this.buckets = new bucket[num2]; this.loadsize = (int) (this.loadFactor * num2); this.isWriterInProgress = false; }
|
当调用Add时Add会判断当前HashTable中的数据的个数,如果还有空间就会直接加入,如果没有,会调用rehash。在rehash中会有一个比较消耗空间和时间的深拷贝,就是因为反复调用putEnty,做深拷贝,重新生成HashTable,占用了很多空间和时间。
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] private void rehash(int newsize) { this.occupancy = 0; Hashtable.bucket[] newBuckets = new Hashtable.bucket[newsize]; for (int i = 0; i < this.buckets.Length; i++) { Hashtable.bucket bucket = this.buckets[i]; if ((bucket.key != null) && (bucket.key != this.buckets)) { this.putEntry(newBuckets, bucket.key, bucket.val, bucket.hash_coll & 0x7fffffff); } } Thread.BeginCriticalRegion(); this.isWriterInProgress = true; this.buckets = newBuckets; this.loadsize = (int) (this.loadFactor * newsize); this.UpdateVersion(); this.isWriterInProgress = false; Thread.EndCriticalRegion(); }
|
问题很可能就是在new HashTable时没有指定capacity,当访问量一大,HashTable被多次rehash造成的。 把原来的:public static Hashtable IpTable = new Hashtable(); 改成了: public static Hashtable IpTable = new Hashtable(30000); 问题解决了。
小结: 估计,类似HashTable这种Collection类型的对象,内部都有这样的处理。反射了NameValueCollection。发现NameValueCollection内部自己保存了一个HashTable和一个Array。ArrayList的Capacity 属性在被Set的时候也会做类似的处理。 在进行new操作,产生对象的时候,最好预估算一下可能的大小,减少内部做rehash或resize的操作,从而提升性能。或者使用基于链表式的存储对象,在进行添加操作的时候,只操作节点引用,不进行类似resize的操作。.Net 2.0中的SortedDictionary 是一个不错的选择,它内部使用树结构存储数据,实现了类似于红—黑树的数据结构。
|
|
#re:由Server Too Busy Exception看到的问题 3/20/2008 12:57:16 PM 天使相思
|
|
#re:由Server Too Busy Exception看到的问题 11/29/2007 12:58:13 AM 游客
|
真诚想和贵博客交换友情链接。 火狐:http://www.huohuliulanqixiazai.com 天天基金:http://www.cnjijin.com 天天基金网:http://www.tiantianjijinwang.com
|
|
|
|
|
|