04_连接池

在这里插入图片描述

在使用三方客户端进行网络通信时,我们首先要确定客户端SDK是否是基于连接池技术实现的。我们知道,TCP是面向连接的基于字节流的协议:

  • 面向连接,意味着连接需要先创建再使用,创建连接的三次握手有一定开销;
  • 基于字节流,意味着字节是发送数据的最小单元,TCP协议本身无法区分哪几个字节是完整的消息体,也无法感知是否有多个客户端在使
    用同一个TCP连接,TCP只是一个读写数据的管道

如果客户端SDK没有使用连接池,而直接是TCP连接,那么就需要考虑每次建立TCP连接(3次握手)的开销,并且因为TCP基于字节流,在多线程的情况下对同一连接进行复用,可能会产生线程安全问题
在这里插入图片描述

我们先看一下涉及TCP连接的客户端SDK,对外提供API的三种方式。在面对各种三方客户端的时候,只有先识别出其属于哪一种,才能理清楚
使用方式。
1,连接池和连接分离的API:有一个XXXPool类负责连接池实现,先从其获得连接XXXConnection,然后用获得的连接进行服务端请求,
完成后使用者需要归还连接。通常,XXXPool是线程安全的,可以并发获取和归还连接,而XXXConnection是非线程安全的。对应到连
接池的结构示意图中,XXXPool就是右边连接池那个框,左边的客户端是我们自己的代码。
2,内部带有连接池的API:对外提供一个XXXClient类,通过这个类可以直接进行服务端请求;这个类内部维护了连接池,SDK使用者无需
考虑连接的获取和归还问题。一般而言,XXXClient是线程安全的。对应到连接池的结构示意图中,整个API就是蓝色框包裹的部分。
3,非连接池的API:一般命名为XXXConnection,以区分其是基于连接池还是单连接的,而不建议命名为XXXClient或直接是XXX。直接连
接方式的API基於单一连接,每次使用都需要创建和断开连接,性能一般,且通常不是线程安全的。对应到连接池的结构示意图中,这种
形式相当于没有右边连接池那个框,客户端直接连接服务端创建连接。

1,如果是分离方式,那么连接池本身一般是线程安全的,可以复用。每次使用需要从连接池获取连接,使用后归还,归还的工作由使用者负
责。
2,如果是内置连接池,SDK会负责连接的获取和归还,使用的时候直接复用客户端。
3,如果SDK没有实现连接池(大多数中间件、数据库的客户端SDK都会支持连接池),那通常不是线程安全的,而且短连接的方式性能不会
很高,使用的时候需要考虑是否自己封装一个连接池。

Jedis的API实现是我们说的三种类型中的第一种,也就是连接池和连接分离的API, JedisPool是线程安全的连接池,Jedis是非线程安全的单一连接。
而Apache HttpClient是内置连接池的API。

**连接池的配置不是一成不变的**
连接池提供了许多参数,包括最小(闲置)连接、最大连接、闲置连接生存时间、连接生存时间等。 其中,最重要的参数是最大连接数,它决定了连接池能使用的连接数量上限,达到上限后,新来的请求需要等待其他请求释放连接。

最大连接数不是设置得越大越好。如果设置得太大,不仅仅是客户端需要耗费过多的资源维护连接,更重要的是由于服务端对应的是多个客户端,每一个客户端都保持大量的连接,会给服务端带来更大的压力。这个压力又不仅仅是内存力,可以想一下如果服务端的网络模型是
一个TCP连接一个线程,那么几千个连接意味着几千个线程,如此多的线程会造成大量的线程切换开销。
当然,连接池最大连接数设置得太小,很可能会因为获取连接的等待时间太长,导致吞吐量低下,甚至超时无法获取连接

数据库设置最大连接数
在真实情况下,只要数据库可以承受,你可以选择在遇到连接超限的时候先设置一个足够大的连接数,然后观察最终应用的并发,再按照实际并发数留出一半的余量来设置最终 的最大连接。
总结
对于使用姿势其实就是两点,一是确保连接池是复用的,二是尽可能在程序退出之前显式关闭连接池释放资源。连接池设计的初衷就是为了保 持一定量的连接,这样连接可以随取随用。从连接池获取连接虽然很快,但连接池的初始化会比较慢,需要做一些管理模块的初始化以及初始 最小闲置连接。一旦连接池不是复用的,那么其性能会比随时创建单一连接更差。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章