INCR key

key 中储存的数字值增一。

如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作。

如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。

本操作的值限制在 64 位(bit)有符号数字表示之内。

这是一个针对字符串的操作,因为 Redis 没有专用的整数类型,所以 key 内储存的字符串被解释为十进制 64 位有符号整数来执行 INCR 操作。

可用版本:
>= 1.0.0
时间复杂度:
O(1)
返回值:
执行 INCR 命令之后 key 的值。

运行示例:

redis> SET page_view 20
OKredis> INCR page_view
(integer) 21redis> GET page_view    # 数字值在 Redis 中以字符串的形式保存
"21"

模式:计数器

计数器是 Redis 的原子性自增操作可实现的最直观的模式了,它的想法相当简单:每当某个操作发生时,向 Redis 发送一个 INCR 命令。

比如在一个 web 应用程序中,如果想知道用户在一年中每天的点击量,那么只要将用户 ID 以及相关的日期信息作为键,并在每次用户点击页面时,执行一次自增操作即可。

比如用户名是 peter ,点击时间是 2012 年 3 月 22 日,那么执行命令 INCR peter::2012.3.22

可以用以下几种方式扩展这个简单的模式:

  • 可以通过组合使用 INCR 和 EXPIRE ,来达到只在规定的生存时间内进行计数(counting)的目的。
  • 客户端可以通过使用 GETSET 命令原子性地获取计数器的当前值并将计数器清零,更多信息请参考 GETSET 命令。
  • 使用其他自增/自减操作,比如 DECRINCRBY ,用户可以通过执行不同的操作增加或减少计数器的值,比如在游戏中的记分器就可能用到这些命令。

模式:限速器

限速器是特殊化的计算器,它用于限制一个操作可以被执行的速率(rate)。

限速器的典型用法是限制公开 API 的请求次数,以下是一个限速器实现示例,它将 API 的最大请求数限制在每个 IP 地址每秒钟十个之内:

 1 FUNCTION LIMIT_API_CALL(ip)
 2 ts = CURRENT_UNIX_TIME()
 3 keyname = ip+":"+ts
 4 current = GET(keyname)
 5
 6 IF current != NULL AND current > 10 THEN
 7     ERROR "too many requests per second"
 8 END
 9
10 IF current == NULL THEN
11     MULTI
12         INCR(keyname, 1)
13         EXPIRE(keyname, 1)
14     EXEC
15 ELSE
16     INCR(keyname, 1)
17 END
18
19 PERFORM_API_CALL()

这个实现每秒钟为每个 IP 地址使用一个不同的计数器,并用 EXPIRE 命令设置生存时间(这样 Redis 就会负责自动删除过期的计数器)。

注意,我们使用事务打包执行 INCR 命令和 EXPIRE 命令,避免引入竞争条件,保证每次调用 API 时都可以正确地对计数器进行自增操作并设置生存时间。

以下是另一个限速器实现:

 1 FUNCTION LIMIT_API_CALL(ip):
 2 current = GET(ip)
 3 IF current != NULL AND current > 10 THEN
 4     ERROR "too many requests per second"
 5 ELSE
 6     value = INCR(ip)
 7     IF value == 1 THEN
 8         EXPIRE(ip,1)
 9     END
10     PERFORM_API_CALL()
11 END

这个限速器只使用单个计数器,它的生存时间为一秒钟,如果在一秒钟内,这个计数器的值大于 10 的话,那么访问就会被禁止。

这个新的限速器在思路方面是没有问题的,但它在实现方面不够严谨,如果我们仔细观察一下的话,就会发现在 INCREXPIRE 之间存在着一个竞争条件,假如客户端在执行 INCR 之后,因为某些原因(比如客户端失败)而忘记设置 EXPIRE 的话,那么这个计数器就会一直存在下去,造成每个用户只能访问 10 次,噢,这简直是个灾难!

要消灭这个实现中的竞争条件,我们可以将它转化为一个 Lua 脚本,并放到 Redis 中运行(这个方法仅限于 Redis 2.6 及以上的版本):

1 local current
2 current = redis.call("incr",KEYS[1])
3 if tonumber(current) == 1 then
4     redis.call("expire",KEYS[1],1)
5 end

通过将计数器作为脚本放到 Redis 上运行,我们保证了 INCREXPIRE 两个操作的原子性,现在这个脚本实现不会引入竞争条件,它可以运作的很好。

关于在 Redis 中运行 Lua 脚本的更多信息,请参考 EVAL 命令。

还有另一种消灭竞争条件的方法,就是使用 Redis 的列表结构来代替 INCR 命令,这个方法无须脚本支持,因此它在 Redis 2.6 以下的版本也可以运行得很好:

 1 FUNCTION LIMIT_API_CALL(ip)
 2 current = LLEN(ip)
 3 IF current > 10 THEN
 4     ERROR "too many requests per second"
 5 ELSE
 6     IF EXISTS(ip) == FALSE
 7         MULTI
 8             RPUSH(ip,ip)
 9             EXPIRE(ip,1)
10         EXEC
11     ELSE
12         RPUSHX(ip,ip)
13     END
14     PERFORM_API_CALL()
15 END

新的限速器使用了列表结构作为容器, LLEN 用于对访问次数进行检查,一个事务包裹着 RPUSHEXPIRE 两个命令,用于在第一次执行计数时创建列表,并正确设置地设置过期时间,最后, RPUSHX 在后续的计数操作中进行增加操作。

本文参考自:http://doc.redisfans.com/string/incr.html#incr

转载于:https://www.cnblogs.com/abc-begin/p/7896452.html

redis命令_INCR相关推荐

  1. Redis 命令整理

    Redis 命令整理 一.从大而全的方向看,完整的命令查看文档地址: http://doc.redisfans.com/ 二.Redis 键(key)   常用 案例 三.Redis 字符串(Stri ...

  2. redis命令_Redis 命令执行过程(下)

    点击上方"程序员历小冰",选择"置顶或者星标" 你的关注意义重大! 在上一篇文章中<Redis 命令执行过程(上)>中,我们首先了解 Redis 命 ...

  3. Redis 命令参考

    Redis 命令参考 本文档是 Redis Command Reference 和 Redis Documentation 的中文翻译版, 阅读这个文档可以帮助你了解 Redis 命令的具体使用方法, ...

  4. 不到 10 个提升逼格的 Redis 命令

    keys 我把这个命令放在第一位,是因为笔者曾经做过的项目,以及一些朋友的项目,都因为使用keys这个命令,导致出现性能毛刺.这个命令的时间复杂度是O(N),而且redis又是单线程执行,在执行key ...

  5. linux连接redis 命令_在Docker中使用Redis

    1. 简介 本文章将介绍如何使用 Docker 探索 Redis.我们可以在 Docker for Windows .Docker for mac 或者 Linux 模式下运行 Docker 命令. ...

  6. Redis命令参考简体中文版

    Redis命令参考简体中文版 本文是huangz1990对<Redis Command Reference>的简体中文翻译版. 原文:http://redis.readthedocs.or ...

  7. linux 关闭redis 命令_redis----------linux和mac如何安装redis和启动,关闭

    1.打开官网https://redis.io/download.官网有安装命令 2.以下是我的执行过程截图 执行完官网给的命令以后,再执行  make PREFIX=/usr/local/redis ...

  8. Redis命令:SETNX key value(SET if Not eXists)

    起始版本:1.0.0 时间复杂度:O(1) 将key设置值为value,如果key不存在,这种情况下等同SET命令. 当key存在时,什么也不做.SETNX是"SET if Not eXis ...

  9. Lua 脚本内部执行 Redis 命令

    Lua 脚本内部允许通过内置函数执行 Redis 命令: redis.call() redis.pcall() 两者非常相似,区别在于: 若 Redis 命令执行错误,redis.call() 将错误 ...

  10. Redis-学习笔记02【Redis命令操作】

    Java后端 学习路线 笔记汇总表[黑马程序员] Redis-学习笔记01[Redis环境搭建] Redis-学习笔记02[Redis命令操作] Redis-学习笔记03[Redis持久化] Redi ...

最新文章

  1. iOS-直播开发(开发从底层做起)
  2. oracle 11g备份,导入oracle 10g
  3. 动态修改dom node的两种方法性能比较
  4. wince中BIB文件的详细介绍
  5. RabbitMq队列 queue
  6. 25个关键技术点,带你熟悉Python
  7. epoll的一个使用例子
  8. 【转载】Apache如何设置访问一个目录需要密码
  9. Unity实时涂鸦绘画插件:RealTime Painting
  10. 串行通信:常见的串行通信接口协议UART、SPI、I2C简介
  11. php使用gd库合并图片,php使用GD库合并简单图片并变动部分颜色
  12. 软件测试与代码安全详解
  13. 有关网络安全基础知识
  14. Centos7下新硬盘的挂载操作
  15. 史上最详细的LXR安装介绍
  16. ArcGIS如何创建渔网?渔网不见了。
  17. 不讲武德!为击破苹果的“隐私高墙”,谷歌、Facebook 竟然“二打一”?
  18. 抖音短视频KOL玩法.优质抖音KOL
  19. 笑傲江湖中的政治斗争
  20. Java中定义抽象类Shape,其中包含抽象方法double getPeremeter( )求周长和double getArea( )求面积。 定义一个矩形类,继承此抽象类,并自行扩充成员变量和方法。

热门文章

  1. 游戏筑基开发之字符串的注意点(C语言)
  2. HW浮动静态路由及负载均衡
  3. KVM详解(六)——KVM虚拟机快照
  4. WLAN加密技术详解
  5. 从10秒到2秒!ElasticSearch性能调优实践
  6. 解决连接本地oracle无监听的问题
  7. 科大讯飞发布会,我看到的人工智能
  8. Redis系列四 Redis常见配置
  9. Gson 与 fastJson 在使用上的差异(fastJson的优点)
  10. [转]如何:定义和处理 SOAP 标头