SQL/MongoDB 连接并发测试
最近一直在搞mongodb 文件服务器大量文件并发上传测试,在官方文档发现mongo是线程安全的,支持单一连接下的并发操作。印象ADO.NET 似乎不支持单一连接并发。于是,测试一下来证实这个疑虑。(前两篇小记一直纠结mongodb吃内存导致并发文件上传变慢问题,经过这两天测试,发现文件并发上传越来越慢的瓶颈是磁盘的IO读写的瓶颈)
以10W条/20W条 记录写入测试,下面是测试结果
操作 | 10W w/s | 20W w/s | 操作方式 | 备注 |
1 | 79.958 | 163.396 | 主线程 有池 单连接 单打开 | 单打开指的一次open close 内执行所有写入操作 |
2 | 79.958 | 164.412 | 主线程 有池 单连接 多打开 | 多打开指的写入一次就open close一次 |
总结:可以看出有池的情况open close基本没有性能消耗。 MSDN官方解释,池的效果在minpoolsize不为零的情况, 总保持相应数量的活动连接,当Open的时候实现直接用了活动连接, 而Close操作并没close,只是又将活动连接放回池里。 |
||||
3 | 79.13 | 163.396 | 主线程 无池 单连接 单打开 | |
4 | 290.334 | 620.694 | 主线程 无池 单连接 多打开 | |
总结:无池的情况下,open close非常消耗性能,由于没池每次Open Close 都要打开关闭连接 ,所以效率没有池高。 |
||||
5 | 49.13 | 142.33 | 单线程 无池 单连接 单打开 | 异步执行反而快了?测了几次都这个结果 |
6 | 326.495 | 865.44 | 单线程 无池 单连接 多打开 | |
7 | 137.985 | 有池 单连接 单打开 10线程并行写入 写入锁 | Ado.net 不支持单连接并行写入 通过线程锁控制实现 | |
8 | 141.464 | 有池 单连接 多打开 10线程并行写入 写入锁 | Ado.net 不支持单连接并行写入 通过线程锁控制实现 | |
总结:单连接通过写入锁控制多线程写入速度明显慢了很多, 单连接并不适合并发写入操作。 |
||||
9 | 18.943 | 37.815 | 有池 10连接并行 单打开 | 相当于操作1 ---- 10个单连接 单打开 的并行操作 |
10 | 19.658 | 41.793 | 有池 10连接并行 多打开 | 相当于操作1 ---- 10个单连接 多打开 的并行操作 |
总结: 多线程并行多连接的操作效果还是很理想的,发挥了多线程任务的优势。Connection是非线安全的,也就是说最好为每个线程单独创建一个数据库连接实例是最理想的。 | ||||
可以确定的是ado.net connection 是非线程安全的 一个连接下一次open close 过程不允许并发,并且多次open close并发会相互冲突 (想并发只能通过锁来控制了,但这个不用想肯定效率不高)。
而mongodb 则在这方面具有优势, mongo是线程安全的。一个连接下是允许并行写入操作的,同样mongodb 可以多连接并发,然后每个连接下又可以多并发写入操作,这样每秒并写入记录数可以更高。mongodb的池,是预先创建指定数量的闲置连接,用到其中的连接的时候,该转为活动状态。经过这两天测试,mongodb的单连接的并行写入效率没有并行多连接写入的效率高。推测mongodb的单连接并行写入也采用了写锁或者队列,效率上可能低于多连接操作。因此在合理的并行线程内,合适的并行连接数写入很重要。
由此可见,不同的数据库池的设计理想有所不同。
而ado.net 写入并发实现只有下面两种合适的
一 有池-单连接 单打开 并发写入(引及写入锁) (锁的引入,反而导致速度下降,这个方案排除了)
二 无池-并发多连接 单打开 这种不推荐
二 有池-并发多连接 单打开/多打开 目前,测试只有这种情最理想
另外建议连接池的minpoolsize 要设置(不设置或设置为零,会在一定时间内关闭池内所有连接)但不要设置太高,否则会占用太多资源。详细可查看MSDN介绍。
在微软的Petshop以及很多开源项目曾经看到的SQLHelper此类的数据库存操作类大都是静态的? 为什么呢,因为静态方法在不引用静态字段的前提下是线程安全的。静态字段是多线程共享的,而静态方法在每个线程是都有一个副本,只要静态方法不调用静态字段则是线程安全的,因此我们看到为何SQL 单连接的情况都是使用静态方法,可以防止单连接并发操作。