文章目录
  1. 1. 从侯捷老师的池内春秋谈起
  2. 2. socket需要用到池的概念吗?
  3. 3. 池的数据结构

侯捷老师的池内春秋谈起

记得侯捷老师的经典文章《池内春秋》讲的是内存池,由于当时内存价格昂贵,被称为是“CPU之外最宝贵的电脑硬件资源”,当我们直接使用new、malloc等API申请分配内存,缺点就是:由于所申请内存块的大小不定,当频繁使用时会造成大量的内存碎片并进而降低性能,所以需要使用使用内存池来解决这个问题。

然而时过境迁,内存昂贵的时代早就一去不复返,但是问题依然存在,只不过从内存分配转移到了文件IO上,现如今服务器的性能瓶颈就是文件IO,于是乎以前处理内存的技术—-池,又有了用武之地,可见,很多技术都是旧瓶装新酒。

我两个月之前曾近实现了mysql和redis的连接池DBPool,代码中加上了大量注释,而且在我的CSDN博客当中写了一系列博文来分析这个池的设计。在博文的最后,我说道:接下来我想实现一个socket连接池,进而来深入复习网络编程。如今,SocketPool已经完成了。

我在我的csdn博客 数据库连接池DBPool(一):简介 当中概述了池作为中间件解决了什么问题:

  • 1,性能的提升:数据库连接是一种极耗系统资源的操作,尤其是在多层结构的应用环境中,这种资源的耗费对系统性能影响尤为明显。我实习的时候,部门经理告诉我,框架性能的压力大部分集中在数据库的IO上,这是在他review我的代码的时候说的,当时我写的数据库接口访问Mysql,本来可以一条SELECT语句查询出结果,再使用循环将结果写入到vector当中,但是我却是在循环当中使用了SELECT语句,导致了多次查询。经理告诉我相同功能的查询语句,由于打开关闭数据库连接的次数不同导致两个查询语句耗费的时间差别很大。

  • 2,内存碎片(memory fragmentation)的问题,这个是对于内存池来说的。

  • 3,线程池,减少线程创建的开销,而且在请求到达时候线程已经存在了,所以无意中也消除了线程创建所带来的延迟。这样,就可以立即为请求服务,使应用程序响应更快。

socket需要用到池的概念吗?

实际上socket连接需要用到池的地方不多,相比数据库连接池,有很多程序员同时在同一个数据库上做操作,创建和删除数据库连接的开销很大,原因就在于对于数据库来说,我们是客户端,我们不能改数据库的代码(当然geek另说),为了快速响应,当然需要创建池。同样的,socket客户端才更加需要池的概念,而作为服务器,有很多的方案比使用池更加好,比如成熟的模型one loop per thread,就能提供高并发。所以池的概念是相对于客户端来说的,服务器用池来创建多个监听其实没有用。而且就算对于客户端来说,以我的经验:很多公司就是需要用连接的地方直接创建一个tcp长连接就可以了,创建那么多的连接放在池里面反而不好。

长连接和短连接
短连接是指socket连接后发送后接收完数据后马上断开连接。
长连接的概念与短连接相对,指在一个连接上可以连续发送多个数据包,就是在传输完数后不关闭连接,而不断的发送包保持连接等待处理下一个数据包。
使用
netstat –inet | grep 9999
查看9999端口上的长连接

由于每次连接都需要TCP三次握手,这需要时间,所以使用长连接,而不是频繁创建短连接有助于提高速度。数据库的连接用长连接,如果用短连接频繁的通信会造成socket错误,而且频繁的socket 创建也是对资源的浪费。而像WEB网站的http服务一般都用短链接,因为长连接对于服务端来说会耗费一定的资源,而像WEB网站这么频繁的成千上万甚至上亿客户端的连接用短连接会更省一些资源

所以这次在我的gtest的测试代码当中,我只是意思一下,写了连接池的测试代码。而我最近学习的真正重点在于one loop per thread事件驱动这两个东西,当然,我也在gtest目录下给出了我的代码:也就是服务器使用one loop per thread事件驱动来解决C10K problem(当然现在的企业的要求是C1000K problem, C10k problem已经过期了),而客户端是拿来测试服务器用的,就是同时启动多个客户端,查看服务器能否承受压力。

池的数据结构

那么用什么数据结构来实现池呢?我觉得具体情况需要具体分析,比如说我最常用的STL是map,比vector还常用,但是我在实现DBPool的时候存储数据库连接使用的是list。因为考虑到了listpoppush_back的开销比mapfind要小。(list取出连接的时候用pop,map取出连接需要查找一下second来判断这个key是否可用)

但是socket连接池使用list反而不好,因为数据库可以指定一个专门的数据库服务器,然后我们写的代码使用高并发,使用多个mysql连接的话,反正都是连接到这一台mysql服务器上面,所以每个连接都可以是一样的。但是socket本来就是要与多个服务器通信才设计出来的,换句话说,就是每个连接都不一样,使用多个socket连接的话,我怎么知道哪个连接能连接到哪台服务器?虽然可以通过连接的函数getsockname来得到,但是我想要根据ip地址和端口号来寻找到连接的话,使用list就需要遍历整个list了,而使用map则不需要这种操作。

在根据ip地址和端口号查找连接的时候,使用了小技巧。我把ip地址和端口号整合成了一条string,比如”127.0.0.1###9999”,作为map的first,而second就是一个连接。所以这里使用multimap

文章目录
  1. 1. 从侯捷老师的池内春秋谈起
  2. 2. socket需要用到池的概念吗?
  3. 3. 池的数据结构