目录

目录 1

1. 前言 1

2. 优点 1

3. 方法一:使用struct 2

3.1. 设置初始值(覆盖原有的,如果存在) 2

3.2. 查询k1的值 2

3.3. 设置初始值(覆盖原有的,如果存在) 2

3.4. 查询k1的值 2

3.5. 增量操作(增1) 2

3.6. 查询k1的值 3

3.7. 增量操作(增1) 3

3.8. 查询k1的值 3

3.9. pack和unpack 3

3.10. AOF文件 3

3.11. 进化的增量操作 4

3.12. 进化的查询操作 4

4. 方法二:使用CJSON 5

5. 方法三:使用CMSGPACK 5

6. 方法四:借助Redis的module 5

6.1. 参考一:rediSQL 5

6.2. 参考二:ReJSON 5

1. 前言

一些应用场景需要对多个值进行原子计数,Redis的eval+hincrby可以达到目标,但如果计算的字段比较多时,效率会是个问题,它的时间复杂度为O(N),而且对于查询也同样如此。如果能将所有字段作为一个个struct成员,时间复杂度会固定下来。如果能象C/C++中的引用或指针操作,时间复杂度可以降低到O(1),否则考虑先get再set,这样时间复杂度为O(2),当字段数较多时,比如达到10个甚至更多时,相比O(N)就好了许多。

2. 优点

1)不需要hash,普通kv即可实现多字段的计数,而且是原子操作

2)当字段较多时,性能不会线性下降(hincrby多字段操作性能会线性下降,因为多字段hincrby操作时间复杂度为O(n))

3)当字段较多时,查询性能不变,保持为O(1)

3. 方法一:使用struct

3.1. 设置初始值(覆盖原有的,如果存在)

调用struct的pack函数打包(序列化)两个字段的值56和78,并将该struct赋值给本地变量a(注意Redis内的lua不支持全局变量,如果需要全局变通,可变通使用Redis的KV),然后将变量a作为k1的值设置进去。

127.0.0.1:6379> EVAL 'local a;a=struct.pack("ll",56,78);local x=redis.call("set","k1",a);return x;' 0

OK

3.2. 查询k1的值

因为struct是个二进制值,因为取到值时,需要先unpack反序列化(解包)。

127.0.0.1:6379> eval 'local x=redis.call("get","k1");local m,n=struct.unpack("ll",x);return {m,n}' 0

1) (integer) 56

2) (integer) 78

3.3. 设置初始值(覆盖原有的,如果存在)

127.0.0.1:6379> EVAL 'local a;a=struct.pack("lll",56,78,99);local x=redis.call("set","k1",a);return x;' 0

OK

3.4. 查询k1的值

127.0.0.1:6379> eval 'local x=redis.call("get","k1");local m,n,l=struct.unpack("lll",x);return {m,n,l}' 0

1) (integer) 56

2) (integer) 78

3) (integer) 99

3.5. 增量操作(增1)

这内含两个Redis操作:get和set两个操作,因此时间复杂度为O(2)。

127.0.0.1:6379> eval 'local x=redis.call("get","k1");local m,n,l=struct.unpack("lll",x);m=m+1;n=n+1;l=l+1;local a=struct.pack("lll",m,n,l);local z=redis.call("set","k1",a);return z;' 0

OK

3.6. 查询k1的值

127.0.0.1:6379> eval 'local x=redis.call("get","k1");local m,n,l=struct.unpack("lll",x);return {m,n,l}' 0

1) (integer) 57

2) (integer) 79

3) (integer) 100

3.7. 增量操作(增1)

127.0.0.1:6379> eval 'local x=redis.call("get","k1");local m,n,l=struct.unpack("lll",x);m=m+1;n=n+1;l=l+1;local a=struct.pack("lll",m,n,l);local z=redis.call("set","k1",a);return z;' 0

OK

3.8. 查询k1的值

127.0.0.1:6379> eval 'local x=redis.call("get","k1");local m,n,l=struct.unpack("lll",x);return {m,n,l}' 0

1) (integer) 58

2) (integer) 80

3) (integer) 101

3.9. pack和unpack

Redis内置支持struct,pack和unpack中的第一个参数为格式参数,其中单个“l”表示有符号long类型,大写的“L”则表示无符号的long类型,更多可以参见eval命令的说明:https://redis.io/commands/eval

3.10. AOF文件

上述操作对应的AOF文件内容:

$ tail -f appendonly-6379.aof 

*2

$6

SELECT

$1

0

*3

$4

EVAL

$76

local a;a=struct.pack("ll",56,78);local x=redis.call("set","k1",a);return x;

$1

0

*3

$4

EVAL

$80

local a;a=struct.pack("lll",56,78,99);local x=redis.call("set","k1",a);return x;

$1

0

*3

$4

eval

$159

local x=redis.call("get","k1");local m,n,l=struct.unpack("lll",x);m=m+1;n=n+1;l=l+1;local a=struct.pack("lll",m,n,l);local z=redis.call("set","k1",a);return z;

$1

0

*3

$4

eval

$159

local x=redis.call("get","k1");local m,n,l=struct.unpack("lll",x);m=m+1;n=n+1;l=l+1;local a=struct.pack("lll",m,n,l);local z=redis.call("set","k1",a);return z;

$1

0

3.11. 进化的增量操作

可用于生产环境的增量操作,允许被操作的key不存在(大小超过200字节):

eval 'local x=redis.call("get",KEYS[1]); local m,n,l;if (x) then m,n,l=struct.unpack("lll",x);m=m+ARGV[1];n=n+ARGV[2];l=l+ARGV[3]; else m=ARGV[1];n=ARGV[2];l=ARGV[3]; end; local a=struct.pack("lll",m,n,l);local z=redis.call("set",KEYS[1],a);return z;' 1 "k1" 1 2 3

3.12. 进化的查询操作

可用于生产环境的查询操作,允许被查询的key不存在:

eval 'local x=redis.call("get",KEYS[1]); if (x) then local m,n,l=struct.unpack("lll",x);return {m,n,l}; else return x; end;' 1 "k1"

4. 方法二:使用CJSON

暂略。

5. 方法三:使用CMSGPACK

暂略。

6. 方法四:借助Redis的module

6.1. 参考一:rediSQL

https://github.com/RedBeardLab/rediSQL

6.2. 参考二:ReJSON

https://github.com/RedisLabsModules/ReJSON

Redis基于eval的多字段原子增量计算的更多相关文章

  1. ODI基于源表时间戳字段获取增量数据

    实现目标:通过ODI获取一个没有时间戳的子表(qb_bw)的增量数据,而主表(qb_tb)有一个rksj入库时间,且主表和子表之间通过ID关联.目标表名是qb_bw1. 设计原理:通过在ODI的map ...

  2. Redis之eval+lua实现初步

    目录 目录 1 1. 前言 1 2. 执行方式 1 3. 执行过程 3 4. 使用原则 3 1. 前言 Redis的实现保证eval的执行是原子的,即使eval执行的lua超时,Redis也不会自动终 ...

  3. Particles.js基于Canvas画布创建粒子原子颗粒效果

    文章目录 使用方法 自定义参数 相关链接 Particles.js是一款基于HTML5 Canvas画布的轻量级粒子动画插件,可以设置粒子的形状.旋转.分布.颜色等属性,还可以动态添加粒子,效果非常炫 ...

  4. Redis基于Java的客户端SDK收集

    如果要找这类的SDK,第一反应应该直奔官网,找一下看下有什么推荐.先找最权威的回答,找不到再尝试民间方案. 就Redis来说,官方已经提供了一个列表包括市面上绝大多数语言的SDK,可以参考以下网址看J ...

  5. Others-大数据平台Lambda架构浅析(全量计算+增量计算)

    大数据平台Lambda架构浅析(全量计算+增量计算) 2016年12月23日 22:50:53 scuter_victor 阅读数:1642 标签: spark大数据lambda 更多 个人分类: 造 ...

  6. win7基于mahout推荐之用户相似度计算

    http://www.douban.com/note/319219518/?type=like win7基于mahout推荐之用户相似度计算 2013-12-03 09:19:11    事情回到半年 ...

  7. Atitit.基于时间戳的农历日历历法日期计算

    Atitit.基于时间戳的农历日历历法日期计算 1. 农历xx年的大小月份根据万年历查询1 2. 农历xx年1月1日的时间戳获取1 3. 计算当年的时间戳与农历日期的对应表,时间戳为key,日期为va ...

  8. [Redis] 基于redis的分布式锁

    前言分布式锁一般有三种实现方式:1. 数据库乐观锁:2. 基于Redis的分布式锁:3. 基于ZooKeeper的分布式锁.本篇博客将介绍第二种方式,基于Redis实现分布式锁. 可靠性首先,为了确保 ...

  9. Redis 使用 Eval 多个键值自增操作示例

    在PHP上使用Redis 给多个键值进行自增,示例如下: $set['money'] = $this->redis->hIncrByFloat($key, $hour .'_money', ...

随机推荐

  1. Xshell无法使用root远程登录Ubuntu16服务器

    修改/etc/ssh/sshd_config文件,把PermitRootLogin Prohibit-password 添加#注释掉 新添加:PermitRootLogin yes 2. 重启ssh服 ...

  2. sqlserver数据库的备份与还原——完整备份与还原

    sqlserver提供四种数据库备份方式 完整备份:备份整个数据库的所有内容包括书屋和日志 差异备份:只备份上次完整备份后更高的数据部分 事务日志备份:只备份事务日志里的内容 文件或文件组备份:只备份 ...

  3. 如何将你拍摄的照片转换成全景图及六面体(PTGui)

    在完成全景照片的拍摄之后,接下来,我们需要的是进行全景图的拼接.全景图片分为两种类型1.立方体全景图(6面体)制作全景时通常使用该种格式 如下图 2.球形图(2:1的单张全景图片)2:1全景图宽高比例 ...

  4. VS2013中Nuget程序包管理器控制台使用入门(二)-如何使用Nuget提供的帮助(原创)

    如何使用Nuget提供的帮助? 1.从get-help Nuget开始,键入“get-help NuGet”以查看所有可用的 NuGet 命令. 用法: PM> get-help Nuget 主 ...

  5. Oracle_PL/SQL(9) 例外处理

    例外处理1.例外分类:预定义例外,非预定义例外,自定义例外三种传递例外:如果在例外处理部分exception没有捕捉例外,oracle会将例外传递到调用环境.捕捉并处理例外:使用例外处理部分完成exc ...

  6. redis 哨兵(sentinel)

    redis哨兵 哨兵自动故障转移 自动通知应用最新master信息 无需担心,master挂了,程序不需要修改IP啥的,由哨兵自动完成 修改sentinel.conf protected-mode n ...

  7. m0n0wall 详细介绍

    pfSense就是基于m0n0wall m0n0wall,挺奇怪的软件名, M0n0wall是基于以性能和稳定性著称的FreeBSD内核的嵌入式的防火墙系统. m0n0wall对硬件要求很低,486芯 ...

  8. Ubuntu下实现gedit支持nesC语法高亮

    在TinyOS下主要采用nesC语言(C语言的一个变种)编程,ubuntu系统默认打开文本的工具是gedit,为实现gedit支持nesC语法高亮,将最下面的代码保存为nesC.lang文件,然后将n ...

  9. base64编码是什么

    首先明确一点base64 是一种编码格式.就想utf-8一样,能在电脑上表示所有字符,或者换句话说通过编码能让电脑理解你想要标识的字符(因为电脑只知道0和1 ) 就像ascII 中 0100 0001

  10. 实现WireCard支付

    实现WireCard支付,暂未完成 WireCardController.cs using System; using System.Collections.Generic; using System ...