项目介绍
开源项目:gitee.com/xungen/redi…
实现一个简单易用的Redis客户端,自带连接池。
一个redis客户端线程通过从连接池获取一个连接对象来访问redis服务器,发送Redis命令和接收redis命令的回复。一个连接可以收发多条命令,由于Redis服务器的并发能力较强,一个连接对象可以处理多个redis命令的请求。
连接池维护了多个连接对象,避免了当多个线程同时访问redis服务器需要依次排队等待连接对象的现象,提高了系统的并发性能,避免了连接对象被过度占用而导致的性能瓶颈问题。
同时,连接池考虑到了连接对象的复用和回收,避免资源浪费和内存泄露等问题。
在RedisConnect项目中,连接池中维护的连接是指和Redis服务器的连接。一个连接可以调用多条命令,而不是仅限于一条命令。 在RedisConnect中,连接池中维护的连接对象可以被多个线程共享。不同的线程可以通过获取连接对象来访问Redis服务器,发送Redis命令和接收Redis命令的回复。由于Redis服务器的并发能力较强,因此一个连接对象可以同时处理多个Redis命令的请求,不需要为每个Redis命令单独创建连接对象。 在RedisConnect中,需要多个连接的原因主要是为了保证系统的并发性能。当多个线程同时访问Redis服务器时,如果只有一个连接对象,那么这些线程就需要依次排队等待连接对象,从而降低了系统的并发性能。因此,在RedisConnect中,通过维护多个连接对象,可以提高系统的并发性能,同时也避免了连接对象被过度占用而导致的性能瓶颈问题。 需要注意的是,为了保证连接对象的稳定性和有效性,RedisConnect中使用了连接池的设计思想,对连接对象进行有效的管理和分配。连接池中维护了一定数量的连接对象,并对连接对象进行复用和回收,以避免资源浪费和内存泄漏等问题。同时,RedisConnect中还考虑了连接状态的检测,保证了连接的稳定性。
项目优点: 高效性:redisConnect使用了连接池来管理Redis连接对象,避免了频繁的连接和断开操作,提高了效率。同时,redisConnect使用了RESP协议来与Redis服务器进行通信,具有高效、简单和可扩展等特点。
可扩展性:redisConnect使用了C++语言和Boost库,具有良好的可扩展性和可维护性,可以方便地添加新功能和接口。
易用性:redisConnect提供了丰富的接口和功能,可以方便地连接Redis服务器、执行Redis命令和获取命令回复数据,同时采用了面向对象的设计思想,提高了代码的可读性和可维护性。
可靠性:redisConnect使用了智能指针和异常处理等技术,可以有效地避免内存泄漏和程序崩溃等问题,提高了代码的稳定性和可靠性。
环境:Linux
参考
(50条消息) 什么是池化技术_风神修罗使的博客-CSDN博客
1. 连接池
池化技术: 池化技术 (Pool) 是一种很常见的编程技巧,在请求量大时能明显优化应用性能,降低系统频繁建连的资源开销。我们日常工作中常见的有数据库连接池、线程池、对象池等,它们的特点都是将 “昂贵的”、“费时的” 的资源维护在一个特定的 “池子” 中,规定其最小连接数、最大连接数、阻塞队列等配置,方便进行统一管理和复用,通常还会附带一些探活机制、强制回收、监控一类的配套功能。
进程池/线程池: 线程池的原理很简单,类似于操作系统中的缓冲区的概念,它的流程如下:先启动若干数量的线程,并让这些线程都处于睡眠状态,当需要一个开辟一个线程去做具体的工作时,就会唤醒线程池中的某一个睡眠线程,让它去做具体工作,当工作完成后,线程又处于睡眠状态,而不是将线程销毁。
连接池:
数据库连接池的基本思想是在系统初始化的时候将数据库连接作为对象存储在内存中,当用户需要访问数据库的时候,并非建立一个新的连接,而是从连接池中取出一个已建立的空闲连接对象。在使用完毕后,用户也不是将连接关闭,而是将连接放回到连接池中,以供下一个请求访问使用。这些连接的建立、断开都由连接池自身来管理。
同时,还可以设置连接池的参数来控制连接池中的初始连接数、连接的上下限数和每个连接的最大使用次数、最大空闲时间等。当然,也可以通过连接池自身的管理机制来监视连接的数量、使用情况等。
redis连接池功能:有效减少Redis客户端与服务器建立连接的开销,提高应用程序性能和可拓展性。
redis连接池用法:应用程序启动时,初始化一定数量的redis连接存储再连接池中。当需要连接服务器时,从连接池中取出一个可用链接。使用连接执行redis命令,使用完成后需归还连接
- 若连接池中没有可用连接:等待/抛出异常 /创建新的连接
- 连接超时:长久未被使用则认为该链接失效,移除并关闭。以便在连接空闲一段时间后自动关闭连接,以避免资源浪费。
- 连接复用:减少连接创建和销毁,
- 连接池大小控制:最大连接数和最小连接数
连接池中连接对象资源的管理:共享型智能指针
共享型智能指针是一种智能指针,可以共享指针指向的对象,多个共享型智能指针可以同时指向同一个对象,当没有智能指针指向该对象时,该对象会自动被释放。
维护一个共享型智能指针,可以使得连接池中的连接对象得到合理的管理和分配,以避免资源浪费和内存泄漏等问题。
- 实现连接对象在多个线程间共享:redis客户端是一个多线程应用程序,不同的线程需要共享连接对象来实现对redis服务器的访问。
- 避免内存泄露:保证连接对象的正确释放。连接对象不再被使用时,内部技术为0,连接对象自动被释放
在实现Redis连接池时,需要考虑以下因素: 连接数量:连接池中的连接数量应该根据应用程序的需要进行调整,以便在高负载情况下能够满足请求。 连接超时:连接池应该设置一个连接超时时间,以便在连接空闲一段时间后自动关闭连接,以避免资源浪费。 连接复用:连接池应该尽可能复用连接,以减少连接创建和销毁的开销。 连接监控:连接池应该监控连接的状态,以便在连接出现异常时能够及时处理 创建连接的目的是为了建立与Redis服务器的连接,以便发送Redis命令和接收Redis命令的回复。在RedisConnect中,通过连接池来管理连接对象,避免了频繁的连接和断开操作,提高了效率。连接池中的连接对象可以被多个线程共享,避免了资源浪费和Redis服务器负载过高的问题。因此,创建连接是RedisConnect项目中的一个重要操作,确保了连接的有效性和稳定性。 通过连接池的设计,RedisConnect实现了连接的复用,避免了频繁的连接和断开操作,提高了效率。同时,RedisConnect还考虑了连接状态的检测,保证了连接的稳定性。
Redis链接池的实现原理通常包括以下几个方面:
- 预先创建Redis连接:在Redis链接池初始化的时候,会预先创建一定数量的Redis连接,并将这些连接保存在连接池中。这样可以避免每次需要Redis连接时都要重新创建Redis连接,提高系统的性能和效率。
- 连接复用:Redis链接池会对已经创建的Redis连接进行管理和复用。当需要Redis连接时,会先从连接池中获取一个可用的Redis连接,如果连接池中没有可用的连接,则会创建新的Redis连接。
- 连接超时:为了避免Redis连接被长时间占用,Redis链接池通常会设置连接超时时间。当Redis连接超过预设的超时时间时,Redis链接池会将其关闭并从连接池中移除,以便后续的使用。
- 连接池大小控制:Redis连接池通常会设置最大连接数和最小连接数。最大连接数指连接池中最多可以存在的Redis连接数,而最小连接数指连接池中最少需要存在的Redis连接数。连接池会根据实际的需求动态调整连接数,以便资源的最优化利用
- 连接状态检测:为了保证连接池中的Redis连接可用性,Redis链接池会定时对连接池中的Redis连接进行状态检测。如果发现连接不可用,则会将其关闭并从连接池中移除。 综上所述,Redis链接池的实现原理主要包括预先创建Redis连接、连接复用、连接超时、连接池大小控制和连接状态检测等方面,通过这些机制可以提高Redis的性能和效率,同时保证连接池中的Redis连接的可用性和稳定性。
如何进行链接状态检测: RedisConnect中对连接状态的检测是通过对redisContext结构体中的err属性进行判断实现的。当err属性不为0时,表示连接状态异常,需要进行重新连接。在连接状态检测的过程中,可以通过设置timeout属性来控制连接检测的时间间隔。 如何控制连接池的大小、 RedisConnect中对连接池的大小是通过设置redisPool结构体中的maxConnections属性来实现的。在创建连接池时,可以通过传入maxConnections参数来指定连接池的最大连接数。当连接池中的连接数达到最大值时,后续的连接请求将被拒绝。 最大连接数:200 最小连接数:50
如何复用链接; 在RedisConnect中,复用连接是通过连接池的设计来实现的。在连接池中,连接对象是被复用的资源,可以被多次使用,避免了频繁的连接和断开操作,提高了效率。
具体来说,RedisConnect中通过维护一个空闲连接队列来实现连接的复用。当一个连接对象不再被使用时,RedisConnect会将该连接对象放入空闲连接队列中,以便下一次的连接请求可以直接使用该连接对象,避免了重新连接的开销。当有新的连接请求时,RedisConnect会先从空闲连接队列中获取一个连接对象,如果空闲连接队列为空,则会创建新的连接对象。如果获取的连接对象已经被使用,则需要进行重新连接。
在使用连接对象时,RedisConnect还需要考虑连接状态的问题。如果连接对象的状态异常,就需要重新建立连接。在RedisConnect中,连接状态是通过对redisContext结构体中的err属性进行判断实现的。当err属性不为0时,表示连接状态异常,需要进行重新连接。
为什么连接池内部维护了一个共享性智能指针? 在RedisConnect项目中,维护一个共享型智能指针的主要目的是为了管理连接池中的连接对象。连接池中的连接对象是一个资源,需要进行合理的管理和分配,以避免资源浪费和内存泄漏等问题,确保连接池的高效运行。共享型智能指针是一种智能指针,可以共享指针指向的对象,多个共享型智能指针可以同时指向同一个对象,当没有智能指针指向该对象时,该对象会自动被释放。
- 连接池中的连接对象需要在多个线程之间共享:
连接池中的连接对象需要在多个线程之间共享的主要原因是,RedisConnect是一个多线程应用程序,不同的线程需要共享连接对象来实现对Redis服务器的访问。如果每个线程都创建自己的连接对象,那么就会导致连接池中连接对象数量过多,浪费了系统资源,同时也会导致Redis服务器的负载增加。
通过共享型智能指针来管理连接对象,实现了连接对象在多个线程之间的共享。当连接对象被一个线程使用时,共享型智能指针会增加对该连接对象的引用计数。当连接对象不再被使用时,共享型智能指针会减少对该连接对象的引用计数。当该连接对象的引用计数为0时,该连接对象会自动被释放,从而避免了内存泄漏等问题。
连接池的使用流程:
2. 客户端和服务器之间的通信:
应用层协议:RESP(Redis Serialization Protocol)
Redis使用的一种序列化文本协议,使用ASCII码表示数据,规定了服务器和客户端之间传输数据的格式和规则,使用简单的文本协议来编码二进制数据,以便服务器和客户端之间能够相互理解和解析。规定了不同类型的数据如何如何被编码和解码。 RESP协议是一种简单、高效、可扩展的协议,被广泛应用于Redis客户端和服务端之间的通信。其简单的文本格式和丰富的数据类型使得RESP协议易于实现和扩展,同时也保证了通信效率和稳 优点:简单、高效、可扩展的协议,被广泛应用于Redis客户端和服务端之间的通信。其简单的文本格式和丰富的数据类型使得RESP协议易于实现和扩展,同时也保证了通信效率和稳定性。
实现:
- 将命令字符串转换为RESP协议的字符串格式发送到redis服务器
- 服务端将RESP协议格式数据解析成Redis命令并执行
- 解析RESP协议格式的响应
- 处理数据 当客户端向服务器发送命令时,使用RESP协议将命令编码为二进制格式,然后通过socket发送给服务器,服务器受到数据后,再使用RESP将解码数据。
RESP协议是一种文本协议,使用ASCII码表示数据,RESP协议通过以上五种数据类型来表示Redis命令和命令回复数据。客户端向服务端发送Redis命令时,需要将Redis命令转换成对应的RESP协议格式,然后通过网络连接发送给服务端。服务端接收到RESP协议格式的数据后,会将其解析成Redis命令,并执行相应的操作。服务端执行完Redis命令后,会将执行结果转换成RESP协议格式的数据,并通过网络连接发送给客户端。客户端接收到RESP协议格式的数据后,会将其解析成命令执行结果,并进行相应的处理。
- 简单字符串(Simple String):以"+"号开头,表示一个简单的字符串,例如"+OK\r\n"表示一个字符串"OK"。
- 错误信息(Error):以"-"号开头,表示一个错误信息,例如"-ERR wrong password\r\n"表示一个错误信息"wrong password"。
- 整数(Integer):以":"号开头,表示一个整数,例如":1000\r\n"表示一个整数1000。
- 批量字符串(Bulk String):以"6\r\nhello\r\n"表示一个字符串"hello"。
- 数组(Array):以"*"号开头,表示一个长度可变的数组,例如"*3\r\n:1\r\n:2\r\n:3\r\n"表示一个包含三个整数的数组。
与socket协议区别: 1. RESP是应用层协议,socket是应用层和传输层之间的抽象层。 2. RESP协议规定了服务器和客户端之间传输数据的格式和规则,使用简单的文本协议来编码二进制数据,以便服务器和客户端之间能够相互理解和解析。规定了不同类型的数据如何如何被编码和解码。 3. Socket是一种更低层次的通信方式,提供了一个编程接口,允许应用程序直接访问网络协议栈。
传输层协议:TCP 应用层和传输层之间的抽象层:Socket
提供了一个编程接口,允许应用程序直接访问网络协议栈。
socket触发模式: 在Redis中,通过epoll的ET模式可以更加高效地处理网络事件,提高Redis的性能和吞吐量。 在ET模式下,只有当文件描述符上的状态发生变化时,epoll才会通知应用程序进行处理。与水平触发(Level-Triggered,LT)模式相比,ET模式可以更加精细地控制事件通知,能够减少被通知的次数,提高系统的性能和效率。 Redis客户端和服务端通信使用epoll的触发模式通常是边缘触发(Edge-Triggered,ET)模式。 在ET模式下,只有当文件描述符上的状态发生变化时,epoll才会通知应用程序进行处理。与水平触发(Level-Triggered,LT)模式相比,ET模式可以更加精细地控制事件通知,能够减少被通知的次数,提高系统的性能和效率。 在Redis中,客户端和服务端之间的通信是基于TCP协议的,通过epoll的ET模式可以更加高效地处理网络事件,提高Redis的性能和吞吐量。
通过epoll的ET模式可以更加高效地处理网络事件,提高Redis的性能和吞吐量,原因如下:*
- 减少事件通知次数:在ET模式下,只有当文件描述符上的状态发生变化时,epoll才会通知应用程序进行处理,可以减少被通知的次数,降低CPU的占用率。
- 避免重复处理事件:在ET模式下,只有在文件描述符状态从无可读可写变为有可读可写时才会触发事件通知。这样可以避免同一个事件被重复处理,提高系统的效率。
- 支持非阻塞IO:ET模式支持非阻塞IO,可以在IO操作未完成时立即返回,避免阻塞线程等待IO操作完成。
- 支持高并发:ET模式能够处理大量的并发连接,同时保持较好的性能表现,可以提高Redis的吞吐量和并发能力。 综上所述,通过epoll的ET模式可以减少CPU的占用率、避免重复处理事件、支持非阻塞IO以及支持高并发,从而提高Redis的性能和吞吐量。
redisConnect 如何处理 Redis 数据库连接、如何执行 Redis 命令以及如何处理 Redis 数据库的响应。 建立连接:RedisConnect 函数会创建一个 TCP 连接,并向 Redis 服务器发送一个连接请求。建立连接后,Redis 服务器会返回一个连接成功的响应。 发送 Redis 命令:RedisConnect 函数会发送 Redis 命令到 Redis 服务器。Redis 命令是一些文本字符串,例如 SET key value,表示设置键为 key 的值为 value。 处理 Redis 命令响应:Redis 服务器接收到 Redis 命令后,会执行相应的操作,并将执行结果返回给客户端。RedisConnect 函数会等待 Redis 服务器返回响应,然后解析响应并处理响应结果。Redis 响应通常是一个字符串,例如 OK 或者 key 对应的 value 值。 关闭连接:RedisConnect 函数会在完成 Redis 命令操作后,关闭 Redis 数据库连接。 总的来说,RedisConnect 函数是 Redis 客户端与 Redis 服务器之间通信的核心函数,它负责处理 Redis 数据库连接、执行 Redis 命令以及处理 Redis 数据库的响应。
3. 常见Redis命令
以下是Redis常见命令及用法的简要介绍:
SET key value:设置一个键值对。如果键已经存在,会覆盖原有的值。
GET key:获取指定键的值
DEL key:删除指定键的值。
EXISTS key:判断指定键是否存在。
KEYS pattern:列出所有符合给定模式的键。
TTL key:获取指定键的剩余生存时间。
EXPIRE key seconds:设置指定键的生存时间(单位为秒)。
INCR key:将指定键的值加1。
DECR key:将指定键的值减1。
HSET key field value:设置指定哈希表中的字段值。
HGET key field:获取指定哈希表中的字段值。
HDEL key field:删除指定哈希表中的字段。
HMSET key field1 value1 field2 value2 ...:设置指定哈希表中的多个字段值。
HMGET key field1 field2 ...:获取指定哈希表中的多个字段值。
LPUSH key value1 value2 ...:向列表左侧添加一个或多个值。
RPUSH key value1 value2 ...:向列表右侧添加一个或多个值。
LPOP key:从列表左侧弹出一个值。
RPOP key:从列表右侧弹出一个值。
LRANGE key start stop:获取列表中指定范围的值。
SADD key member1 member2 ...:向集合中添加一个或多个成员。
SMEMBERS key:获取集合中的所有成员。
SREM key member1 member2 ...:从集合中删除一个或多个成员。
SCARD key:获取集合中成员的数量。
以上是Redis常见命令及用法的简要介