我们现在就是Redis

了解更多

集成模块

万博体育彩Redis Enterprise允许您无缝集成Redis模块到您的数据库。模块是扩展Redis以覆盖任何行业最流行的用例的附加组件。万博体育彩Redis企业版配备了一系列内置模块,每个模块都经过了信任、测试和验证,可以与Redis企业版以及开源Redis一起工作:

此外,您可以部署列表中列出的认证模块之一模块集线器,但请注意,这些模块经认证可与特定版本的Redis Enterprise和开放源码Redis配合使用,因此未被视为生产就绪。此外,Redis Enterprise允许万博体育彩您部署模块集线器上列出的任何其他模块,甚至您自己的自定义模块,尽管没有功能、高可用性或安全保证。

企业模块在中提供云专业/终极和软件万博电竞客服部署;所有其他模块仅在Redis企业软件部署或非生产使用的开源Redis中可用。万博体育彩万博电竞客服

一旦你配置了一个模块,Redis Enterprise就会万博体育彩确保该模块在数据库的整个生命周期中都是可用的,包括在复制、故障转移、数据持久化、备份、分片迁移、再平衡等操作期间。原生集群感知的模块,如RedisJSON和RedisBloom,将立即使用重新分片和缩放操作。对于需要多分片通信才能在集群配置中正常运行的模块(如RediSearch), Redis Enterprise以完全透明的方式添加了一个特定于模块的协调实体,负责所有集群操作和多分片通信。万博体育彩

一个万博体育彩集成模块的Redis企业集群节点

企业模块

企业模块(redisresearch、RedisJSON、RedisGraph、RedisTimeSeries和RedisBloom)继承了Redis Enterprise的所有伸缩性、高可用性和性能优势,如下所述。万博体育彩

再研究

RediSearch是一个功能强大的模块,它不仅为Redis中的数据,而且为任何数据库中的数据提供辅助索引和搜索功能。其显著特点包括在同时搜索和索引大量数据时具有极高的性能。阅读更多关于重新研究

RedisGraph

RedisGraph是一个Redis模块,它使企业能够比传统的关系数据库或现有的Graph数据库更快地处理任何类型的连接数据。RedisGraph将连接的数据表示为稀疏邻接矩阵,而不是每个数据点的普通邻接表表示。稀疏矩阵和GraphBLAS(一个高度优化的稀疏矩阵操作库)的结合,使RedisGraph成为存储、管理和处理图的最快和最有效的方法。读关于RedisGraph的更多信息

Redisson

RedisJSON是一种新的数据类型,它提供了本机JSON功能,非常适合快速高效地操作JSON文档。与任何Redis数据类型一样,RedisJSON值存储在键中,可以通过一组专门的命令访问这些键。这些命令的设计目的是让从JSON世界来到Redis的用户直观,反之亦然。考虑这个示例,演示如何设置和获取值:

127.0.0.1:6379>JSON.SET scalar'“你好,JSON!”“确定127.0.0.1:6379>JSON.SET对象。”{“foo”:“bar”,“ans”:42}OK 127.0.0.1:6379>JSON.GET对象“{\“foo\”:\“bar”,“ans\”:42}”127.0.0.1:6379>JSON.GET对象.ans“42”

RedisJSON的命令带有前缀。JSON.SET和JSON.GET都希望键的名称作为其第一个参数。在第一行中,我们将名为“scalar”的键的根(由句点字符“.”表示)设置为字符串值。接下来,使用JSON对象(首先读取整个对象)设置名为“object”的不同键,然后通过path设置单个子元素。

在引擎盖下,无论何时调用JSON.SET,模块都会通过流式lexer获取值,流式lexer解析输入JSON并构建一个树数据结构值:

RedisJSON以二进制格式将数据存储在树的节点中,并支持JSONPath方便子元素的引用。它拥有一个为每个JSON值类型量身定制的原子命令库,包括:

  • JSON。STRAPPEND用于追加字符串
  • JSON。NUMMULTBY用于数字相乘
  • 用于修剪数组的JSON.arrtim

因为RedisJSON是作为Redis模块实现的,所以您可以将其用于任何支持模块或允许发送原始命令的Redis客户端。例如,您可以使用Python代码中支持RedisJSON的Redis服务器redis py,如图所示:

import redis import json data={'foo':'bar','ans':42}r=redis.StrictRedis()r.execute_命令('json.SET','object','.','json.dumps(data))reply=json.loads(r.execute_命令('json.GET','object'))

最初的基准测试表明,RedisJSON在性能方面非常强大:

上面的图表比较了3.4KB JSON负载上三个嵌套级别的读写操作的速率(操作/秒)和平均延迟。RedisJSON与两种将数据存储在string中的变体相比较。这两种变体都实现为Redis服务器端Lua脚本json.lua存储原始序列化JSON的变量,以及msgpack.lua使用MessagePack编码。

重新开花

什么是Bloom过滤器?

Bloom过滤器是一种概率数据结构,它提供了一种有效的方法来验证条目不在集合中。这使得它在试图搜索昂贵的访问资源上的条目时特别有用,例如通过网络或磁盘。对于一个大的磁盘上的数据库,如果你想知道键“foo”是否存在,可以先查询Bloom过滤器。Bloom筛选器查询将确定地返回它是否可能存在(然后磁盘查找可以继续)或不存在,此时您可以放弃昂贵的磁盘查找,直接向堆栈发送一个否定的回复。

虽然可以使用其他数据结构来执行此操作,但Bloom过滤器也特别有用,因为它们每个元素占用的空间非常小,通常以比特数(而不是字节数!)计算。假阴性是不可能的,但一定比例的假阳性是可以控制的,但对于一组钥匙是否存在的初始测试,它们提供了极好的速度,最重要的是,极好的空间效率。

Bloom过滤器用于各种各样的应用:

  • 广告服务,确保用户不会经常看到广告;
  • 内容推荐系统,确保推荐不会经常出现,
  • 在访问磁盘上的表之前,快速检查表中是否存在表项。

Bloom过滤器的工作原理

大多数关于Bloom过滤器的文献使用高度符号和/或数学描述来描述它们。这里有另一种解释:

Bloom过滤器是由许多位组成的数组。当一个元素被“添加”到bloom过滤器时,该元素将被散列。然后位[哈希值%n位]设置为1。这看起来非常类似于哈希表中桶的映射方式。要检查项目是否存在,将计算哈希值,并检查过滤器是否设置了相应的位。

布卢姆滤波器图

当然,这是受碰撞影响的。如果发生冲突,筛选器将返回假阳性,表示找到了条目。重要的是要理解Bloom过滤器永远不会返回假阴性,换句话说,当某些东西实际上存在时,却声称它不存在。

为了减少冲突的风险,一个条目可能使用不止一位:条目被哈希每个元素的位(bpe)每次迭代都使用不同的种子,从而产生不同的哈希值。对于每个哈希值,设置相应的哈希%n位。为了检查条目是否存在,候选密钥也会被哈希bpe次,如果任何对应的位未设置,则可以确定该项不存在。

bpe的值在创建过滤器时确定。通常,每个元素的位数越多,误报的可能性越低。

布卢姆滤波器图

在上面的示例中,所有三位都需要设置,以便过滤器返回正结果。

Bloom过滤器的精度受填充比率的影响,或者过滤器中实际设置了多少位。当过滤器设置了绝大多数位时,任何特定查找返回false的可能性都会降低,同样,过滤器返回假阳性的可能性也会增加。

可伸缩Bloom过滤器

通常,在创建Bloom过滤器时,必须预先知道它们将包含多少项。bpe编号必须是固定的,同样,位数组的宽度也是固定的。

与哈希表不同,Bloom过滤器不能“重新平衡”,因为无法知道哪些条目是过滤器的一部分——过滤器可以确定给定条目是否不存在,但并不实际存储存在的条目。

为了使Bloom过滤器能够缩放并容纳比设计更多的元素,可以将其堆叠起来。一旦单个布卢姆过滤器达到容量,将在顶部创建一个新的布卢姆过滤器。通常,新过滤器的容量比前一个过滤器大,以减少需要堆叠另一个过滤器的可能性。

在一个可堆叠(可扩展)的Bloom过滤器中,检查成员现在包括检查每个层的存在。现在添加新项包括检查Bloom筛选器是否预先存在,并将值添加到当前筛选器。然而,哈希值仍然只需要计算一次。

在创建Bloom过滤器(即使是可伸缩的过滤器)时,重要的是要有一个大概的预期包含多少项。如果过滤器的初始层只能包含少量元素,则性能将显著下降,因为需要更多层才能达到更大的容量。

RedisBloom在行动

下面是一些RedisBloom工作的例子:

127.0.0.1:6379>BF.AddBloomMark 1)(整数)1127.0.0.1:6379>BF.AddBloomRedis 1)(整数)1127.0.0.1:6379>BF.EXISTS BloomMark(整数)1127.0.0.1:6379>BF.EXISTS BloomRedis Noexist(整数)0127.0.0.1:6379>BF.EXISTS Blooms Blooms Blooms que?(整数)0127.0.0.1:6379>BF.MADD bloom elem1 elem2 elem3 1)(整数)12)(整数)13)(整数)1127.0.0.1:6379>BF.MEXISTS bloom elem1 elem2 elem3 1)(整数)12)(整数)13)(整数)1

您还可以创建自定义Bloom过滤器。BF.ADD命令创建一个新的Bloom过滤器,适用于数量较少的项目。这会消耗更少的内存,但对于大型过滤器可能不太理想:

127.0.0.1:6379 >男朋友。储备大花0.0001 1000000 OK 127.0.1:6379> BF。ADD largebloom mark 1)(整数)1

基准、速度和实施

RedisBloom使用的是libloom,并进行了一些增强:

  • 我们发现,当测试是否存在时,libbloom将继续检查每个位,即使发现了未设置的位。在第一个未设置的位之后返回可提高性能。
  • 将哈希计算API与查找API分离意味着RedisBloom只需要计算哈希并将其提供给筛选器代码。
  • 下表显示了设置初始容量为10000、错误率为0.01、比例因子为2的单个Bloom过滤器的基准。测试使用单个客户端线程进行,并使用流水线,以尽可能避免网络/调度干扰:
实现 添加 检查
卢阿 29日k / s 25k/s
开花 250k/s 200 k / s
重新开花 400k/s 440k/s

创建自定义模块

模块里有什么

基本上,模块包含具有以下签名的命令处理程序-C函数:

int MyCommand(RedisModuleCtx*ctx,RedisModuleString**argv,int argc)

从签名中可以看出,函数返回一个整数,OK或ERR。通常,返回OK(即使向用户返回一个错误)就可以了。

命令处理程序接受再模数转换*对象。这个对象对模块开发人员是不透明的,但在内部它包含调用客户机的状态,甚至内部内存管理,我们将在后面介绍。下一个接收argv命令行参数个数,这些基本上是用户传递给被调用命令的参数。第一个参数是调用本身的名称,其余参数只是从Redis协议解析的参数。请注意,它们作为再分配对象也是不透明的。如果需要操作,可以将它们转换为普通的C字符串,并且不复制。

要激活模块的命令,模块的标准入口点是一个名为int RedisModule_OnLoad (RedisModuleCtx * ctx).这个函数告诉Redis模块中有哪些命令,并将它们映射到它们的处理程序。

编写一个模块

在本简短教程中,我们将重点介绍一个实现新Redis命令的模块的简单示例:HGETSET . HGETSET . HGETSETHGETSET是一个组合HGETHSET这使您可以检索哈希对象中的当前值,并在其位置原子地设置一个新值。这是非常基本的,也可以通过简单的事务或LUA脚本来完成,但是HGETSET具有非常简单的优点。

  1. 让我们从一个简单的命令处理程序开始:
int HGetSetCommand(RedisModuleCtx*ctx,RedisModuleString**argv,int argc){return REDISMODULE_OK;}

同样,这目前什么也不做,它只是返回OK代码。所以让我们给它一些实质内容。

  1. 验证参数

记住,我们的命令是HGETSET . HGETSET . HGETSET,这意味着它在argv中始终有四个参数。因此,让我们确保这确实是发生的:

/*HGETSET*/int HGetSetCommand(RedisModuleCtx*ctx,RedisModuleString**argv,int argc){if(argc!=4){return RedisModule_errority(ctx);}return RedisModule_OK;}

RedisModule_Errorarity将以以下形式向客户端返回标准错误:

(错误)“get”命令的参数数目错误。

  1. 激活自动记忆

Redis Modules API的一个重要特性是自动资源和内存管理。而模块作者可以独立分配和释放内存,调用RedisModule_AutoMemory允许你自动创建Redis资源和分配Redis字符串,关键字和响应在处理程序的生命周期。

RedisModule_AutoMemory (ctx);
  1. 执行一个Redis调用

现在我们运行两个Redis调用中的第一个,HGET. 我们将键和元素argv[1]和argv[2]作为参数传递。我们使用泛型重新分配模块调用命令,它只允许模块开发人员调用任何现有的Redis命令,很像Lua脚本:

RedisModuleCallReply *rep = RedisModule_Call(ctx, " HGET ", " ss ", argv[1], argv[2]);//如果RedisModule_CallReplyType(rep) == REDISMODULE_REPLY_ERROR) {return redismodule_replywithreply (ctx, srep);}

请注意,重新分配模块调用的第三个参数“ss”表示Redis应该如何对待传递给函数的可变参数。“党卫军”是指“两个再分配其他的说明符是“c”表示c字符串,“d”表示双精度,“l”表示长,以及“b”表示c缓冲区(字符串后跟其长度)。

现在让我们执行第二个Redis调用,HSET:

RedisModuleCallReply *srep = RedisModule_Call(ctx, " HSET ", " sss ", argv[1], argv[2], argv[3]);if (RedisModule_CallReplyType(srep) == REDISMODULE_REPLY_ERROR) {return redismodule_replywithreply (ctx, srep);}

使用HSET类似于HGET命令,只不过我们向它传递了三个参数。

  1. 返回结果

在这个简单的例子中,我们只需要返回HGET,或更改之前的值。这是通过一个简单的函数实现的,RedisModule_ReplyWithCallReply,将应答对象转发给客户端:

RedisModule_ReplyWithCallReply (ctx,代表);返回REDISMODULE_OK;}

就这样!我们的指挥人员准备好了;我们只需要正确注册模块和命令处理程序。

  1. 初始化模块

所有Redis模块的入口点都是一个名为RedisModule_OnLoad,开发人员必须实现。它注册并初始化模块,并向Redis注册其命令,以便调用它们。初始化模块的工作原理如下:

int RedisModule_OnLoad(redismodulex *ctx){//注册模块本身-它被称为' example '并且有一个API版本为1 if (RedisModule_Init(ctx, " example ", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR) {return REDISMODULE_ERR;} //注册我们的命令-它是一个写命令,一个键在argv[1] if (RedisModule_CreateCommand(ctx, " HGETSET ", HGetSetCommand, " write ", 1,1,1) == REDISMODULE_ERR) {return REDISMODULE_ERR;}返回REDISMODULE_OK;}

仅此而已!我们的模块完成了。

  1. 浅谈模块化建设

剩下的就是编译我们的模块。不必讨论为其创建makefile的细节,您需要知道的是Redis模块不需要特殊链接。一旦你包括了模块h文件并实现了入口点函数,这就是Redis加载模块所需的全部内容。任何其他链接由您决定。使用gcc编译此基本模块所需的命令有:

在Linux上:$gcc-fPIC-std=gnu99-c-o module.o module.c$ld-o module.so module.o-shared-Bsymbolic-lc在OSX上:$gcc-dynamic-fno common-std=gnu99-c-o module.o module.c$ld-o module.so module.o-bundle-undefined dynamic\u lookup-lc
  1. 加载模块

构建模块后,需要加载它。假设您已经从最新的稳定版本(支持模块)下载了Redis,您只需使用加载模块命令行参数:

/ / module.so redis-server loadmodule /路径

Redis现在正在运行,并加载了我们的模块。我们可以简单地连接到redis-cli并运行我们的命令!

获取来源

这里详细介绍的完整源代码可以作为RedisModuleSDK,它包括一个模块项目模板、makefile和一个实用程序库(带有一些函数,可以自动化一些关于编写原始API中不包含的模块的更枯燥的工作)。您不一定要使用它,但可以这样做。

Baidu