如题,网站增加个统计ip的功能,于是有了如下代码:
每有一个ip访问,都会执行一次Count方法。
在一分钟500ip的时候,IIS就反应不过来了,CPU占用100%,求优化啊
(不含有数据库操作)
public static readonly List<IPLog> IPList = new List<IPLog>(); public void Count(xxxxx) { var log = new IPLog() { IP = ip, VisitTime = DateTime.Now }; IPList.Add(log); if (IPList.Count >= 1000) { var clone = ipList.GetRange(0, IPList.Count); IPList.Clear(); //保存到数据库(clone) //每1000IP提交到数据库一次
//已注释 } }
多谢各位,确实不是这个代码的问题。找到一个问题,稍微缓解了一下,虽然CPU也很高,但还可以接收,是因为Unity有一个特殊的注入,采用的反射的方法占用了资源。
如果就你给的这些代码,速度不会慢的,而且都是1000IP才会提交数据库了,那更没理由慢了。
嗯,是啊,想不明白,也不知道从哪里下手分析
@wdwwtzy: 不确定哪里影响了速度的话,你可以为几个可能影响速度的方法提供计时,将计时结果保存到日志文件里。虽然日志记录本身会有速度影响,但是对分析问题很有用。
@wdwwtzy:
明白了,你把方法写成静态的,不然的话,你这样没一个ip都要创建一个对象?用线程安全的集合,采用多线程+异步来处理,
线程池呀 什么滴 你看一下就能用,开启并行 我就不信 他还会死机?
可以使用一个缓存数据库,比如使用MongoDB,没一条写一次
每日同步MongoDB to SQL SERVER
如果你不能确定CPU被谁占用的话,用2-3个DUMP分析下,哪些线程占用CPU时间多。
sorry 不太清楚如何做,可否给些资料?
@wdwwtzy: 博客园里有:http://www.cnblogs.com/juqiang/archive/2008/01/11/1035689.html
@wdwwtzy: 这个工具应该用起来简单:Debug Diagnostics Tool.可以使用Add Rule 的 Performance,也可以到Processes列表中抓DUMP,然后使用Advanced Analysis来分成报告,一般来说一眼就能看出占用CPU高的线程。如果看不出来,就把DUMP文件交给WinDBG分析,分析方法看上面那篇博文。
@Launcher: 多谢,我试试
你都没找到速度慢的原因在哪,这叫怎么优化 ,另外 你给的这段代码 你都可以自己写个测试程序 循环几百次 来测试
另外说一句,你这段代码不安全,多线程存在危险 改进一下吧,省的以后麻烦
多谢,我这样lock行不?
..... ..... lock(xxx) { IPList.Add(log); .... }
@wdwwtzy:
你的问题还没有根本解决 ,线程问题最好用c#的线程安全集合,开启并行
用缓存,不一定非要使用Redis,Mongdb等等缓存数据库,可以使用.net自带的缓存进行一些常用数据的缓存。
1.数据库方面要对常用Sql语句进行存储过程处理。
2.常用数据,比如排名等等信息进行缓存,避免重复计算。
3.优化程序。
4.对常用数据表加上索引。
5.进行数据库读写分离。
6.对网站做CDN加速,不过要花钱的。
7.如果有记日志的话,将日志表从业务数据库中分离出来。日志记录是一个消耗性能。可以参考使用Log4Net来进行日志记录。
8.尝试使用redis或者mongdb来对常用数据进行缓存。
9.优化系统架构,避免不必要的分层。
10.对大数据表做表分区处理,可以分散压力。
11.使用工具找到网站或者系统的压力点,然后对症下药。祝你好运。
每有一个ip访问,都会执行一次Count方法
这么做不对。给你几个建议:
1. 定义一个静态的字典ConcurrentDictionary<string, IPLog>,字典的key是ip(string类型),value是 IPLog 类型。不要使用List<IPLog>,它是非线程安全的,会引起数据错误。
2. 每有一个新的请求过来,就往1中的字典里加入(或者已经存在了就不加入)当前请求的ip信息,这样新的请求很快就处理完了。而不是你之前的做法,“有可能”要执行很长时间(写数据库什么的)
3. 在Application_Start方法里启动一个新线程,这个线程每过n分钟(例如5分钟)就把1中的字典的信息写到数据里去(当然你也可以不立刻写,而是检查数目,等有了5000再写)
添加 IPList, 和添加数据库,清空 IPList 用线程分开操作
最奇怪的,就是楼主的这段代码没有加锁就访问了静态的字段。
if (IPList.Count >= 1000) { var clone = ipList.GetRange(0, IPList.Count); IPList.Clear(); //保存到数据库(clone) //每1000IP提交到数据库一次
//已注释 }
这边添加到数据库的代码,就多开个线程去完成吧
可以单独开个线程干这个。
那个线程 优先级稍稍低一点。
因为这个东西没必要实时做。 只要最后能做完就行。