当前位置: 首页 > news >正文

C++操作redis(实现连接池、分布式锁)


文章目录

  • Redis连接池
    • 编译项目
    • 整体架构
    • 使用
    • 分布式锁
    • 总结


Redis连接池

封装hiredis的一些基本操作,redishelper类提供包含连接,放回,存取键,push,pop,执行redis语句和执行lua脚本的函数,连接池是类模板,传入相应helper类即可实现多种连接池,后续实现mysql连接池。

编译项目

  1. 安装hiredis,解压文件中hiredis.tar(后续对源码进行了改动,文件中是改后的)
tar -xvf hiredis.tar
cd hiredis/
make
make install	# 权限不足加上sudo
  1. 删除之前的CMakeCache.txt
cd ConnPool/
rm CMakeCache.txt
  1. 重新cmake和make
cmake .
make -j4
  1. 后续引入头文件SimConnPool.h即可使用,简单应用见tests文件

整体架构

  1. RedisHelper:redis相关操作,创建一个连接时构造函数不做任何事,在connection函数时才真正建立一条连接,每条连接都包含一个指向连接池的指针,为了实现放回操作,基础实现依赖hiredis库中的redisCommand函数
  2. ConnPool :连接池模板,初始化时构造函数不做任何操作,在连接池connection时才执行init函数完成每一个连接的初始化,并且依次调用每条连接的connection函数
  3. Singleton:单例模板,包装ConnPool类,变成单例对象

使用

static SimpleConnPool::redisPool* pool = SimpleConnPool::redisConnPoolMgr::GetInstance();   // 获取一个连接池单例对象,默认5个连接
pool->connection("127.0.0.1", 6000);      // 连接池内连接上redis,入参:ip、端口号、密码默认为空
SimpleConnPool::redisPool::connPtr conn = pool->get();      // 取出一条连接
// TODO
conn->connBack();     // 放回连接

分布式锁

当多线程并发访问数据库中某个资源时,可能同一时间返回都取到了旧值,并且对旧值进行变更,这样会造成逻辑上的混淆。比如在电商场景,库存这个变量,当多个用户进行抢购的时候,首先判断库存然后库存减一,若不加锁,库存为1的时候,可能多个用户获取库存判断时都拿到了1,最后都进行库存减一,可能就出现负数了。

在分布式系统环境下,一个方法在同一时间只能被一个机器的一个线程执行

高可用的获取锁与释放锁

具备可重入特性(可理解为重新进入,由多于一个任务并发使用,而不必担心数据错误)

具备锁失效机制,即自动解锁,防止死锁

加锁:

实际是,对一个键进行赋值,借助set key val NX PX timeout 语句实现,NX表示若键存在返回nil,不存在则赋值,当多线程运行到lock时,只有第一个执行语句的线程可以跳出,继续执行,其余线程都需要阻塞在lock内部。

设置超时时间为了保证不会因为加锁线程挂掉而导致死锁的情况。

/* 加锁逻辑:在不存在键时设置键 并同时设置超时时间  保证原子性set key value NX PX timeout默认10秒返回该线程拿到锁生成的值,后续解锁比较,不能因为挂机或网络原因解锁别的线程锁分布式锁的键为:redis.lock      值为:当前时间戳 nsec*/
std::string lock(uint64_t timeout = 30000) {while(1) {struct timespec time = {0, 0};clock_gettime(CLOCK_REALTIME, &time);std::string uuid = std::to_string(time.tv_nsec);std::string cmd = "set redis.lock " + uuid + " NX PX " + std::to_string(timeout);std::string flag;RedisState sta;{MutexType::Lock lock(m_mutex);sta = execute(cmd, &flag);}if(sta == RedisState::M_REDIS_OK) {std::cout << "get redis.lock!" << std::endl;return uuid;}}
}

解锁:

需要取值、判断、删除三个操作,因此使用lua脚本来保证原子性,判断是为了保证不会删除其余线程所创建的锁。

/*解锁逻辑:获取锁,判断锁,删除锁为了保证原子性,使用lua脚本来完成三个操作redis使用eval "xxxx" keys数量 key1 key2 num1 num2 */
void unlock(const std::string& uuid) {std::string cmd = "eval \"if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end\" 1 redis.lock " + uuid;int flag;RedisState sta = executeLua(cmd.c_str(), &flag);if(sta == RedisState::M_REDIS_OK && flag > 0) {std::cout << "获取到锁并解锁" << std::endl;}else {std::cout << "未获取到锁 errstr: " << m_error_msg << std::endl;}return ;
}

总结

基于hiredis,只需要引入头文件即可使用,简单方便,复杂语句使用execute函数直接执行,但是需要根据redis客户端返回值,传入该函数第二个参数(set,get返回ok就传string,del返回1或0就传int)

为了可以执行lua脚本,对hiredis中源码进行了改动,原先是以空格来分割命令的,但是lua脚本需要return时肯定包含空格,需要更改分割规则,增加以双引号分割,详见(hiredis中lua脚本调用_hiredis lua_suhiymof的博客-CSDN博客)

std::string cmd = "EVAL \"redis.call('SET', KEYS[1], ARGV[1]) local result = redis.call('get',KEYS[1]) return result\" 1 foo1 bar1";
std::string flag;       // set get为string类型,del为int类型,看redis客户端返回的类型设置
conn->executeLua(cmd.c_str(), &flag);
std::cout << "lua执行结果:" << flag << std::endl;

帮助大家熟悉C++和redis的基本操作,使用lua脚本实现了简单的分布式锁,可以多线程的访问数据库中某个变量

还缺少健康检测,自动扩缩容等实现,大家有需要可以继续开发
整体项目地址 供大家学习使用,如果有帮助请多点点star

相关文章:

C++操作redis(实现连接池、分布式锁)

文章目录Redis连接池编译项目整体架构使用分布式锁总结Redis连接池 封装hiredis的一些基本操作&#xff0c;redishelper类提供包含连接&#xff0c;放回&#xff0c;存取键&#xff0c;push&#xff0c;pop&#xff0c;执行redis语句和执行lua脚本的函数&#xff0c;连接池是类…...

硬件基础专题-01电阻篇

目录 课程链接 学习目的 电阻 电阻理论讲解 电阻定义​ 欧姆定律​ 电阻单位换算 电阻选型考虑 安装方式 常见电阻值 各种贴片电阻的读取方式 确定电阻值的方法 电阻数据手册 电阻测量 电阻的产品应用​ 零欧姆电阻 热敏电阻 光敏电阻 课程链接 视频专辑 - 硬件…...

【JAVA程序设计】(C00112)基于Springboot+Thymeleaf的在线购物商城——有文档

基于SpringbootThymeleaf的在线购物商城——有文档项目简介项目获取开发环境项目技术运行截图运行视频项目简介 基于Springbootthymeleaf框架的在线购物商城系统&#xff0c;本系统共分为二个角色&#xff1a;管理员和用户 管理员角色包含以下功能&#xff1a; 商品管理、商品…...

shell基础(5)算数计算:运算语法、自增自减

文章目录1. shell算数运算的特点2. 运算符一览3. 运算语法3.1 整形运算3.2. 小数运算 ing4. 自增自减4.1. a与a4.2. 自加1. shell算数运算的特点 Shell 和其它编程语言不同&#xff0c;Shell 不能直接进行算数运算&#xff0c;必须使用数学计算命令。Shell只支持整数运算&#…...

virtio设备input节点

注册virtio_input_node节点&#xff0c;节点类型为VLIB_NODE_TYPE_INPUT。 VLIB_REGISTER_NODE (virtio_input_node) {.name "virtio-input",.sibling_of "device-input",.format_trace format_virtio_input_trace,.flags VLIB_NODE_FLAG_TRACE_SUPP…...

《计算机网络:自顶向下方法》学习笔记——第一章:计算机网络和因特网

计网 第一章 计算机网络和因特网 1.1 什么是因特网 回答这个问题有两种方式 其一&#xff0c;我们能够描述因特网的具体构成&#xff0c;即构成因特网的基本硬件和软件组件&#xff1b;其二&#xff0c;我们能够根据为分布式应用提供服务的联网基础设施来描述因特网。 1.1.…...

PDF 解析格式化输出 API 数据接口

PDF 解析格式化输出 API 数据接口 支持输出 TEXT HTML XML TAG&#xff0c;多种格式输出&#xff0c;超精准识别率。 1. 产品功能 通用的识别接口&#xff0c; 支持标准 PDF 文件解析&#xff1b;多种格式输出&#xff0c;支持 TEXT HTML XML TAG&#xff1b;HTML 包含完美排…...

RL笔记:基于策略迭代求CliffWaking-v0最优解(python实现)

目录 1. 概要 2. 实现 3. 运行结果 1. 概要 CliffWalking-v0是gym库中的一个例子[1]&#xff0c;是从Sutton-RLbook-2020的Example6.6改编而来。不过本文不是关于gym中的CliffWalking-v0如何玩的&#xff0c;而是关于基于策略迭代求该问题最优解的实现例。 CliffWalking-v0的…...

350. 两个数组的交集 II

两个数组的交集 II 给你两个整数数组 nums1 和 nums2 &#xff0c;请你以数组形式返回两数组的交集。返回结果中每个元素出现的次数&#xff0c;应与元素在两个数组中都出现的次数一致&#xff08;如果出现次数不一致&#xff0c;则考虑取较小值&#xff09;。可以不考虑输出结…...

Android仿微信选择图片

效果展示首先先添加用到的权限<uses-permission android:name"android.permission.INTERNET" /><!--获取手机存储卡权限--><uses-permission android:name"android.permission.READ_EXTERNAL_STORAGE"/><uses-permission android:nam…...

python+嵌入式——串口通信篇(收发解包)

目录前言安装pyserialpyserial大致概括整体流程硬件连接例子(简单版)详细使用serial初始化参数发包收包收包检查包并解包python struct模块结语前言 这几年&#xff0c;自己也做了一些嵌入式机器人。在整个开发的过程中&#xff0c;调通信通常会花费一段比较长的时间&#xff…...

剖析G1 垃圾回收器

简单回顾 在Java当中&#xff0c;程序员在编写代码的时候只需要创建对象&#xff0c;从来不需要考虑将对象进行释放&#xff0c;这是因为Java中对象的垃圾回收全部由JVM替你完成了(所有的岁月静好都不过是有人替你负重前行)。 而JVM的垃圾回收由垃圾回收器来负责&#xff0c;在…...

如何打造一款专属于自己的高逼格电脑桌面

作为一名电脑重度使用者&#xff0c;你是否拥有一款属于你自己的高逼格电脑桌面呢&#xff1f;你是不是也像大多数同学一样&#xff0c;会把所有的内容全部都堆积到电脑桌面&#xff0c;不仅找东西困难&#xff0c;由于桌面内容太多还会导致C盘空间不足&#xff0c;影响电脑的反…...

【C++】string的使用及其模拟实现

文章目录1. STL的介绍1.1 STL的六大组件1.2 STL的版本1.3 STL的缺陷2. string的使用2.1 为什么要学习string类&#xff1f;2.2 常见构造2.3 Iterator迭代器2.4 Capacity2.5 Modifiers2.6 String operations3. string的模拟实现3.1 构造函数3.2 拷贝构造函数3.3 赋值运算符重载和…...

怀念在青鸟的日子

时间过的可真快&#xff0c;一转眼来到了2023年&#xff01;我初中上完就没有在念&#xff0c;下了学门步入社会&#xff0c;那时的我一片迷茫&#xff0c;不知道该去干什 么&#xff0c;父母说要不去学挖掘机、理发、修车...我思考再三&#xff0c;一个都没有我喜欢的&#xf…...

学习记录---Python内置类型

文章目录字符串split()列表常见操作列表相减字典创建普通创建eval(s)添加或更新元素d[t] 1d.update({c: 3}){**d1, **d2} **字典解包装运算符删除元素 d.pop(c)属性d.items()d.keys()d.values()访问元素d[Name]d.get(score)遍历字典for key in dictfor key, values in dict.it…...

Python笔记 -- 列表

文章目录1、列表简介2、修改、添加、删除元素2.1、添加2.2、删除3、排序、倒序4、遍历列表5、创建数值列表6、列表切片7、列表复制8、元组1、列表简介 在Python中用方括号[]表示列表&#xff0c;用逗号隔开表示其元素 通过索引访问列表 names [aa,bb,cc,dd]print(names[0]) …...

谈谈UVM中的uvm_info打印

uvm_info宏的定义如下&#xff1a; define uvm_info(ID,MSG,VERBOSITY) \begin \if (uvm_report_enabled(VERBOSITY,UVM_INFO,ID)) \uvm_report_info (ID, MSG, VERBOSITY, uvm_file, uvm_line); \end 从这里可以看出uvm_info由两部分组成&#xff1a;uvm_report_enabled(VER…...

矩阵理论1 集合上的等价关系(equivalence relations on a set S)

定义 对于一个集合S, 如果集合E⊂SS\mathcal{E} \subset S\times SE⊂SS满足以下条件 自反性: 对于∀s∈S,都有(s,s)∈E\forall s\in S, 都有 (s, s) \in \mathcal{E}∀s∈S,都有(s,s)∈E对称性: (s,t)∈E⇔(t,s)∈E(s,t) \in \mathcal{E} \Leftrightarrow (t,s)\in \mathcal…...

【网络监控】Zabbix详细安装部署(最全)

文章目录Zabbix详细安装部署环境准备安装依赖组件访问初始化配置Zabbix详细安装部署 Zabbix 是一个高度集成的网络监控解决方案&#xff0c;可以提供企业级的开源分布式监控解决方案&#xff0c;由一个国外的团队持续维护更新&#xff0c;软件可以自由下载使用&#xff0c;运作…...

大数据领域中分布式计算的性能优化策略

大数据领域中分布式计算的性能优化策略&#xff1a;解锁大数据处理的高效密码 关键词&#xff1a;大数据、分布式计算、性能优化、数据分区、负载均衡、通信优化 摘要&#xff1a;在大数据时代&#xff0c;分布式计算成为处理海量数据的关键技术。然而&#xff0c;如何优化分布…...

重构文献预览体验:Zotero PDF Preview让学术效率提升70%的无缝解决方案

重构文献预览体验&#xff1a;Zotero PDF Preview让学术效率提升70%的无缝解决方案 【免费下载链接】zotero-pdf-preview Preview Zotero attachments in the library view. 项目地址: https://gitcode.com/gh_mirrors/zo/zotero-pdf-preview 一、场景化痛点&#xff1a…...

终极指南:如何使用Rust构建企业级数据脱敏系统

终极指南&#xff1a;如何使用Rust构建企业级数据脱敏系统 在当今数据驱动的时代&#xff0c;企业面临着日益严格的隐私保护法规和数据安全挑战。数据脱敏作为保护敏感信息的关键技术&#xff0c;正成为企业数据治理的核心环节。本文将详细介绍如何利用Rust这一安全高效的系统编…...

域名过期后会不会影响网站的SEO排名

域名过期后是否会影响网站的SEO排名&#xff1a;深入探讨与解决方案 在当今互联网时代&#xff0c;域名是网站的核心标识&#xff0c;它不仅代表了网站的身份&#xff0c;还在搜索引擎优化&#xff08;SEO&#xff09;中扮演着重要角色。有时我们可能会面临域名过期的情况&…...

IDM激活工具使用指南:长期使用IDM的技术方案详解

IDM激活工具使用指南&#xff1a;长期使用IDM的技术方案详解 【免费下载链接】IDM-Activation-Script IDM Activation & Trail Reset Script 项目地址: https://gitcode.com/gh_mirrors/id/IDM-Activation-Script Internet Download Manager&#xff08;IDM&#xf…...

3个实用技巧让你彻底告别浏览器自动化测试的版本兼容性烦恼

3个实用技巧让你彻底告别浏览器自动化测试的版本兼容性烦恼 【免费下载链接】chrome-for-testing 项目地址: https://gitcode.com/gh_mirrors/ch/chrome-for-testing 还在为Chrome浏览器和ChromeDriver版本不匹配而头疼吗&#xff1f;Chrome for Testing项目正是为了解…...

3种突破窗口限制的高效方案:WindowResizer让桌面管理更自由

3种突破窗口限制的高效方案&#xff1a;WindowResizer让桌面管理更自由 【免费下载链接】WindowResizer 一个可以强制调整应用程序窗口大小的工具 项目地址: https://gitcode.com/gh_mirrors/wi/WindowResizer 在数字化办公环境中&#xff0c;窗口尺寸管理直接影响工作效…...

AI辅助开发:描述需求即可自动生成流程图,比手动visio下载更智能

最近在做一个用户系统的设计&#xff0c;需要画登录注册的流程图。以前用Visio这类工具时&#xff0c;经常要手动拖拽各种图形、调整连线&#xff0c;特别费时间。这次尝试了用AI辅助生成&#xff0c;发现效率提升太多了&#xff01; 需求解析环节 我把需求描述成一段自然语言&…...

新手开发者的第一课:用快马打造零基础的mc指令学习助手

作为一个刚接触《我的世界》指令系统的玩家&#xff0c;我最初完全搞不懂那些复杂的斜杠命令。直到自己动手做了一个指令查询工具&#xff0c;才发现原来理解指令可以这么简单。今天就来分享如何用InsCode(快马)平台快速打造一个零基础友好的MC指令助手。 为什么需要专门的指令…...

YOLOv8n-face:工业级人脸检测技术的精度与效率平衡之道

YOLOv8n-face&#xff1a;工业级人脸检测技术的精度与效率平衡之道 【免费下载链接】yolov8-face yolov8 face detection with landmark 项目地址: https://gitcode.com/gh_mirrors/yo/yolov8-face 一、行业痛点诊断&#xff1a;企业级人脸检测的现实挑战 1.1 复杂场景…...