redis 连接池 hiredis
对Hiredis进行了简单封装
1、API进行统一,对外只提供一个接口;
2、屏蔽上层应用对连接的细节处理;
3、底层采用队列的方式保持连接池,保存连接会话;
4、重连时采用时间戳进行控制,每隔一定时间(3s)重连一次,防止频繁重试造成的不必要浪费。
先看一下Hiredis的常用数据结构与API:
/* Context for a connection to Redis */
typedef struct redisContext {
int err; /* Error flags, 0 when there is no error */
char errstr[128]; /* String representation of error when applicable */
int fd;
int flags;
char *obuf; /* Write buffer */
redisReader *reader; /* Protocol reader */
} redisContext;
#define REDIS_REPLY_STRING 1
#define REDIS_REPLY_ARRAY 2
#define REDIS_REPLY_INTEGER 3
#define REDIS_REPLY_NIL 4
#define REDIS_REPLY_STATUS 5
#define REDIS_REPLY_ERROR 6
typedef struct redisReply {
int type; /* REDIS_REPLY_* */
long long integer; /* The integer when type is REDIS_REPLY_INTEGER */
int len; /* Length of string */
char *str; /* Used for both REDIS_REPLY_ERROR and REDIS_REPLY_STRING */
size_t elements; /* number of elements, for REDIS_REPLY_ARRAY */
struct redisReply **element; /* elements vector for REDIS_REPLY_ARRAY */
} redisReply;
void redisFree(redisContext *c);
封装后的代码:
redis_pool.h
#define __REDIS_POOL_H__
#include <string.h>
#include <string>
#include <stdio.h>
#include <memory>
#include <mutex>
#include <queue>
#include <sys/time.h>
{
public:
KGRedisClient(std::string ip, int port, std::string password, int timeout = 2000);
virtual ~KGRedisClient();
// bool ExecuteCmd_spop(const char *cmd, size_t len, std::string &response);
bool ExecuteCmd_spop(std::string &response, const char* format, ...);
// redisReply* ExecuteCmd(const char *cmd, size_t len);
redisReply* ExecuteCmd(const char* format, ...);
private:
int m_timeout;
int m_serverPort;
std::string m_setverIp;
std::string m_password;
// CCriticalSection m_lock;
std::mutex _mutex;
std::queue<redisContext *> m_clients;
time_t m_beginInvalidTime;
static const int m_maxReconnectInterval = 3;
redisContext* CreateContext();
void ReleaseContext(redisContext *ctx, bool active);
bool CheckStatus(redisContext *ctx);
};
#include <stdio.h>
{
m_timeout = timeout;
m_serverPort = port;
m_setverIp = ip;
m_password = password;
m_beginInvalidTime = 0;
}
KGRedisClient::~KGRedisClient()
{
// CAutoLock autolock(m_lock);
std::unique_lock <std::mutex> lck(_mutex);
while(!m_clients.empty())
{
redisContext *ctx = m_clients.front();
redisFree(ctx);
m_clients.pop();
}
}
{
va_start(args, format);
redisReply *reply = ExecuteCmd(format, args);
va_end(args);
if(reply == NULL) return false;
std::shared_ptr<redisReply> autoFree(reply, freeReplyObject);
{
response = std::to_string(reply->integer);
return true;
}
else if(reply->type == REDIS_REPLY_STRING)
{
response.assign(reply->str, reply->len);
return true;
}
else if(reply->type == REDIS_REPLY_STATUS)
{
response.assign(reply->str, reply->len);
return true;
}
else if(reply->type == REDIS_REPLY_NIL)
{
response = "";
return true;
}
else if(reply->type == REDIS_REPLY_ERROR)
{
response.assign(reply->str, reply->len);
return false;
}
else if(reply->type == REDIS_REPLY_ARRAY)
{
response = "Not Support Array Result!!!";
return false;
}
else
{
response = "Undefine Reply Type";
return false;
}
}
redisReply* KGRedisClient::ExecuteCmd(const char* format, ...)
{
va_start(args, format);
if(ctx == NULL) return NULL;
// redisReply *reply = (redisReply*)redisCommand(ctx, "spop %b", cmd, len);
// redisReply *reply = (redisReply*)redisCommand(ctx, "%s", cmd);
redisReply* reply = (redisReply*)redisCommand(ctx, format, args);
va_end(args);
ReleaseContext(ctx, reply != NULL);
return reply;
}
{
{
// CAutoLock autolock(m_lock);
std::unique_lock <std::mutex> lck(_mutex);
{
redisContext *ctx = m_clients.front();
m_clients.pop();
return ctx;
}
}
time_t now = time(NULL);
if(now < m_beginInvalidTime + m_maxReconnectInterval) return NULL;
struct timeval tv;
tv.tv_sec = m_timeout / 1000;
tv.tv_usec = (m_timeout % 1000) * 1000;;
redisContext *ctx = redisConnectWithTimeout(m_setverIp.c_str(), m_serverPort, tv);
if(ctx == NULL || ctx->err != 0)
{
if(ctx != NULL) redisFree(ctx);
m_beginInvalidTime = time(NULL);
return NULL;
}
std::string strReply = "AUTH ";
strReply += m_password;
reply = (redisReply*)redisCommand(ctx, strReply.c_str());
freeReplyObject(reply);
reply = NULL;
return ctx;
}
void KGRedisClient::ReleaseContext(redisContext *ctx, bool active)
{
if(ctx == NULL) return;
if(!active) {redisFree(ctx); return;}
// CAutoLock autolock(m_lock);
std::unique_lock <std::mutex> lck(_mutex);
}
bool KGRedisClient::CheckStatus(redisContext *ctx)
{
redisReply *reply = (redisReply*)redisCommand(ctx, "ping");
if(reply == NULL) return false;
std::shared_ptr<redisReply> autoFree(reply, freeReplyObject);
if(reply->type != REDIS_REPLY_STATUS) return false;
if(strcasecmp(reply->str,"PONG") != 0) return false;
return true;
}
成员变量:m_clients用于保存连接池。
成员变量:m_beginInvalidTime、m_maxReconnectInterval 用于控制断掉时的频繁连接。
对外API:ExecuteCmd(const char *cmd, string &response);
redis 连接池 hiredis的更多相关文章
- Redis 连接池的问题
目录 Redis 连接池的问题 1 1. 前言 1 2.解决方法 1 前言 问题描述:Redis跑了一段时间之后,出现了以下异常. Redis Timeout ex ...
- 红眼技术博客 » redis连接池红眼技术博客 » redis连接池
红眼技术博客 » redis连接池 redis连接池
- redis连接池操作
/** * @类描述 redis 工具 * @功能名 POJO * @author zxf * @date 2014年11月25日 */public final class RedisUtil { p ...
- java操作redis redis连接池
redis作为缓存型数据库,越来越受到大家的欢迎,这里简单介绍一下java如何操作redis. 1.java连接redis java通过需要jedis的jar包获取Jedis连接. jedis-2.8 ...
- 三:Redis连接池、JedisPool详解、Redisi分布式
单机模式: package com.ljq.utils; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; ...
- 压测过程中,获取不到redis连接池,发现redis连接数高
说明:图片截得比较大,浏览器放大倍数看即可(涉及到隐私,打了码,请见谅,如果有疑问,欢迎骚扰). 最近在压测过程中,出现获取不到redis连接池的问题 xshell连接redis服务器,查看连接数,发 ...
- Redis连接池
package com.lee.utils; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; impor ...
- Redis】Java中使用Jedis操作Redis(Maven导入包)、创建Redis连接池
如果我们使用Java操作Redis, 需要确保已经安装了 redis 服务及 Java redis 驱动. Maven项目可以直接在pom.xml中加入jedis包驱动: <!-- https: ...
- redis连接池 jedis-2.9.0.jar+commons-pool2-2.4.2.jar
java使用Redis连接池 jar包为 jedis-2.9.0.jar+commons-pool2-2.4.2.jar jar下载地址 package com.test; import redis ...
随机推荐
- UIImageView的常用方法
//初始化 init(image: UIImage!) @availability(iOS, introduced=3.0)//初始化,highlightedImage 高亮图片 init(image ...
- loadrunner场景报错:Error: CCI compilation error -/tmp/brr_5d65oV/netdir/E/\320\324/Action.c (318): undeclared identifier `LAST'解决思路
在windows下写的脚本编译通过 但是拿到linux agent场景执行中就会提示如下,同样的脚本在windows agent下没有任何问题 agent连的是linux负载机 通过脚本一行一行排查, ...
- Python学习(五) —— 文件操作
一.文件操作 1.文件操作:数据持久化的一种 步骤:找到文件,打开文件,操作:读.写.追写,关闭文件 打开文件:f = open(文件路径,操作模式,编码方式),f:文件句柄.文件 ...
- jenkins(2): jenkins定时构建项目
参考:http://blog.sina.com.cn/s/blog_b5fe6b270102v7xo.html https://blog.csdn.net/xueyingqi/article/deta ...
- Codeforces Round #487 (Div. 2) 跌分有感
又掉分了 这次的笑话多了. 首先,由于CF昨天的比赛太早了,忘记了有个ER,比赛开始半个小时才发现. 于是只能今天了. 嗯哈. 今天这场也算挺早的. 嗯嗯,首先打开A题. 草草看了一遍题意,以为不是自 ...
- day 50 js-part1基础语法,数据类型及用法,流程控制语句,循环
js基本概念: JavaScript 是世界上最流行的脚本语言. JavaScript 被数百万计的网页用来改进设计.验证表单.检测浏览器.创建cookies,以及更多的应用. JavaScript ...
- day30 网络编程 之进程,线程,协程
进程点进去 线程点进去 协程点进去 什么是进程 进程(有时称为重量级进程)是一个执行中的程序.每个进程都拥有自己的地址空间.内存.数据栈以及其他用于跟踪执行的辅助数据.同一个程序执行两次,属于是两个不 ...
- responseHandler
resonsehandler 接受服务端传过来的数据,然后在这个函数里处理好要显示的数据在return个table显示 <!DOCTYPE html> <html lang=&quo ...
- hive中的分桶表
桶表也是一种用于优化查询而设计的表类型.创建通表时,指定桶的个数.分桶的依据字段,hive就可以自动将数据分桶存储.查询时只需要遍历一个桶里的数据,或者遍历部分桶,这样就提高了查询效率 ------创 ...
- JavaEE 之 RESTful
1.RESTful a.定义:一种软件架构风格,设计风格而不是标准,只是提供了一组设计原则和约束条件.它主要用于客户端和服务器交互类的软件.基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等 ...