问题描述

hiredis查询key失败后,出现key丢失的问题。

REDIS版本及源码:6.0.10

hiredis版本及源码:v1.0.2

案例描述:

REDIS中预先写入1个字符串键"hello",客户端代码基于hiredis,创建100个读线程和100个写线程,每个线程里发起一次短连接读写key,代码参考:

#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <hiredis/hiredis.h>
#include <pthread.h>#define SERV_IP "127.0.0.1"
#define SERV_PORT 6379
#define NUM_READER 100
#define NUM_WRITER 100static const int OK = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;int DBGetString(const char *key, char *value) {struct timeval tv;tv.tv_sec = 5; tv.tv_usec = 0;redisContext *c = redisConnectWithTimeout(SERV_IP, SERV_PORT, tv);assert(c != NULL && !c->err);char cmd[256];sprintf(cmd, "GET %s", key);redisReply *reply = (redisReply *)redisCommand(c, cmd);assert(reply->str != NULL);strcpy(value, reply->str);freeReplyObject(reply);redisFree(c);return OK;
}int DBSetString(const char *key, const char *value) {struct timeval tv;tv.tv_sec = 5; tv.tv_usec = 0;redisContext *c = redisConnectWithTimeout(SERV_IP, SERV_PORT, tv);assert(c != NULL && !c->err);char cmd[256];sprintf(cmd, "SET %s %s", key, value);redisReply *reply = (redisReply *)redisCommand(c, cmd);freeReplyObject(reply);redisFree(c);return OK;
}void *Reader(void *args) {char buf[256];DBGetString("hello", buf);printf("%s\n", buf);return NULL;
}void *Writer(void *args) {DBSetString("hello", "world");return NULL;
}void testcase() {time_t t1 = time(NULL);pthread_t wid[NUM_WRITER];pthread_t rid[NUM_READER];for (int i = 0; i < NUM_WRITER; ++i) {pthread_create(&wid[i], NULL, Writer, NULL);}for (int i = 0; i < NUM_READER; ++i) {pthread_create(&rid[i], NULL, Reader, NULL);}for (int i = 0; i < NUM_WRITER; ++i) {pthread_join(wid[i], NULL);}for (int i = 0; i < NUM_READER; ++i) {pthread_join(rid[i], NULL);}time_t t2 = time(NULL);printf("%ld s\n", t2 - t1);
}int main() {testcase();return 0;
}

定位思路

Redis key丢失一般有如下原因:

  • key被客户端删除。
  • key是过期键,到期自动删除。
  • 因为内存不足导致key被逐出。

本案例中的客户端只有get,set,没有删除操作,未设置键的过期时间,且机器内存也足够(4G以上)。初步分析不出原因,只能结合REDIS源码正向定位,于是有了第二种思路:

REDIS是基于内存的数据库,字符串键肯定在REDIS-SERVER进程中的某个内存地址处,key丢失时这个地址的内容肯定被改写,这时只需要GDB打个数据断点,看下调用栈即可分析原因。

以下给出详细的定位过程。

定位过程

1、使用GCC的-g -O0编译选项,重新编译redis-server, hiredis源代码。(这一步非必要,目的是更方便调试)

2、GDB打数据断点

3、断点触发,观察调用栈

观察第5帧,freeMemoryIfNeeded,说明触发了REDIS的内存淘汰机制,GDB打印出的REDIS配置项maxmemory仅为1048576字节(表示内存大小为1M),且内存淘汰机制为allkeys-lru,这个机制会导致key被回收。

解决方法

修改redis配置项maxmemory,内存给多点。(这里给1073741824,表示1G内存)

hiredis查询失败时出现key丢失问题定位相关推荐

  1. php join a.id b.id,mysql,sql_MySQL A left join B on B.cid=A.id 左链接查询失败,求解,mysql,sql - phpStudy...

    MySQL A left join B on B.cid=A.id 左链接查询失败,求解 mysql> desc fb_category; +-------+-------------+---- ...

  2. 当我们输入一条SQL查询语句时,发生了什么?

    我们经常说,看一个事儿千万不要直接陷入细节里,你应该先鸟瞰其全貌,这样能够帮助你从高维度理解问题.同样,对于 MySQL 的学习也是这样.平时我们使用数据库,看到的通常都是一个整体.比如,你有个最简单 ...

  3. python requests请求失败重试_Python Requests.post()请求失败时的retry设置

    1. 问题描述 通常,我们在做爬虫工作或远程接口调用的过程中,往往由于访问频率过快等原因遇到连接超时的报错问题,利用最近调用api.ai.qq.com某个接口举例如下: Traceback (most ...

  4. python从云端数据库获取数据失败_使用%s的Python MySQL Connector数据库查询失败

    使用%s的Python MySQL Connector数据库查询失败 我有一个基本程序,应该查询包含用户信息的数据库.我正在尝试为特定用户选择信息并将其打印到控制台. 这是我的代码:import my ...

  5. android百度地图地址解析失败怎么办,【百度地图API】当地址解析失败时,如何调用search方法查找地址...

    有个朋友问我,当地址解析失败时,应该如何处理呢?比如,他想搜索"南宁市青秀区". ------------------------------------------------- ...

  6. 解决打包AssetBundle时Shader(材质)丢失问题

    从Unity4.2开始,为了减少首包大小,不会默认将所有Shader引擎加到游戏程序中,据Unity技术支持人员所说, Unity会将Shader引擎打包到Assetbundle资源中,但是我测试发现 ...

  7. 用户sa登陆失败时,应该如何解决

    用户sa登录失败时,应该如何解决   文章作者:R热血江湖私服网 文章来源:网络转载       用户 sa 登录失败.原因: 未与信任 SQL Server 连接 的解决方法2007-04-19 0 ...

  8. 如何计算哈希表查找失败时的平均查找长度

    题目描述: 1.请回答采用线性探测再散列和链地址法处理冲突构建的哈希表中,查找失败时的平均查找长度如何计算? 例:已知一组关键字(19,14,23,1,68,20,84,27,55,11,10,79) ...

  9. vue本地项目配置图片加载失败_vue图片加载失败时用默认图片替换的方法

    vue图片加载失败时用默认图片替换的方法 前言 本文主要给大家介绍的关于vue实现图片加载失败时用默认图片替换的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧 方法如下 原理 ...

最新文章

  1. #27 回文数字 Palindrome Detector
  2. 怎么查计算机网络硬件配置,如何查看电脑本机的硬件配置?
  3. 深度学习 常用python操作(1)
  4. Code Quality
  5. 计算机网络实验(华为eNSP模拟器)——第五章 单臂路由
  6. java 检索ldap,从LDAP(Java)检索信息
  7. mysql 查询 投影,MySql-连接查询
  8. C++工作笔记-stl中map基础用法(插入,遍历,删除)
  9. 小玉买文具(洛谷-P1421)
  10. (25)Vue.js组件通信—父组件向子组件传值
  11. 2015二级java真题及答案_2015计算机二级《JAVA》考前模拟操作和应用题及答案
  12. linux系统克隆安装教程,使用Clonezilla克隆Linux安装的方法
  13. 软件源码破解工具De4Dot用法,net破解、反混淆
  14. 双层pdf软件free_这款软件神器,让你读文献的效率翻一倍!(文末有福利哦)...
  15. wincc工程组态论文_2020/12/18【推荐】几种常用工控组态软件介绍,这次找齐了,你懂哪种?...
  16. 大学学python要买电脑吗_大学生需要买电脑吗?
  17. Linux中docker的使用
  18. 手机计算机里面的符号代表什么意思,计算器上的符号各代表什么意思?
  19. 什么是嵌入式系统?嵌入式系统应该如何学习?
  20. 华为人均工资70万人人想要,可华为员工16项标准你能做到几条?

热门文章

  1. 面经手册 · 第7篇《ArrayList也这么多知识?一个指定位置插入就把谢飞机面晕了!》
  2. 安防监控系统中IP网络监控比模拟摄像头有哪些优劣?
  3. 基于Web的校园互助平台设计与实现
  4. 如何 在 .net 下使用 zint 生成条形码
  5. 中国联通网上4G商城营业厅VIP客户俱乐部简介
  6. DSt:数据结构的简介、最强学习路线(逻辑结构【数组-链表-栈和队列/树-图-哈希】、物理结构、数据运算【十大排序/四大查找-图三大搜索-树三大遍历】、高级算法【贪心/分治/动态规划】之详细攻略
  7. python 最好用的数据库模块_Python 使用pymysql模块操作数据库
  8. LayaAir2.13新特性:新增VR相关功能、渐变环境光、3D自定义分辨率、新的渲染命令、新的动画插值方式、新的粒子功能等等...
  9. blackberry环境搭建
  10. 【竞品分析】小睡眠APP和蜗牛睡眠APP,基于用户体验5要素的分析框架