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

[Redis#10] scan | db_0 | redis_cli | RESP | C++-redis启动教程

目录

1. 渐进式遍历

1.2 常见指令 - scan

2. 数据库管理

3.redis 客户端

是否前面学习的这些 redis 命令,没有价值了呢?

4.RESP 自定义协议

为什么能编写出一个自定义的 Redis 客户端?

RESP 协议

5.在 Ubuntu 下启用 C++ 操作 Redis

1. 前置依赖 - hiredis

2. 安装 redis-plus-plus

3. 示例:通用命令


1. 渐进式遍历

  • keys * 指令用于获取 Redis 中所有的 key,采用遍历的方式。但当 Redis 存储的 key 较多时,该操作可能会阻塞 Redis,影响其他指令执行。
  • 为避免上述问题,可以使用 scan 指令进行渐进式遍历。这种方式可以在不卡死服务器的情况下获取所有 key,并且 每次执行命令只获取其中的一小部分数据,如果 key 较多,则需要多次执行 scan 命令。
1.2 常见指令 - scan
  • 语法scan cursor [MATCH pattern] [COUNT count] [TYPE type]

功能:以渐进式方式对 Redis 中的所有键进行遍历。

  • cursor:表示从哪个 光标 开始遍历。光标为 0 时,表示从头开始遍历。光标的概念不可以理解为下标,它不是一个连续递增的整数,他只是一个普通的字符串在每次遍历后返回下次遍历开始的光标(若 返回的字符串是 0,说明遍历已经完成)
    • 可能程序员不理解,但是 Redis服务器是可以知道这个光标对应的元素的位置的.
  • pattern:匹配指定模式的 key。
  • count:限制每次返回的元素个数,默认为 10。需要注意的是,这里的 count 只是客户端给 Redis 服务器的一个 建议具体返回多少取决于实际情况。
  • type:指定 key 对应 value 的类型,包含 5 个通用类型和 5 个特殊场景使用的类型。

在遍历过程中,不会在服务器中保存任何状态信息如光标位置等。遍历可以随时终止,不会对服务器产生副作用。

  • 就像我们去吃烧烤,如果有一部分烧烤还没有上来,我们就需要退款,这时候老板就到后厨看了一眼,说已经烤上了,退不了了。
  • 再比如我们在遍历 Redis 服务器中的 key 的时候,遍历了一半,不想遍历了,但是这时候又取消不了,如果强行退出,这时候 服务器就会保存状态,这时候就会对服务造成一定的影响,这时候就相当于服务器保存了客户端的状态。
  • 再比如我们去超市买东西,如果我们在结账的时候,发现钱没有带够,后面的东西不想要了,这时候 可以不扫后面的商品。
  • 这时就像 Redis 中的渐进式遍历,没有保存之前遍历的状态,可以随时停止。

示例

127.0.0.1:6379> mset k1 val1 k2 val2 k3 val3 k4 val4 k5 val5
OK
127.0.0.1:6379> scan 0 count 3
1) "1" // 返回下次开始遍历的光标
2) 1) "k3"
   2) "k4"
   3) "k5"
127.0.0.1:6379> scan 1 count 3
1) "0"
2) 1) "k1"
   2) "k2" // 虽然输入的 count 是 3, 但是只遍历了 2 个
  • 注意:尽管 scan 解决了阻塞问题,但在 遍历期间如果键有所变化(增加、修改或删除),可能会导致重复遍历或遗漏。

不仅仅是 Redis,遍历其他内容的时候,也是比较忌讳一边遍历一边修改的。

C++ STL

遍历 + 修改/新增/删除 => 迭代器失效

std::vector<int> v = {1, 2, 3, 4};
for (auto it = v.begin(); it != v.end(); ++it) {
    v.erase(it);
}

注意!!这样的代码,就会导致“迭代器失效”。

当删除完成之后,it 这个迭代器指向哪里,已经不知道了!

此时循环体结束之后再次 ++it,不一定就能指向下一个元素了。

  • 在遍历过程中,不要一边遍历一边修改。
  • C++ 中的迭代器在删除元素后可能会失效。

大部分编程语言中,++ 都是后置写的

  • C++ 更偏好前置 ++
    • 在 C++ 里 前置 ++ 比后置 ++ 性能更高(少了一次临时对象的构造)
  • Java 中 ++ 只是针对数字,数字本身无论是前置后置都是足够快
    • C++ 中 ++ 可能是针对一个对象(C++ 有运算符重载)

不像 C++ 里可能就崩溃了

  • Redis 虽然不会给你崩溃,但是可能会出现 遗漏重复。

2. 数据库管理

  • 类似于 MySQL 中的 database 概念,Redis 中也有 database 的概念,但用户不能随意创建或删除数据库。
  • Redis提供了⼏个⾯向Redis数据库的操作,分别是 dbsizeselectflushdbflushall

说明:

  • 许多关系型数据库,例如MySQL⽀持在⼀个实例下有多个数据库存在的,但是  与关系型数据库⽤字符来区分不同数据库名不同,Redis只是⽤数字作为多个数据库的实现
  • Redis默认配置中是有16个数据库。select 0操作会切换到第⼀个数据库,select 15会切换到最后⼀个数据库
  • 0号数据库和15号数据库保存的数据是完全不冲突的,即各种有各⾃的键值对。默认情况下,我们处于数据库0

  • 选择数据库:可以通过 select dbIndex (例如 select 1) 来切换数据库。
  • 清除数据库
    • flushdb:清除当前数据库中的所有数据。
    • flushall:清除 Redis 服务器中的所有数据。
  • 示例
127.0.0.1:6379> SELECT 1
OK
127.0.0.1:6379[1]> SELECT 0
OK
127.0.0.1:6379> FLUSHDB
OK
127.0.0.1:6379> keys *
(empty array)

警告:永远不要在线上环境 执行清除数据的操作,除非你想要体验“从删库到跑路”的操作。

注意Redis中虽然⽀持多数据库,但随着版本的升级,其实不是特别建议使⽤多数据库特性

  • 如果真的需要完全隔离的两套键值对,更好的做法是维护多个Redis实例,⽽不是在⼀个 Redis实例中维护多数据库
    • 这是因为本⾝Redis并没有为多数据库提供太多的特性
    • 其次⽆论是否有多个数据库,Redis都是使⽤单线程模型,所以彼此之间还是需要排队等待命令的执⾏
    • 同时多数据库还会让开发、调试和运维⼯作变得复杂
  • 实践中,始终使⽤数据库0其实是⼀个很好的选择

3.redis 客户端

  • 前面学习的主要是各种 redis 的基本操作/命令,都是在 redis 命令行客户端,手动执行的。
  • 这种操作方式不是我们日常开发中主要的形式
  • 更多的时候,是使用 redis 的 api,来实现定制化的 redis 客户端程序,进一步操作 redis 服务器。
  • 用程序来操作 redis~

以前学习 MySQL 的时候~也会涉及到,关于使用程序来操作 MySQL 服务器

  • C++: MySQL 原生 API
  • Java: JDBC & MyBatis

redis 提供的命令行客户端 / 第三方的图形化客户端 ...
他们本质上都属于是“通用的客户端程序”

相比之下,在工作中更希望使用到的是 “专用的”“定制化”的客户端程序~

是否前面学习的这些 redis 命令,没有价值了呢?
  • 当然不是的!!
  • redis 命令相当于使用代码来执行

使用:

  • 无论 C++还是 Java各自如何编程实现对应的 redis 客户端,其实要做的事情本质上是一样的~
  • 网上关于 redis 这块的编程,基本都是 Java 为主,难道是,其他语言不配操作 redis 嘛?
  • 当然不是!!!redis 能支持很多很多种编程语言

博主后面选择以 C++来进行讲解~


4.RESP 自定义协议

为什么能编写出一个自定义的 Redis 客户端?
  • 网络通信中的协议层次
    • 应用层
    • 传输层:TCP / UDP 协议
    • 网络层:IP 协议
    • 数据链路层:以太网
    • 物理层
  • 虽然业界有很多 成熟的应用层协议,如 HTTP,但在某些情况下,会“自定义”应用层协议。
    • Redis 使用的就是一种自定义的应用层协议。
  • 客户端和服务器之间的交互
    • 客户端按照应用层协议发送请求;
    • 服务器按照该协议解析请求,并根据请求构造响应;
    • 客户端再解析从服务器返回的响应。

  • 关于我们能否 自己 编写自定义 Redis 客户端
    • 直接基于未公开的协议去编写是不可行的。然而,对于 Redis 来说,其使用的自定义协议(即 RESP)是公开的。
    • 就像一些开源项目通过逆向工程实现了 QQ 客户端一样,实现过程依赖于 开发者对协议的理解和技术水平。
  • 自主 开发 Redis 客户端的前提
    • 需要 了解 Redis 的应用层协议(暗号),即 RESP 协议。
    • 由于 Redis 官方已经公开了这一协议规范,因此可以依据这些信息来编写客户端。

RESP 协议

  • 名称:Redis Serialization Protocol (RESP)
  • 特点
    • 简单易实现
    • 快速解析
    • 内容可读性强
  • 与 TCP 的关系
    • 基于 TCP 传输,但不强耦合于 TCP。
    • 请求-响应模型是 一问一答 的形式。

Redis 中的使用方式

  • 客户端发送命令到 Redis 服务器,服务器以 RESP 数组形式接收并处理。
  • 根据命令的不同,服务器将以不同的 RESP 类型进行响应,例如:
    • 直接返回 ok
    • 返回整数
    • 返回数组......

常见 数据类型标识

  • Simple Strings: 开头为 +
  • Errors: 开头为 -
  • Integers: 开头为 :
  • Bulk Strings: 开头为 $
  • Arrays: 开头为 *

示例

    • +OK\r\n
    • -Error message\r\n
    • :1000\r\n
    • $5\r\nhello\r\n
    • *2\r\n$5\r\nhello\r\n$6\r\nworld\r\n
  • Simple Strings:用于传输非二进制安全的文本字符串,开销最小。
  • Bulk Strings:用于传输二进制安全的数据。
  • 可以发现 resp 比 htttps 的设计简单不少~

开发提示

  • 不需要手动解析或构造符合 RESP 规范的字符串,因为已有许多成熟的库支持这种操作。
  • 我们只需要 使用大佬们 提供的库,就可以比较简单方便的来完成和 redis 服务器通信的操作了

5.在 Ubuntu 下启用 C++ 操作 Redis

1. 前置依赖 - hiredis
  • hiredis 是一个用 C 语言实现的 Redis 客户端库,redis-plus-plus 库基于 hiredis 实现。
  • 在开始之前,请确保已安装 libhiredis-dev,可以通过以下命令安装:
sudo apt install libhiredis-dev
2. 安装 redis-plus-plus
  • redis-plus-plus 是一个功能强大且易于使用的 C++ Redis 客户端库。它具有统一的接口风格,使得使用起来非常方便。
  • 以下是安装步骤:
  • 克隆 redis-plus-plus 的 GitHub 仓库到本地:
git clone https://github.com/sewenew/redis-plus-plus.git

进入克隆下来的项目目录,并创建构建目录:

cd redis-plus-plus
mkdir build && cd build

使用 CMake 配置并编译安装:

cmake .. -DCMAKE_INSTALL_PREFIX=/usr
make
sudo make install
  • 说明:
    • redis-plus-plus 库支持多种方式传递参数,如 初始化列表或迭代器对。
    • 当函数需要返回多个数据时,通常会使用插入迭代器将结果添加到容器中。
    • 对于可能返回无效值的情况redis-plus-plus 通常会使用 std::optional 来表示。
3. 示例:通用命令

Quick Start创建一个简单的 C++ 程序来连接 Redis 并发送一个 ping 命令,以检查连接是否成功。

  • main.cc:
#include <iostream>
#include <string>
#include <sw/redis++/redis++.h>

using namespace std;

int main()
{
    // 构建Redis对象的时候,在构造函数中,指定Redis服务器的地址和端口
    sw::redis::Redis redis("tcp://127.0.0.1:6379");
    string ret = redis.ping();
    cout << ret << endl;
    return 0;
}
  • Makefile:
main: main.cc
    g++ -std=c++17 -o $@ $^ -l redis++ -l hiredis -l pthread

.PHONY: clean
clean:
    rm main
  • 编译和运行:
    • 在终端中执行以下命令来编译程序:
make
    • 运行生成的可执行文件:
./main
    • 如果一切正常,可以 看到输出 PONG,这表明已经成功连接到了 Redis 服务器啦

http://www.kler.cn/a/415635.html

相关文章:

  • 多线程——01
  • Vue-TreeSelect组件最下级隐藏No sub-options
  • 动态规划-斐波那契数列模型
  • Electron文件写入、读取(作用:公共全局变量,本地存储)
  • Python蒙特卡罗MCMC:优化Metropolis-Hastings采样策略Fisher矩阵计算参数推断应用—模拟与真实数据...
  • 海康面阵、线阵、读码器及3D相机接线说明
  • springboot-vue excel上传导出
  • hdlbits系列verilog解答(Exams/m2014 q4b)-87
  • Vba实现复制文本到剪切板
  • 从0开始学PHP面向对象内容之常用设计模式(享元)
  • linux下Qt程序部署教程
  • 设计模式学习之——观察者模式
  • 在openEuler中使用top命令
  • 【C++】list模拟实现(完结)
  • 电子电气架构 --- 面向服务的汽车诊断架构
  • 【docker】细致且具有时效性的docker在ubuntu的安装,新鲜出炉
  • python图像彩色数字化
  • PVE相关名词通俗表述方式———多处细节实验(方便理解)
  • 实践五 网络安全防范技术
  • Android复习代码1-4章