├── .gitignore ├── Makefile ├── about.include ├── change_log.rst ├── conf.py ├── connection ├── auth.rst ├── echo.rst ├── index.rst ├── ping.rst ├── quit.rst └── select.rst ├── course.include ├── cover.jpg ├── der ├── README.rst ├── disqus.html ├── layout.html ├── static │ ├── 42qu.png │ ├── dialog-note.png │ ├── dialog-seealso.png │ ├── dialog-topic.png │ ├── dialog-warning.png │ ├── epub.css │ ├── footerbg.png │ ├── headerbg.png │ ├── ie6.css │ ├── middlebg.png │ ├── pyramid.css_t │ └── transparent.gif └── theme.conf ├── donation.include ├── download └── redis.pdf ├── ebookindex.rst ├── hash ├── hdel.rst ├── hexists.rst ├── hget.rst ├── hgetall.rst ├── hincrby.rst ├── hincrbyfloat.rst ├── hkeys.rst ├── hlen.rst ├── hmget.rst ├── hmset.rst ├── hscan.rst ├── hset.rst ├── hsetnx.rst ├── hvals.rst └── index.rst ├── index.rst ├── intro.include ├── key ├── _user_info_table.include ├── del.rst ├── dump.rst ├── exists.rst ├── expire.rst ├── expireat.rst ├── index.rst ├── keys.rst ├── migrate.rst ├── move.rst ├── object.rst ├── persist.rst ├── pexpire.rst ├── pexpireat.rst ├── pttl.rst ├── randomkey.rst ├── rename.rst ├── renamenx.rst ├── restore.rst ├── scan.rst ├── sort.rst ├── ttl.rst └── type.rst ├── list ├── blpop.rst ├── brpop.rst ├── brpoplpush.rst ├── index.rst ├── lindex.rst ├── linsert.rst ├── llen.rst ├── lpop.rst ├── lpush.rst ├── lpushx.rst ├── lrange.rst ├── lrem.rst ├── lset.rst ├── ltrim.rst ├── rpop.rst ├── rpoplpush.rst ├── rpush.rst └── rpushx.rst ├── make.bat ├── pay_to_huangz.png ├── pub_sub ├── index.rst ├── psubscribe.rst ├── publish.rst ├── pubsub.rst ├── punsubscribe.rst ├── subscribe.rst └── unsubscribe.rst ├── readme.rst ├── redis-logo.jpg ├── script ├── eval.rst ├── evalsha.rst ├── index.rst ├── script_exists.rst ├── script_flush.rst ├── script_kill.rst └── script_load.rst ├── server ├── bgrewriteaof.rst ├── bgsave.rst ├── client_getname.rst ├── client_kill.rst ├── client_list.rst ├── client_setname.rst ├── config_get.rst ├── config_resetstat.rst ├── config_rewrite.rst ├── config_set.rst ├── dbsize.rst ├── debug_object.rst ├── debug_segfault.rst ├── flushall.rst ├── flushdb.rst ├── index.rst ├── info.rst ├── lastsave.rst ├── monitor.rst ├── psync.rst ├── save.rst ├── shutdown.rst ├── slaveof.rst ├── slowlog.rst ├── sync.rst └── time.rst ├── set ├── index.rst ├── sadd.rst ├── scard.rst ├── sdiff.rst ├── sdiffstore.rst ├── sinter.rst ├── sinterstore.rst ├── sismember.rst ├── smembers.rst ├── smove.rst ├── spop.rst ├── srandmember.rst ├── srem.rst ├── sscan.rst ├── sunion.rst └── sunionstore.rst ├── sorted_set ├── index.rst ├── zadd.rst ├── zcard.rst ├── zcount.rst ├── zincrby.rst ├── zinterstore.rst ├── zrange.rst ├── zrangebyscore.rst ├── zrank.rst ├── zrem.rst ├── zremrangebyrank.rst ├── zremrangebyscore.rst ├── zrevrange.rst ├── zrevrangebyscore.rst ├── zrevrank.rst ├── zscan.rst ├── zscore.rst └── zunionstore.rst ├── string ├── append.rst ├── bitcount.rst ├── bitop.rst ├── decr.rst ├── decrby.rst ├── get.rst ├── getbit.rst ├── getrange.rst ├── getset.rst ├── incr.rst ├── incrby.rst ├── incrbyfloat.rst ├── index.rst ├── mget.rst ├── mset.rst ├── msetnx.rst ├── psetex.rst ├── set.rst ├── setbit.rst ├── setex.rst ├── setnx.rst ├── setrange.rst └── strlen.rst ├── tdir.include ├── topic ├── cluster-spec.rst ├── cluster-tutorial.rst ├── notification.rst ├── persistence.rst ├── protocol.rst ├── pubsub.rst ├── replication.rst ├── sentinel.rst └── transaction.rst └── transaction ├── discard.rst ├── exec.rst ├── index.rst ├── multi.rst ├── unwatch.rst └── watch.rst /.gitignore: -------------------------------------------------------------------------------- 1 | _build/ 2 | *.swp 3 | -------------------------------------------------------------------------------- /about.include: -------------------------------------------------------------------------------- 1 | 关于 2 | ------- 3 | 4 | 本文档由 `huangz `_ 翻译, 5 | 版权归 Redis 官方所有。 6 | 7 | 关注 `文档的 github 项目 `_ 可以随时追踪文档的最新更新, 8 | 有任何问题、意见或建议, 9 | 可以在文档配套的 disqus 论坛里留言, 10 | 或者直接联系译者。 11 | -------------------------------------------------------------------------------- /change_log.rst: -------------------------------------------------------------------------------- 1 | .. _change_log: 2 | 3 | 更新日志(change log) 4 | ========================= 5 | 6 | 2013 年 12 月(Redis 2.8) 7 | ----------------------------- 8 | 9 | Redis 2.8 带来的更新: 10 | 11 | - 添加 :ref:`SCAN` 命令、 :ref:`SSCAN` 命令、 :ref:`HSCAN` 命令和 :ref:`ZSCAN` 命令。 12 | 13 | - 添加 :ref:`config_rewrite` 命令。 14 | 15 | - 添加 :ref:`pubsub` 命令。 16 | 17 | - 添加 :ref:`client_setname` 命令和 :ref:`client_getname` 命令。 18 | 19 | - 修改 :ref:`ttl` 和 :ref:`pttl` 命令的返回值。 20 | 21 | 文档本身的更新: 22 | 23 | - 开始翻译 Redis 的主题(topic)文档: 24 | 目前已经完成了 :ref:`cluster_tutorial` 、 :ref:`sentinel` 、 :ref:`replication_topic` 、 :ref:`persistence` 等主要文档, 25 | 未来还会翻译更多主题文档。 26 | 27 | - 支持 PDF 格式的离线文档下载。 28 | 29 | - 添加捐款连接。 30 | 31 | 2012 年 4 月(Redis 2.6) 32 | -------------------------- 33 | 34 | 此次更新的主要内容来自于 Redis 2.6 版本: 35 | 36 | - 2.6 版本新增的所有命令(EVAL 、 SCRIPT * 、 TIME 、 PTTL 等)的相关文档全部翻译完毕。 37 | - 2.6 版本新添加的几个应用模式,比如 INCR 命令的计数器模式和限速器模式、 EXPIRE 命令的导航会话模型等,全部翻译完毕。 38 | - 2.6 版本对旧有命令的改进,比如为 SHUTDOWN 添加修饰符、为 INFO 设置新的输出格式 、 CONFIG RESETSTAT 的变动等,这些命令的文档全部翻译/更新完毕。 39 | - 对代码示例及其注释进行了很多修改和重排版,让代码示例更直观。 40 | 41 | 文档自身的更新: 42 | 43 | - 添加 disqus 评论功能。 44 | - 命令不再按类型分页,而是每个命令各一页,载入速度更快。 45 | - 添加进度表,随时了解项目最新动态。 46 | 47 | 2011 年 12 月(Redis 2.4) 48 | -------------------------- 49 | 50 | 完成 pub/sub 、 transaction 、 connection 和 server 四个部分的翻译。 51 | 52 | 2011 年 10 月(Redis 2.4) 53 | -------------------------- 54 | 55 | 更新命令到 Redis 2.4 版本。 56 | 57 | 2011 年 6 月(Redis 2.2) 58 | -------------------------- 59 | 60 | 完成 keys 、 string 、 list 、 set 和 sorted set 六个部分的翻译。 61 | 62 | 2011 年 4 月(Redis 2.2) 63 | -------------------------- 64 | 65 | 开始进行 Redis 命令参考的翻译工作。 66 | -------------------------------------------------------------------------------- /connection/auth.rst: -------------------------------------------------------------------------------- 1 | .. _auth: 2 | 3 | AUTH 4 | ===== 5 | 6 | **AUTH password** 7 | 8 | 通过设置配置文件中 ``requirepass`` 项的值(使用命令 ``CONFIG SET requirepass password`` ),可以使用密码来保护 Redis 服务器。 9 | 10 | 如果开启了密码保护的话,在每次连接 Redis 服务器之后,就要使用 ``AUTH`` 命令解锁,解锁之后才能使用其他 Redis 命令。 11 | 12 | 如果 ``AUTH`` 命令给定的密码 ``password`` 和配置文件中的密码相符的话,服务器会返回 ``OK`` 并开始接受命令输入。 13 | 14 | 另一方面,假如密码不匹配的话,服务器将返回一个错误,并要求客户端需重新输入密码。 15 | 16 | .. warning:: 因为 Redis 高性能的特点,在很短时间内尝试猜测非常多个密码是有可能的,因此请确保使用的密码足够复杂和足够长,以免遭受密码猜测攻击。 17 | 18 | **可用版本:** 19 | >= 1.0.0 20 | 21 | **时间复杂度:** 22 | O(1) 23 | 24 | **返回值:** 25 | 密码匹配时返回 ``OK`` ,否则返回一个错误。 26 | 27 | :: 28 | 29 | # 设置密码 30 | 31 | redis> CONFIG SET requirepass secret_password # 将密码设置为 secret_password 32 | OK 33 | 34 | redis> QUIT # 退出再连接,让新密码对客户端生效 35 | 36 | [huangz@mypad]$ redis 37 | 38 | redis> PING # 未验证密码,操作被拒绝 39 | (error) ERR operation not permitted 40 | 41 | redis> AUTH wrong_password_testing # 尝试输入错误的密码 42 | (error) ERR invalid password 43 | 44 | redis> AUTH secret_password # 输入正确的密码 45 | OK 46 | 47 | redis> PING # 密码验证成功,可以正常操作命令了 48 | PONG 49 | 50 | 51 | # 清空密码 52 | 53 | redis> CONFIG SET requirepass "" # 通过将密码设为空字符来清空密码 54 | OK 55 | 56 | redis> QUIT 57 | 58 | $ redis # 重新进入客户端 59 | 60 | redis> PING # 执行命令不再需要密码,清空密码操作成功 61 | PONG 62 | -------------------------------------------------------------------------------- /connection/echo.rst: -------------------------------------------------------------------------------- 1 | .. _echo: 2 | 3 | ECHO 4 | ======= 5 | 6 | **ECHO message** 7 | 8 | 打印一个特定的信息 ``message`` ,测试时使用。 9 | 10 | **可用版本:** 11 | >= 1.0.0 12 | 13 | **时间复杂度:** 14 | O(1) 15 | 16 | **返回值:** 17 | ``message`` 自身。 18 | 19 | :: 20 | 21 | redis> ECHO "Hello Moto" 22 | "Hello Moto" 23 | 24 | redis> ECHO "Goodbye Moto" 25 | "Goodbye Moto" 26 | -------------------------------------------------------------------------------- /connection/index.rst: -------------------------------------------------------------------------------- 1 | Connection(连接) 2 | ====================== 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | 7 | auth 8 | echo 9 | ping 10 | quit 11 | select 12 | -------------------------------------------------------------------------------- /connection/ping.rst: -------------------------------------------------------------------------------- 1 | .. _ping: 2 | 3 | PING 4 | ====== 5 | 6 | **PING** 7 | 8 | 使用客户端向 Redis 服务器发送一个 ``PING`` ,如果服务器运作正常的话,会返回一个 ``PONG`` 。 9 | 10 | 通常用于测试与服务器的连接是否仍然生效,或者用于测量延迟值。 11 | 12 | **可用版本:** 13 | >= 1.0.0 14 | 15 | **时间复杂度:** 16 | O(1) 17 | 18 | **返回值:** 19 | 如果连接正常就返回一个 ``PONG`` ,否则返回一个连接错误。 20 | 21 | :: 22 | 23 | # 客户端和服务器连接正常 24 | 25 | redis> PING 26 | PONG 27 | 28 | # 客户端和服务器连接不正常(网络不正常或服务器未能正常运行) 29 | 30 | redis 127.0.0.1:6379> PING 31 | Could not connect to Redis at 127.0.0.1:6379: Connection refused 32 | -------------------------------------------------------------------------------- /connection/quit.rst: -------------------------------------------------------------------------------- 1 | .. _quit: 2 | 3 | QUIT 4 | ====== 5 | 6 | **QUIT** 7 | 8 | 请求服务器关闭与当前客户端的连接。 9 | 10 | 一旦所有等待中的回复(如果有的话)顺利写入到客户端,连接就会被关闭。 11 | 12 | **可用版本:** 13 | >= 1.0.0 14 | 15 | **时间复杂度:** 16 | O(1) 17 | 18 | **返回值:** 19 | 总是返回 ``OK`` (但是不会被打印显示,因为当时 Redis-cli 已经退出)。 20 | 21 | :: 22 | 23 | $ redis 24 | 25 | redis> QUIT 26 | 27 | $ 28 | -------------------------------------------------------------------------------- /connection/select.rst: -------------------------------------------------------------------------------- 1 | .. _select: 2 | 3 | SELECT 4 | ======== 5 | 6 | **SELECT index** 7 | 8 | 切换到指定的数据库,数据库索引号 ``index`` 用数字值指定,以 ``0`` 作为起始索引值。 9 | 10 | 默认使用 ``0`` 号数据库。 11 | 12 | **可用版本:** 13 | >= 1.0.0 14 | 15 | **时间复杂度:** 16 | O(1) 17 | 18 | **返回值:** 19 | ``OK`` 20 | 21 | :: 22 | 23 | redis> SET db_number 0 # 默认使用 0 号数据库 24 | OK 25 | 26 | redis> SELECT 1 # 使用 1 号数据库 27 | OK 28 | 29 | redis[1]> GET db_number # 已经切换到 1 号数据库,注意 Redis 现在的命令提示符多了个 [1] 30 | (nil) 31 | 32 | redis[1]> SET db_number 1 33 | OK 34 | 35 | redis[1]> GET db_number 36 | "1" 37 | 38 | redis[1]> SELECT 3 # 再切换到 3 号数据库 39 | OK 40 | 41 | redis[3]> # 提示符从 [1] 改变成了 [3] 42 | -------------------------------------------------------------------------------- /course.include: -------------------------------------------------------------------------------- 1 | .. note:: 2 | 3 | .. image:: redis-logo.jpg 4 | :align: left 5 | :scale: 50 6 | 7 | 由本文档翻译者 huangz 主讲的 Redis 课程 —— 《Redis 从入门到精通》现正接受报名: http://www.chinahadoop.cn/course/53 。 8 | 9 | 课程的内容由浅入深, 10 | 覆盖了 Redis 的应用、配置、管理和运行原理等各个方面, 11 | 旨在帮助 Redis 的初、中级使用者全面地了解 Redis , 12 | 欢迎各位踊跃报名。 13 | -------------------------------------------------------------------------------- /cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/me115/redis/97747be488c7857e241d14b69ee5d3088bbe8136/cover.jpg -------------------------------------------------------------------------------- /der/README.rst: -------------------------------------------------------------------------------- 1 | DER 2 | ===================== 3 | 4 | ``DER == reverse("RED")`` 5 | 6 | 本项目是 `《Redis 设计与实现》 `_ 所使用的 Sphinx 样式。 7 | 8 | 样式特点: 9 | 10 | - 单色调简单风格(默认为红色,但很容易就可以修改成其他颜色) 11 | 12 | - 醒目的 ``h1`` 标题 13 | 14 | - 清晰的、可以高效地对文本进行视线分割的 ``h2`` 标题 15 | 16 | - 固定大小、居中显示、百分比字体大小,布局健壮,适用于多种不同的屏幕环境 17 | 18 | 19 | 使用方法 20 | --------------------- 21 | 22 | 1. 克隆本项目。 23 | 24 | 2. 修改 sphinx 项目 ``conf.py`` 文件中的 ``html_theme_path`` 变量,让它指向 ``der`` 文件夹所在的位置。 25 | 26 | 3. 修改 sphinx 项目 ``conf.py`` 文件中的 ``html_theme`` 变量的值为 ``der`` 。 27 | 28 | 4. 完成! 29 | 30 | 31 | 开启 disqus 支持 32 | --------------------- 33 | 34 | 1. 编辑 ``der`` 文件夹中的 ``layout.html`` 文件,修改文件中和 disqus 有关的语句: 35 | 36 | :: 37 | 38 | {# note: remove this comment if you want to enable disqus support 39 | 40 | {% include "disqus.html" %} 41 | 42 | #} 43 | 44 | 只保留这一句: 45 | 46 | :: 47 | 48 | {% include "disqus.html" %} 49 | 50 | 2. 编辑 ``der`` 文件夹中的 ``disqus.html`` 文件,将其中的 51 | 52 | :: 53 | 54 | var disqus_shortname = 'YOUR-DISQUS-FORUM-SHORTNAME'; 55 | 56 | 中的 ``YOUR-DISQUS-FORUM-SHORTNAME`` 替换成你的 disqus 论坛的名字。 57 | 58 | 3. 完成! 59 | 60 | 61 | 使用许可 62 | --------------------- 63 | 64 | 本样式修改自 `Sphinx `_ 项目自带的 pyramid 样式, 65 | 使用与源项目同样的 BSD 协议发布。 66 | 67 | | Copyright (c) 2013, huangz 68 | | All rights reserved. 69 | 70 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 71 | 72 | - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 73 | 74 | - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 75 | 76 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 77 | -------------------------------------------------------------------------------- /der/disqus.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |

4 | 讨论 5 | 6 |

7 | 8 |
9 | 20 | 21 | comments powered by Disqus 22 |
23 | 24 | 36 | -------------------------------------------------------------------------------- /der/static/42qu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/me115/redis/97747be488c7857e241d14b69ee5d3088bbe8136/der/static/42qu.png -------------------------------------------------------------------------------- /der/static/dialog-note.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/me115/redis/97747be488c7857e241d14b69ee5d3088bbe8136/der/static/dialog-note.png -------------------------------------------------------------------------------- /der/static/dialog-seealso.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/me115/redis/97747be488c7857e241d14b69ee5d3088bbe8136/der/static/dialog-seealso.png -------------------------------------------------------------------------------- /der/static/dialog-topic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/me115/redis/97747be488c7857e241d14b69ee5d3088bbe8136/der/static/dialog-topic.png -------------------------------------------------------------------------------- /der/static/dialog-warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/me115/redis/97747be488c7857e241d14b69ee5d3088bbe8136/der/static/dialog-warning.png -------------------------------------------------------------------------------- /der/static/footerbg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/me115/redis/97747be488c7857e241d14b69ee5d3088bbe8136/der/static/footerbg.png -------------------------------------------------------------------------------- /der/static/headerbg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/me115/redis/97747be488c7857e241d14b69ee5d3088bbe8136/der/static/headerbg.png -------------------------------------------------------------------------------- /der/static/ie6.css: -------------------------------------------------------------------------------- 1 | * html img, 2 | * html .png{position:relative;behavior:expression((this.runtimeStyle.behavior="none")&&(this.pngSet?this.pngSet=true:(this.nodeName == "IMG" && this.src.toLowerCase().indexOf('.png')>-1?(this.runtimeStyle.backgroundImage = "none", 3 | this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.src + "',sizingMethod='image')", 4 | this.src = "_static/transparent.gif"):(this.origBg = this.origBg? this.origBg :this.currentStyle.backgroundImage.toString().replace('url("','').replace('")',''), 5 | this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.origBg + "',sizingMethod='crop')", 6 | this.runtimeStyle.backgroundImage = "none")),this.pngSet=true) 7 | );} 8 | -------------------------------------------------------------------------------- /der/static/middlebg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/me115/redis/97747be488c7857e241d14b69ee5d3088bbe8136/der/static/middlebg.png -------------------------------------------------------------------------------- /der/static/transparent.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/me115/redis/97747be488c7857e241d14b69ee5d3088bbe8136/der/static/transparent.gif -------------------------------------------------------------------------------- /der/theme.conf: -------------------------------------------------------------------------------- 1 | [theme] 2 | inherit = basic 3 | stylesheet = pyramid.css 4 | pygments_style = sphinx.pygments_styles.PyramidStyle 5 | 6 | [options] 7 | color = #C52F24 8 | -------------------------------------------------------------------------------- /donation.include: -------------------------------------------------------------------------------- 1 | 通过捐款支持本文档 2 | ----------------------- 3 | 4 | 对 Redis 的文档更新进行追踪并及时地进行翻译需要花费大量的时间和精力, 5 | 如果你喜欢这个《Redis 命令参考》文档的话, 6 | 可以通过捐款的方式, 7 | 支持译者继续对 Redis 文档进行翻译, 8 | 并将这个文档更好地维护下去。 9 | 10 | 你可以通过使用\ `支付宝钱包 `_\ 扫描以下二维码来进行捐款, 11 | 或者通过向支付宝帐号 huangz1990@gmail.com 转帐来进行捐款。 12 | 13 | .. image:: pay_to_huangz.png 14 | -------------------------------------------------------------------------------- /download/redis.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/me115/redis/97747be488c7857e241d14b69ee5d3088bbe8136/download/redis.pdf -------------------------------------------------------------------------------- /ebookindex.rst: -------------------------------------------------------------------------------- 1 | Redis 命令参考 2 | =================== 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | 7 | key/index 8 | string/index 9 | hash/index 10 | list/index 11 | set/index 12 | sorted_set/index 13 | pub_sub/index 14 | transaction/index 15 | script/index 16 | connection/index 17 | server/index 18 | topic/notification 19 | topic/transaction 20 | topic/pubsub 21 | topic/replication 22 | topic/protocol 23 | topic/persistence 24 | topic/sentinel 25 | topic/cluster-tutorial 26 | topic/cluster-spec 27 | 28 | .. include:: about.include 29 | 30 | .. include:: intro.include 31 | 32 | .. include:: donation.include 33 | -------------------------------------------------------------------------------- /hash/hdel.rst: -------------------------------------------------------------------------------- 1 | .. _hdel: 2 | 3 | HDEL 4 | ===== 5 | 6 | **HDEL key field [field ...]** 7 | 8 | 删除哈希表 ``key`` 中的一个或多个指定域,不存在的域将被忽略。 9 | 10 | .. note:: 在Redis2.4以下的版本里, `HDEL`_ 每次只能删除单个域,如果你需要在一个原子时间内删除多个域,请将命令包含在 :ref:`MULTI` / :ref:`EXEC` 块内。 11 | 12 | **可用版本:** 13 | >= 2.0.0 14 | 15 | **时间复杂度:** 16 | O(N), ``N`` 为要删除的域的数量。 17 | 18 | **返回值:** 19 | 被成功移除的域的数量,不包括被忽略的域。 20 | 21 | :: 22 | 23 | # 测试数据 24 | 25 | redis> HGETALL abbr 26 | 1) "a" 27 | 2) "apple" 28 | 3) "b" 29 | 4) "banana" 30 | 5) "c" 31 | 6) "cat" 32 | 7) "d" 33 | 8) "dog" 34 | 35 | 36 | # 删除单个域 37 | 38 | redis> HDEL abbr a 39 | (integer) 1 40 | 41 | 42 | # 删除不存在的域 43 | 44 | redis> HDEL abbr not-exists-field 45 | (integer) 0 46 | 47 | 48 | # 删除多个域 49 | 50 | redis> HDEL abbr b c 51 | (integer) 2 52 | 53 | redis> HGETALL abbr 54 | 1) "d" 55 | 2) "dog" 56 | -------------------------------------------------------------------------------- /hash/hexists.rst: -------------------------------------------------------------------------------- 1 | .. _hexists: 2 | 3 | HEXISTS 4 | ======== 5 | 6 | **HEXISTS key field** 7 | 8 | 查看哈希表 ``key`` 中,给定域 ``field`` 是否存在。 9 | 10 | **可用版本:** 11 | >= 2.0.0 12 | 13 | **时间复杂度:** 14 | O(1) 15 | 16 | **返回值:** 17 | | 如果哈希表含有给定域,返回 ``1`` 。 18 | | 如果哈希表不含有给定域,或 ``key`` 不存在,返回 ``0`` 。 19 | 20 | :: 21 | 22 | redis> HEXISTS phone myphone 23 | (integer) 0 24 | 25 | redis> HSET phone myphone nokia-1110 26 | (integer) 1 27 | 28 | redis> HEXISTS phone myphone 29 | (integer) 1 30 | -------------------------------------------------------------------------------- /hash/hget.rst: -------------------------------------------------------------------------------- 1 | .. _hget: 2 | 3 | HGET 4 | ===== 5 | 6 | **HGET key field** 7 | 8 | 返回哈希表 ``key`` 中给定域 ``field`` 的值。 9 | 10 | **可用版本:** 11 | >= 2.0.0 12 | 13 | **时间复杂度:** 14 | O(1) 15 | 16 | **返回值:** 17 | | 给定域的值。 18 | | 当给定域不存在或是给定 ``key`` 不存在时,返回 ``nil`` 。 19 | 20 | :: 21 | 22 | # 域存在 23 | 24 | redis> HSET site redis redis.com 25 | (integer) 1 26 | 27 | redis> HGET site redis 28 | "redis.com" 29 | 30 | 31 | # 域不存在 32 | 33 | redis> HGET site mysql 34 | (nil) 35 | -------------------------------------------------------------------------------- /hash/hgetall.rst: -------------------------------------------------------------------------------- 1 | .. _hgetall: 2 | 3 | HGETALL 4 | ======= 5 | 6 | **HGETALL key** 7 | 8 | 返回哈希表 ``key`` 中,所有的域和值。 9 | 10 | 在返回值里,紧跟每个域名(field name)之后是域的值(value),所以返回值的长度是哈希表大小的两倍。 11 | 12 | **可用版本:** 13 | >= 2.0.0 14 | 15 | **时间复杂度:** 16 | O(N), ``N`` 为哈希表的大小。 17 | 18 | **返回值:** 19 | | 以列表形式返回哈希表的域和域的值。 20 | | 若 ``key`` 不存在,返回空列表。 21 | 22 | :: 23 | 24 | redis> HSET people jack "Jack Sparrow" 25 | (integer) 1 26 | 27 | redis> HSET people gump "Forrest Gump" 28 | (integer) 1 29 | 30 | redis> HGETALL people 31 | 1) "jack" # 域 32 | 2) "Jack Sparrow" # 值 33 | 3) "gump" 34 | 4) "Forrest Gump" 35 | -------------------------------------------------------------------------------- /hash/hincrby.rst: -------------------------------------------------------------------------------- 1 | .. _hincrby: 2 | 3 | HINCRBY 4 | ======== 5 | 6 | **HINCRBY key field increment** 7 | 8 | 为哈希表 ``key`` 中的域 ``field`` 的值加上增量 ``increment`` 。 9 | 10 | 增量也可以为负数,相当于对给定域进行减法操作。 11 | 12 | 如果 ``key`` 不存在,一个新的哈希表被创建并执行 `HINCRBY`_ 命令。 13 | 14 | 如果域 ``field`` 不存在,那么在执行命令前,域的值被初始化为 ``0`` 。 15 | 16 | 对一个储存字符串值的域 ``field`` 执行 `HINCRBY`_ 命令将造成一个错误。 17 | 18 | 本操作的值被限制在 64 位(bit)有符号数字表示之内。 19 | 20 | **可用版本:** 21 | >= 2.0.0 22 | 23 | **时间复杂度:** 24 | O(1) 25 | 26 | **返回值:** 27 | 执行 `HINCRBY`_ 命令之后,哈希表 ``key`` 中域 ``field`` 的值。 28 | 29 | :: 30 | 31 | # increment 为正数 32 | 33 | redis> HEXISTS counter page_view # 对空域进行设置 34 | (integer) 0 35 | 36 | redis> HINCRBY counter page_view 200 37 | (integer) 200 38 | 39 | redis> HGET counter page_view 40 | "200" 41 | 42 | 43 | # increment 为负数 44 | 45 | redis> HGET counter page_view 46 | "200" 47 | 48 | redis> HINCRBY counter page_view -50 49 | (integer) 150 50 | 51 | redis> HGET counter page_view 52 | "150" 53 | 54 | 55 | # 尝试对字符串值的域执行HINCRBY命令 56 | 57 | redis> HSET myhash string hello,world # 设定一个字符串值 58 | (integer) 1 59 | 60 | redis> HGET myhash string 61 | "hello,world" 62 | 63 | redis> HINCRBY myhash string 1 # 命令执行失败,错误。 64 | (error) ERR hash value is not an integer 65 | 66 | redis> HGET myhash string # 原值不变 67 | "hello,world" 68 | -------------------------------------------------------------------------------- /hash/hincrbyfloat.rst: -------------------------------------------------------------------------------- 1 | .. _hincrbyfloat: 2 | 3 | HINCRBYFLOAT 4 | ============== 5 | 6 | **HINCRBYFLOAT key field increment** 7 | 8 | 为哈希表 ``key`` 中的域 ``field`` 加上浮点数增量 ``increment`` 。 9 | 10 | 如果哈希表中没有域 ``field`` ,那么 `HINCRBYFLOAT`_ 会先将域 ``field`` 的值设为 ``0`` ,然后再执行加法操作。 11 | 12 | 如果键 ``key`` 不存在,那么 `HINCRBYFLOAT`_ 会先创建一个哈希表,再创建域 ``field`` ,最后再执行加法操作。 13 | 14 | 当以下任意一个条件发生时,返回一个错误: 15 | 16 | - 域 ``field`` 的值不是字符串类型(因为 redis 中的数字和浮点数都以字符串的形式保存,所以它们都属于字符串类型) 17 | - 域 ``field`` 当前的值或给定的增量 ``increment`` 不能解释(parse)为双精度浮点数(double precision floating point number) 18 | 19 | `HINCRBYFLOAT`_ 命令的详细功能和 :ref:`INCRBYFLOAT` 命令类似,请查看 :ref:`INCRBYFLOAT` 命令获取更多相关信息。 20 | 21 | **可用版本:** 22 | >= 2.6.0 23 | 24 | **时间复杂度:** 25 | O(1) 26 | 27 | **返回值:** 28 | 执行加法操作之后 ``field`` 域的值。 29 | 30 | :: 31 | 32 | # 值和增量都是普通小数 33 | 34 | redis> HSET mykey field 10.50 35 | (integer) 1 36 | redis> HINCRBYFLOAT mykey field 0.1 37 | "10.6" 38 | 39 | 40 | # 值和增量都是指数符号 41 | 42 | redis> HSET mykey field 5.0e3 43 | (integer) 0 44 | redis> HINCRBYFLOAT mykey field 2.0e2 45 | "5200" 46 | 47 | 48 | # 对不存在的键执行 HINCRBYFLOAT 49 | 50 | redis> EXISTS price 51 | (integer) 0 52 | redis> HINCRBYFLOAT price milk 3.5 53 | "3.5" 54 | redis> HGETALL price 55 | 1) "milk" 56 | 2) "3.5" 57 | 58 | 59 | # 对不存在的域进行 HINCRBYFLOAT 60 | 61 | redis> HGETALL price 62 | 1) "milk" 63 | 2) "3.5" 64 | redis> HINCRBYFLOAT price coffee 4.5 # 新增 coffee 域 65 | "4.5" 66 | redis> HGETALL price 67 | 1) "milk" 68 | 2) "3.5" 69 | 3) "coffee" 70 | 4) "4.5" 71 | -------------------------------------------------------------------------------- /hash/hkeys.rst: -------------------------------------------------------------------------------- 1 | .. _hkeys: 2 | 3 | HKEYS 4 | ====== 5 | 6 | **HKEYS key** 7 | 8 | 返回哈希表 ``key`` 中的所有域。 9 | 10 | **可用版本:** 11 | >= 2.0.0 12 | 13 | **时间复杂度:** 14 | O(N), ``N`` 为哈希表的大小。 15 | 16 | **返回值:** 17 | | 一个包含哈希表中所有域的表。 18 | | 当 ``key`` 不存在时,返回一个空表。 19 | 20 | :: 21 | 22 | # 哈希表非空 23 | 24 | redis> HMSET website google www.google.com yahoo www.yahoo.com 25 | OK 26 | 27 | redis> HKEYS website 28 | 1) "google" 29 | 2) "yahoo" 30 | 31 | 32 | # 空哈希表/key不存在 33 | 34 | redis> EXISTS fake_key 35 | (integer) 0 36 | 37 | redis> HKEYS fake_key 38 | (empty list or set) 39 | -------------------------------------------------------------------------------- /hash/hlen.rst: -------------------------------------------------------------------------------- 1 | .. _hlen: 2 | 3 | HLEN 4 | ====== 5 | 6 | **HLEN key** 7 | 8 | 返回哈希表 ``key`` 中域的数量。 9 | 10 | **时间复杂度:** 11 | O(1) 12 | 13 | **返回值:** 14 | | 哈希表中域的数量。 15 | | 当 ``key`` 不存在时,返回 ``0`` 。 16 | 17 | :: 18 | 19 | redis> HSET db redis redis.com 20 | (integer) 1 21 | 22 | redis> HSET db mysql mysql.com 23 | (integer) 1 24 | 25 | redis> HLEN db 26 | (integer) 2 27 | 28 | redis> HSET db mongodb mongodb.org 29 | (integer) 1 30 | 31 | redis> HLEN db 32 | (integer) 3 33 | -------------------------------------------------------------------------------- /hash/hmget.rst: -------------------------------------------------------------------------------- 1 | .. _hmget: 2 | 3 | HMGET 4 | ===== 5 | 6 | **HMGET key field [field ...]** 7 | 8 | 返回哈希表 ``key`` 中,一个或多个给定域的值。 9 | 10 | 如果给定的域不存在于哈希表,那么返回一个 ``nil`` 值。 11 | 12 | 因为不存在的 ``key`` 被当作一个空哈希表来处理,所以对一个不存在的 ``key`` 进行 `HMGET`_ 操作将返回一个只带有 ``nil`` 值的表。 13 | 14 | **可用版本:** 15 | >= 2.0.0 16 | 17 | **时间复杂度:** 18 | O(N), ``N`` 为给定域的数量。 19 | 20 | **返回值:** 21 | 一个包含多个给定域的关联值的表,表值的排列顺序和给定域参数的请求顺序一样。 22 | 23 | :: 24 | 25 | redis> HMSET pet dog "doudou" cat "nounou" # 一次设置多个域 26 | OK 27 | 28 | redis> HMGET pet dog cat fake_pet # 返回值的顺序和传入参数的顺序一样 29 | 1) "doudou" 30 | 2) "nounou" 31 | 3) (nil) # 不存在的域返回nil值 32 | -------------------------------------------------------------------------------- /hash/hmset.rst: -------------------------------------------------------------------------------- 1 | .. _hmset: 2 | 3 | HMSET 4 | ===== 5 | 6 | **HMSET key field value [field value ...]** 7 | 8 | 同时将多个 ``field-value`` (域-值)对设置到哈希表 ``key`` 中。 9 | 10 | 此命令会覆盖哈希表中已存在的域。 11 | 12 | 如果 ``key`` 不存在,一个空哈希表被创建并执行 `HMSET`_ 操作。 13 | 14 | **可用版本:** 15 | >= 2.0.0 16 | 17 | **时间复杂度:** 18 | O(N), ``N`` 为 ``field-value`` 对的数量。 19 | 20 | **返回值:** 21 | | 如果命令执行成功,返回 ``OK`` 。 22 | | 当 ``key`` 不是哈希表(hash)类型时,返回一个错误。 23 | 24 | :: 25 | 26 | redis> HMSET website google www.google.com yahoo www.yahoo.com 27 | OK 28 | 29 | redis> HGET website google 30 | "www.google.com" 31 | 32 | redis> HGET website yahoo 33 | "www.yahoo.com" 34 | -------------------------------------------------------------------------------- /hash/hscan.rst: -------------------------------------------------------------------------------- 1 | .. _hscan: 2 | 3 | HSCAN 4 | ============= 5 | 6 | **HSCAN key cursor [MATCH pattern] [COUNT count]** 7 | 8 | 具体信息请参考 :ref:`SCAN` 命令。 9 | -------------------------------------------------------------------------------- /hash/hset.rst: -------------------------------------------------------------------------------- 1 | .. _hset: 2 | 3 | HSET 4 | ===== 5 | 6 | **HSET key field value** 7 | 8 | 将哈希表 ``key`` 中的域 ``field`` 的值设为 ``value`` 。 9 | 10 | 如果 ``key`` 不存在,一个新的哈希表被创建并进行 `HSET`_ 操作。 11 | 12 | 如果域 ``field`` 已经存在于哈希表中,旧值将被覆盖。 13 | 14 | **可用版本:** 15 | >= 2.0.0 16 | 17 | **时间复杂度:** 18 | O(1) 19 | 20 | **返回值:** 21 | | 如果 ``field`` 是哈希表中的一个新建域,并且值设置成功,返回 ``1`` 。 22 | | 如果哈希表中域 ``field`` 已经存在且旧值已被新值覆盖,返回 ``0`` 。 23 | 24 | :: 25 | 26 | redis> HSET website google "www.g.cn" # 设置一个新域 27 | (integer) 1 28 | 29 | redis> HSET website google "www.google.com" # 覆盖一个旧域 30 | (integer) 0 31 | -------------------------------------------------------------------------------- /hash/hsetnx.rst: -------------------------------------------------------------------------------- 1 | .. _hsetnx: 2 | 3 | HSETNX 4 | ======= 5 | 6 | **HSETNX key field value** 7 | 8 | 将哈希表 ``key`` 中的域 ``field`` 的值设置为 ``value`` ,当且仅当域 ``field`` 不存在。 9 | 10 | 若域 ``field`` 已经存在,该操作无效。 11 | 12 | 如果 ``key`` 不存在,一个新哈希表被创建并执行 `HSETNX`_ 命令。 13 | 14 | **可用版本:** 15 | >= 2.0.0 16 | 17 | **时间复杂度:** 18 | O(1) 19 | 20 | **返回值:** 21 | | 设置成功,返回 ``1`` 。 22 | | 如果给定域已经存在且没有操作被执行,返回 ``0`` 。 23 | 24 | :: 25 | 26 | redis> HSETNX nosql key-value-store redis 27 | (integer) 1 28 | 29 | redis> HSETNX nosql key-value-store redis # 操作无效,域 key-value-store 已存在 30 | (integer) 0 31 | -------------------------------------------------------------------------------- /hash/hvals.rst: -------------------------------------------------------------------------------- 1 | .. _hvals: 2 | 3 | HVALS 4 | ====== 5 | 6 | **HVALS key** 7 | 8 | 返回哈希表 ``key`` 中所有域的值。 9 | 10 | **可用版本:** 11 | >= 2.0.0 12 | 13 | **时间复杂度:** 14 | O(N), ``N`` 为哈希表的大小。 15 | 16 | **返回值:** 17 | | 一个包含哈希表中所有值的表。 18 | | 当 ``key`` 不存在时,返回一个空表。 19 | 20 | :: 21 | 22 | # 非空哈希表 23 | 24 | redis> HMSET website google www.google.com yahoo www.yahoo.com 25 | OK 26 | 27 | redis> HVALS website 28 | 1) "www.google.com" 29 | 2) "www.yahoo.com" 30 | 31 | 32 | # 空哈希表/不存在的key 33 | 34 | redis> EXISTS not_exists 35 | (integer) 0 36 | 37 | redis> HVALS not_exists 38 | (empty list or set) 39 | -------------------------------------------------------------------------------- /hash/index.rst: -------------------------------------------------------------------------------- 1 | Hash(哈希表) 2 | ========================= 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | 7 | hdel 8 | hexists 9 | hget 10 | hgetall 11 | hincrby 12 | hincrbyfloat 13 | hkeys 14 | hlen 15 | hmget 16 | hmset 17 | hset 18 | hsetnx 19 | hvals 20 | hscan 21 | -------------------------------------------------------------------------------- /index.rst: -------------------------------------------------------------------------------- 1 | .. Redis命令参考简体中文版 documentation master file, created by 2 | sphinx-quickstart on Tue Oct 25 17:56:34 2011. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Redis 命令参考 7 | ================= 8 | 9 | .. include:: intro.include 10 | 11 | .. include:: course.include 12 | 13 | 命令目录(使用 CTRL + F 快速查找): 14 | -------------------------------------- 15 | 16 | +-------------------+-----------------------+-------------------+-----------------------+ 17 | | .. toctree:: | .. toctree:: | .. toctree:: | .. toctree:: | 18 | | :maxdepth: 2 | :maxdepth: 2 | :maxdepth: 2 | :maxdepth: 2 | 19 | | | | | | 20 | | key/index | string/index | hash/index | list/index | 21 | +-------------------+-----------------------+-------------------+-----------------------+ 22 | | .. toctree:: | .. toctree:: | .. toctree:: | .. toctree:: | 23 | | :maxdepth: 2 | :maxdepth: 2 | :maxdepth: 2 | :maxdepth: 2 | 24 | | | | | | 25 | | set/index | sorted_set/index | pub_sub/index | transaction/index | 26 | +-------------------+-----------------------+-------------------+-----------------------+ 27 | | .. toctree:: | .. toctree:: | .. toctree:: | 28 | | :maxdepth: 2 | :maxdepth: 2 | :maxdepth: 2 | 29 | | | | | 30 | | script/index | connection/index | server/index | 31 | +-------------------+-----------------------+-------------------+-----------------------+ 32 | 33 | .. include:: tdir.include 34 | 35 | 文档 36 | ------------------- 37 | 38 | 以下文章翻译自 `redis.io/documentation `_ 文档。 39 | 40 | +-----------------------+---------------------------+-----------------------+ 41 | | .. toctree:: | .. toctree:: | .. toctree:: | 42 | | :maxdepth: 2 | :maxdepth: 2 | :maxdepth: 2 | 43 | | | | | 44 | | topic/notification | topic/transaction | topic/pubsub | 45 | +-----------------------+---------------------------+-----------------------+ 46 | | .. toctree:: | .. toctree:: | .. toctree:: | 47 | | :maxdepth: 2 | :maxdepth: 2 | :maxdepth: 2 | 48 | | | | | 49 | | topic/replication | topic/protocol | topic/persistence | 50 | +-----------------------+---------------------------+-----------------------+ 51 | | .. toctree:: | .. toctree:: | .. toctree:: | 52 | | :maxdepth: 2 | :maxdepth: 2 | :maxdepth: 2 | 53 | | | | | 54 | | topic/sentinel | topic/cluster-tutorial | topic/cluster-spec | 55 | +-----------------------+---------------------------+-----------------------+ 56 | 57 | 58 | .. include:: about.include 59 | 60 | .. include:: donation.include 61 | -------------------------------------------------------------------------------- /intro.include: -------------------------------------------------------------------------------- 1 | 本文档是 `Redis Command Reference `_ 和 `Redis Documentation `_ 的中文翻译版: 2 | 所有 Redis 命令文档均已翻译完毕, 3 | Redis 最重要的一部分主题(topic)文档, 4 | 比如事务、持久化、复制、Sentinel、集群等文章也已翻译完毕。 5 | 6 | 文档目前描述的内容以 Redis 2.8 版本为准, 7 | 查看\ :ref:`change_log`\ 可以了解本文档对 Redis 2.8 所做的更新。 8 | 9 | 你可以通过网址 `www.RedisDoc.com `_ 在线阅览本文档, 10 | 也可以下载 `PDF 格式 `_ 或者 `HTML 格式 `_ 的离线版本。 11 | -------------------------------------------------------------------------------- /key/_user_info_table.include: -------------------------------------------------------------------------------- 1 | ====== ================ ======================== 2 | uid user_name_{uid} user_level_{uid} 3 | ====== ================ ======================== 4 | 1 admin 9999 5 | 2 jack 10 6 | 3 peter 25 7 | 4 mary 70 8 | ====== ================ ======================== 9 | -------------------------------------------------------------------------------- /key/del.rst: -------------------------------------------------------------------------------- 1 | .. _del: 2 | 3 | DEL 4 | ==== 5 | 6 | **DEL key [key ...]** 7 | 8 | 删除给定的一个或多个 ``key`` 。 9 | 10 | 不存在的 ``key`` 会被忽略。 11 | 12 | **可用版本:** 13 | >= 1.0.0 14 | 15 | **时间复杂度:** 16 | | O(N), ``N`` 为被删除的 ``key`` 的数量。 17 | 18 | | 删除单个字符串类型的 ``key`` ,时间复杂度为O(1)。 19 | | 删除单个列表、集合、有序集合或哈希表类型的 ``key`` ,时间复杂度为O(M), ``M`` 为以上数据结构内的元素数量。 20 | 21 | **返回值:** 22 | 被删除 ``key`` 的数量。 23 | 24 | :: 25 | 26 | # 删除单个 key 27 | 28 | redis> SET name huangz 29 | OK 30 | 31 | redis> DEL name 32 | (integer) 1 33 | 34 | 35 | # 删除一个不存在的 key 36 | 37 | redis> EXISTS phone 38 | (integer) 0 39 | 40 | redis> DEL phone # 失败,没有 key 被删除 41 | (integer) 0 42 | 43 | 44 | # 同时删除多个 key 45 | 46 | redis> SET name "redis" 47 | OK 48 | 49 | redis> SET type "key-value store" 50 | OK 51 | 52 | redis> SET website "redis.com" 53 | OK 54 | 55 | redis> DEL name type website 56 | (integer) 3 57 | -------------------------------------------------------------------------------- /key/dump.rst: -------------------------------------------------------------------------------- 1 | .. _dump: 2 | 3 | DUMP 4 | ========= 5 | 6 | **DUMP key** 7 | 8 | 序列化给定 ``key`` ,并返回被序列化的值,使用 :doc:`restore` 命令可以将这个值反序列化为 Redis 键。 9 | 10 | 序列化生成的值有以下几个特点: 11 | 12 | - 它带有 64 位的校验和,用于检测错误, :doc:`restore` 在进行反序列化之前会先检查校验和。 13 | 14 | - 值的编码格式和 RDB 文件保持一致。 15 | 16 | - RDB 版本会被编码在序列化值当中,如果因为 Redis 的版本不同造成 RDB 格式不兼容,那么 Redis 会拒绝对这个值进行反序列化操作。 17 | 18 | 序列化的值不包括任何生存时间信息。 19 | 20 | 21 | **可用版本:** 22 | >= 2.6.0 23 | 24 | **时间复杂度:** 25 | | 查找给定键的复杂度为 O(1) ,对键进行序列化的复杂度为 O(N*M) ,其中 N 是构成 ``key`` 的 Redis 对象的数量,而 M 则是这些对象的平均大小。 26 | | 如果序列化的对象是比较小的字符串,那么复杂度为 O(1) 。 27 | 28 | **返回值:** 29 | | 如果 ``key`` 不存在,那么返回 ``nil`` 。 30 | | 否则,返回序列化之后的值。 31 | 32 | :: 33 | 34 | redis> SET greeting "hello, dumping world!" 35 | OK 36 | 37 | redis> DUMP greeting 38 | "\x00\x15hello, dumping world!\x06\x00E\xa0Z\x82\xd8r\xc1\xde" 39 | 40 | redis> DUMP not-exists-key 41 | (nil) 42 | -------------------------------------------------------------------------------- /key/exists.rst: -------------------------------------------------------------------------------- 1 | .. _exists: 2 | 3 | EXISTS 4 | ====== 5 | 6 | **EXISTS key** 7 | 8 | 检查给定 ``key`` 是否存在。 9 | 10 | **可用版本:** 11 | >= 1.0.0 12 | 13 | **时间复杂度:** 14 | O(1) 15 | 16 | **返回值:** 17 | 若 ``key`` 存在,返回 ``1`` ,否则返回 ``0`` 。 18 | 19 | :: 20 | 21 | redis> SET db "redis" 22 | OK 23 | 24 | redis> EXISTS db 25 | (integer) 1 26 | 27 | redis> DEL db 28 | (integer) 1 29 | 30 | redis> EXISTS db 31 | (integer) 0 32 | -------------------------------------------------------------------------------- /key/expire.rst: -------------------------------------------------------------------------------- 1 | .. _expire: 2 | 3 | EXPIRE 4 | ======= 5 | 6 | **EXPIRE key seconds** 7 | 8 | 为给定 ``key`` 设置生存时间,当 ``key`` 过期时(生存时间为 ``0`` ),它会被自动删除。 9 | 10 | 在 Redis 中,带有生存时间的 ``key`` 被称为『易失的』(volatile)。 11 | 12 | 生存时间可以通过使用 :ref:`DEL` 命令来删除整个 ``key`` 来移除,或者被 :ref:`SET` 和 :ref:`GETSET` 命令覆写(overwrite),这意味着,如果一个命令只是修改(alter)一个带生存时间的 ``key`` 的值而不是用一个新的 ``key`` 值来代替(replace)它的话,那么生存时间不会被改变。 13 | 14 | 比如说,对一个 ``key`` 执行 :ref:`INCR` 命令,对一个列表进行 :ref:`LPUSH` 命令,或者对一个哈希表执行 :ref:`HSET` 命令,这类操作都不会修改 ``key`` 本身的生存时间。 15 | 16 | 另一方面,如果使用 :doc:`rename` 对一个 ``key`` 进行改名,那么改名后的 ``key`` 的生存时间和改名前一样。 17 | 18 | :doc:`rename` 命令的另一种可能是,尝试将一个带生存时间的 ``key`` 改名成另一个带生存时间的 ``another_key`` ,这时旧的 ``another_key`` (以及它的生存时间)会被删除,然后旧的 ``key`` 会改名为 ``another_key`` ,因此,新的 ``another_key`` 的生存时间也和原本的 ``key`` 一样。 19 | 20 | 使用 :doc:`persist` 命令可以在不删除 ``key`` 的情况下,移除 ``key`` 的生存时间,让 ``key`` 重新成为一个『持久的』(persistent) ``key`` 。 21 | 22 | **更新生存时间** 23 | 24 | 可以对一个已经带有生存时间的 ``key`` 执行 :ref:`EXPIRE` 命令,新指定的生存时间会取代旧的生存时间。 25 | 26 | **过期时间的精确度** 27 | 28 | 在 Redis 2.4 版本中,过期时间的延迟在 1 秒钟之内 —— 也即是,就算 ``key`` 已经过期,但它还是可能在过期之后一秒钟之内被访问到,而在新的 Redis 2.6 版本中,延迟被降低到 1 毫秒之内。 29 | 30 | **Redis 2.1.3 之前的不同之处** 31 | 32 | 在 Redis 2.1.3 之前的版本中,修改一个带有生存时间的 ``key`` 会导致整个 ``key`` 被删除,这一行为是受当时复制(replication)层的限制而作出的,现在这一限制已经被修复。 33 | 34 | **可用版本:** 35 | >= 1.0.0 36 | 37 | **时间复杂度:** 38 | O(1) 39 | 40 | **返回值:** 41 | | 设置成功返回 ``1`` 。 42 | | 当 ``key`` 不存在或者不能为 ``key`` 设置生存时间时(比如在低于 2.1.3 版本的 Redis 中你尝试更新 ``key`` 的生存时间),返回 ``0`` 。 43 | 44 | :: 45 | 46 | redis> SET cache_page "www.google.com" 47 | OK 48 | 49 | redis> EXPIRE cache_page 30 # 设置过期时间为 30 秒 50 | (integer) 1 51 | 52 | redis> TTL cache_page # 查看剩余生存时间 53 | (integer) 23 54 | 55 | redis> EXPIRE cache_page 30000 # 更新过期时间 56 | (integer) 1 57 | 58 | redis> TTL cache_page 59 | (integer) 29996 60 | 61 | 模式:导航会话 62 | ----------------- 63 | 64 | 假设你有一项 web 服务,打算根据用户最近访问的 N 个页面来进行物品推荐,并且假设用户停止阅览超过 60 秒,那么就清空阅览记录(为了减少物品推荐的计算量,并且保持推荐物品的新鲜度)。 65 | 66 | 这些最近访问的页面记录,我们称之为『导航会话』(Navigation session),可以用 :ref:`INCR` 和 :ref:`RPUSH` 命令在 Redis 中实现它:每当用户阅览一个网页的时候,执行以下代码: 67 | 68 | :: 69 | 70 | MULTI 71 | RPUSH pagewviews.user: http://..... 72 | EXPIRE pagewviews.user: 60 73 | EXEC 74 | 75 | 如果用户停止阅览超过 60 秒,那么它的导航会话就会被清空,当用户重新开始阅览的时候,系统又会重新记录导航会话,继续进行物品推荐。 76 | 77 | 78 | -------------------------------------------------------------------------------- /key/expireat.rst: -------------------------------------------------------------------------------- 1 | .. _expireat: 2 | 3 | EXPIREAT 4 | ======== 5 | 6 | **EXPIREAT key timestamp** 7 | 8 | `EXPIREAT`_ 的作用和 :doc:`expire` 类似,都用于为 ``key`` 设置生存时间。 9 | 10 | 不同在于 `EXPIREAT`_ 命令接受的时间参数是 UNIX 时间戳(unix timestamp)。 11 | 12 | **可用版本:** 13 | >= 1.2.0 14 | 15 | **时间复杂度:** 16 | O(1) 17 | 18 | **返回值:** 19 | | 如果生存时间设置成功,返回 ``1`` 。 20 | | 当 ``key`` 不存在或没办法设置生存时间,返回 ``0`` 。 21 | 22 | :: 23 | 24 | redis> SET cache www.google.com 25 | OK 26 | 27 | redis> EXPIREAT cache 1355292000 # 这个 key 将在 2012.12.12 过期 28 | (integer) 1 29 | 30 | redis> TTL cache 31 | (integer) 45081860 32 | -------------------------------------------------------------------------------- /key/index.rst: -------------------------------------------------------------------------------- 1 | Key(键) 2 | ================= 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | 7 | del 8 | dump 9 | exists 10 | expire 11 | expireat 12 | keys 13 | migrate 14 | move 15 | object 16 | persist 17 | pexpire 18 | pexpireat 19 | pttl 20 | randomkey 21 | rename 22 | renamenx 23 | restore 24 | sort 25 | ttl 26 | type 27 | scan 28 | -------------------------------------------------------------------------------- /key/keys.rst: -------------------------------------------------------------------------------- 1 | .. _keys: 2 | 3 | KEYS 4 | ===== 5 | 6 | **KEYS pattern** 7 | 8 | 查找所有符合给定模式 ``pattern`` 的 ``key`` 。 9 | 10 | | ``KEYS *`` 匹配数据库中所有 ``key`` 。 11 | | ``KEYS h?llo`` 匹配 ``hello`` , ``hallo`` 和 ``hxllo`` 等。 12 | | ``KEYS h*llo`` 匹配 ``hllo`` 和 ``heeeeello`` 等。 13 | | ``KEYS h[ae]llo`` 匹配 ``hello`` 和 ``hallo`` ,但不匹配 ``hillo`` 。 14 | 15 | 特殊符号用 ``\`` 隔开 16 | 17 | .. warning:: 18 | `KEYS`_ 的速度非常快,但在一个大的数据库中使用它仍然可能造成性能问题,如果你需要从一个数据集中查找特定的 ``key`` ,你最好还是用 Redis 的集合结构(set)来代替。 19 | 20 | **可用版本:** 21 | >= 1.0.0 22 | 23 | **时间复杂度:** 24 | O(N), ``N`` 为数据库中 ``key`` 的数量。 25 | 26 | **返回值:** 27 | 符合给定模式的 ``key`` 列表。 28 | 29 | :: 30 | 31 | redis> MSET one 1 two 2 three 3 four 4 # 一次设置 4 个 key 32 | OK 33 | 34 | redis> KEYS *o* 35 | 1) "four" 36 | 2) "two" 37 | 3) "one" 38 | 39 | redis> KEYS t?? 40 | 1) "two" 41 | 42 | redis> KEYS t[w]* 43 | 1) "two" 44 | 45 | redis> KEYS * # 匹配数据库内所有 key 46 | 1) "four" 47 | 2) "three" 48 | 3) "two" 49 | 4) "one" 50 | -------------------------------------------------------------------------------- /key/migrate.rst: -------------------------------------------------------------------------------- 1 | .. _migrate: 2 | 3 | MIGRATE 4 | ============ 5 | 6 | **MIGRATE host port key destination-db timeout [COPY] [REPLACE]** 7 | 8 | 将 ``key`` 原子性地从当前实例传送到目标实例的指定数据库上,一旦传送成功, ``key`` 保证会出现在目标实例上,而当前实例上的 ``key`` 会被删除。 9 | 10 | 这个命令是一个原子操作,它在执行的时候会阻塞进行迁移的两个实例,直到以下任意结果发生:迁移成功,迁移失败,等到超时。 11 | 12 | 命令的内部实现是这样的:它在当前实例对给定 ``key`` 执行 :doc:`dump` 命令 ,将它序列化,然后传送到目标实例,目标实例再使用 :doc:`restore` 对数据进行反序列化,并将反序列化所得的数据添加到数据库中;当前实例就像目标实例的客户端那样,只要看到 :doc:`restore` 命令返回 ``OK`` ,它就会调用 :doc:`del` 删除自己数据库上的 ``key`` 。 13 | 14 | ``timeout`` 参数以毫秒为格式,指定当前实例和目标实例进行沟通的\ **最大间隔时间**\ 。这说明操作并不一定要在 ``timeout`` 毫秒内完成,只是说数据传送的时间不能超过这个 ``timeout`` 数。 15 | 16 | `MIGRATE`_ 命令需要在给定的时间规定内完成 IO 操作。如果在传送数据时发生 IO 错误,或者达到了超时时间,那么命令会停止执行,并返回一个特殊的错误: ``IOERR`` 。 17 | 18 | 当 ``IOERR`` 出现时,有以下两种可能: 19 | 20 | - ``key`` 可能存在于两个实例 21 | - ``key`` 可能只存在于当前实例 22 | 23 | 唯一不可能发生的情况就是丢失 ``key`` ,因此,如果一个客户端执行 `MIGRATE`_ 命令,并且不幸遇上 ``IOERR`` 错误,那么这个客户端唯一要做的就是检查自己数据库上的 ``key`` 是否已经被正确地删除。 24 | 25 | 如果有其他错误发生,那么 `MIGRATE`_ 保证 ``key`` 只会出现在当前实例中。(当然,目标实例的给定数据库上可能有和 ``key`` 同名的键,不过这和 `MIGRATE`_ 命令没有关系)。 26 | 27 | **可选项:** 28 | 29 | - ``COPY`` :不移除源实例上的 ``key`` 。 30 | 31 | - ``REPLACE`` :替换目标实例上已存在的 ``key`` 。 32 | 33 | **可用版本:** 34 | >= 2.6.0 35 | 36 | **时间复杂度:** 37 | | 这个命令在源实例上实际执行 :doc:`dump` 命令和 :doc:`del` 命令,在目标实例执行 :doc:`restore` 命令,查看以上命令的文档可以看到详细的复杂度说明。 38 | | ``key`` 数据在两个实例之间传输的复杂度为 O(N) 。 39 | 40 | **返回值:** 41 | 迁移成功时返回 ``OK`` ,否则返回相应的错误。 42 | 43 | 示例 44 | ------ 45 | 46 | 先启动两个 Redis 实例,一个使用默认的 6379 端口,一个使用 7777 端口。 47 | 48 | :: 49 | 50 | $ ./redis-server & 51 | [1] 3557 52 | 53 | ... 54 | 55 | $ ./redis-server --port 7777 & 56 | [2] 3560 57 | 58 | ... 59 | 60 | 然后用客户端连上 6379 端口的实例,设置一个键,然后将它迁移到 7777 端口的实例上: 61 | 62 | :: 63 | 64 | $ ./redis-cli 65 | 66 | redis 127.0.0.1:6379> flushdb 67 | OK 68 | 69 | redis 127.0.0.1:6379> SET greeting "Hello from 6379 instance" 70 | OK 71 | 72 | redis 127.0.0.1:6379> MIGRATE 127.0.0.1 7777 greeting 0 1000 73 | OK 74 | 75 | redis 127.0.0.1:6379> EXISTS greeting # 迁移成功后 key 被删除 76 | (integer) 0 77 | 78 | 使用另一个客户端,查看 7777 端口上的实例: 79 | 80 | :: 81 | 82 | $ ./redis-cli -p 7777 83 | 84 | redis 127.0.0.1:7777> GET greeting 85 | "Hello from 6379 instance" 86 | -------------------------------------------------------------------------------- /key/move.rst: -------------------------------------------------------------------------------- 1 | .. _move: 2 | 3 | MOVE 4 | ==== 5 | 6 | **MOVE key db** 7 | 8 | 将当前数据库的 ``key`` 移动到给定的数据库 ``db`` 当中。 9 | 10 | 如果当前数据库(源数据库)和给定数据库(目标数据库)有相同名字的给定 ``key`` ,或者 ``key`` 不存在于当前数据库,那么 ``MOVE`` 没有任何效果。 11 | 12 | 因此,也可以利用这一特性,将 `MOVE`_ 当作锁(locking)原语(primitive)。 13 | 14 | **可用版本:** 15 | >= 1.0.0 16 | 17 | **时间复杂度:** 18 | O(1) 19 | 20 | **返回值:** 21 | 移动成功返回 ``1`` ,失败则返回 ``0`` 。 22 | 23 | :: 24 | 25 | # key 存在于当前数据库 26 | 27 | redis> SELECT 0 # redis默认使用数据库 0,为了清晰起见,这里再显式指定一次。 28 | OK 29 | 30 | redis> SET song "secret base - Zone" 31 | OK 32 | 33 | redis> MOVE song 1 # 将 song 移动到数据库 1 34 | (integer) 1 35 | 36 | redis> EXISTS song # song 已经被移走 37 | (integer) 0 38 | 39 | redis> SELECT 1 # 使用数据库 1 40 | OK 41 | 42 | redis:1> EXISTS song # 证实 song 被移到了数据库 1 (注意命令提示符变成了"redis:1",表明正在使用数据库 1) 43 | (integer) 1 44 | 45 | 46 | # 当 key 不存在的时候 47 | 48 | redis:1> EXISTS fake_key 49 | (integer) 0 50 | 51 | redis:1> MOVE fake_key 0 # 试图从数据库 1 移动一个不存在的 key 到数据库 0,失败 52 | (integer) 0 53 | 54 | redis:1> select 0 # 使用数据库0 55 | OK 56 | 57 | redis> EXISTS fake_key # 证实 fake_key 不存在 58 | (integer) 0 59 | 60 | 61 | # 当源数据库和目标数据库有相同的 key 时 62 | 63 | redis> SELECT 0 # 使用数据库0 64 | OK 65 | redis> SET favorite_fruit "banana" 66 | OK 67 | 68 | redis> SELECT 1 # 使用数据库1 69 | OK 70 | redis:1> SET favorite_fruit "apple" 71 | OK 72 | 73 | redis:1> SELECT 0 # 使用数据库0,并试图将 favorite_fruit 移动到数据库 1 74 | OK 75 | 76 | redis> MOVE favorite_fruit 1 # 因为两个数据库有相同的 key,MOVE 失败 77 | (integer) 0 78 | 79 | redis> GET favorite_fruit # 数据库 0 的 favorite_fruit 没变 80 | "banana" 81 | 82 | redis> SELECT 1 83 | OK 84 | 85 | redis:1> GET favorite_fruit # 数据库 1 的 favorite_fruit 也是 86 | "apple" 87 | -------------------------------------------------------------------------------- /key/object.rst: -------------------------------------------------------------------------------- 1 | .. _object: 2 | 3 | OBJECT 4 | ====== 5 | 6 | **OBJECT subcommand [arguments [arguments]]** 7 | 8 | `OBJECT`_ 命令允许从内部察看给定 ``key`` 的 Redis 对象。 9 | 10 | | 它通常用在除错(debugging)或者了解为了节省空间而对 ``key`` 使用特殊编码的情况。 11 | | 当将Redis用作缓存程序时,你也可以通过 `OBJECT`_ 命令中的信息,决定 ``key`` 的驱逐策略(eviction policies)。 12 | 13 | OBJECT 命令有多个子命令: 14 | 15 | * ``OBJECT REFCOUNT `` 返回给定 ``key`` 引用所储存的值的次数。此命令主要用于除错。 16 | * ``OBJECT ENCODING `` 返回给定 ``key`` 锁储存的值所使用的内部表示(representation)。 17 | * ``OBJECT IDLETIME `` 返回给定 ``key`` 自储存以来的空闲时间(idle, 没有被读取也没有被写入),以秒为单位。 18 | 19 | | 对象可以以多种方式编码: 20 | 21 | * 字符串可以被编码为 ``raw`` (一般字符串)或 ``int`` (为了节约内存,Redis 会将字符串表示的 64 位有符号整数编码为整数来进行储存)。 22 | * 列表可以被编码为 ``ziplist`` 或 ``linkedlist`` 。 ``ziplist`` 是为节约大小较小的列表空间而作的特殊表示。 23 | * 集合可以被编码为 ``intset`` 或者 ``hashtable`` 。 ``intset`` 是只储存数字的小集合的特殊表示。 24 | * 哈希表可以编码为 ``zipmap`` 或者 ``hashtable`` 。 ``zipmap`` 是小哈希表的特殊表示。 25 | * 有序集合可以被编码为 ``ziplist`` 或者 ``skiplist`` 格式。 ``ziplist`` 用于表示小的有序集合,而 ``skiplist`` 则用于表示任何大小的有序集合。 26 | 27 | | 假如你做了什么让 Redis 没办法再使用节省空间的编码时(比如将一个只有 1 个元素的集合扩展为一个有 100 万个元素的集合),特殊编码类型(specially encoded types)会自动转换成通用类型(general type)。 28 | 29 | **可用版本:** 30 | >= 2.2.3 31 | 32 | **时间复杂度:** 33 | O(1) 34 | 35 | **返回值:** 36 | | ``REFCOUNT`` 和 ``IDLETIME`` 返回数字。 37 | | ``ENCODING`` 返回相应的编码类型。 38 | 39 | :: 40 | 41 | redis> SET game "COD" # 设置一个字符串 42 | OK 43 | 44 | redis> OBJECT REFCOUNT game # 只有一个引用 45 | (integer) 1 46 | 47 | redis> OBJECT IDLETIME game # 等待一阵。。。然后查看空闲时间 48 | (integer) 90 49 | 50 | redis> GET game # 提取game, 让它处于活跃(active)状态 51 | "COD" 52 | 53 | redis> OBJECT IDLETIME game # 不再处于空闲状态 54 | (integer) 0 55 | 56 | redis> OBJECT ENCODING game # 字符串的编码方式 57 | "raw" 58 | 59 | redis> SET big-number 23102930128301091820391092019203810281029831092 # 非常长的数字会被编码为字符串 60 | OK 61 | 62 | redis> OBJECT ENCODING big-number 63 | "raw" 64 | 65 | redis> SET small-number 12345 # 而短的数字则会被编码为整数 66 | OK 67 | 68 | redis> OBJECT ENCODING small-number 69 | "int" 70 | 71 | -------------------------------------------------------------------------------- /key/persist.rst: -------------------------------------------------------------------------------- 1 | .. _persist: 2 | 3 | PERSIST 4 | ======== 5 | 6 | **PERSIST key** 7 | 8 | 移除给定 ``key`` 的生存时间,将这个 ``key`` 从『易失的』(带生存时间 ``key`` )转换成『持久的』(一个不带生存时间、永不过期的 ``key`` )。 9 | 10 | **可用版本:** 11 | >= 2.2.0 12 | 13 | **时间复杂度:** 14 | O(1) 15 | 16 | **返回值:** 17 | | 当生存时间移除成功时,返回 ``1`` . 18 | | 如果 ``key`` 不存在或 ``key`` 没有设置生存时间,返回 ``0`` 。 19 | 20 | :: 21 | 22 | redis> SET mykey "Hello" 23 | OK 24 | 25 | redis> EXPIRE mykey 10 # 为 key 设置生存时间 26 | (integer) 1 27 | 28 | redis> TTL mykey 29 | (integer) 10 30 | 31 | redis> PERSIST mykey # 移除 key 的生存时间 32 | (integer) 1 33 | 34 | redis> TTL mykey 35 | (integer) -1 36 | -------------------------------------------------------------------------------- /key/pexpire.rst: -------------------------------------------------------------------------------- 1 | .. _pexpire: 2 | 3 | PEXPIRE 4 | ======== 5 | 6 | **PEXPIRE key milliseconds** 7 | 8 | 这个命令和 :doc:`expire` 命令的作用类似,但是它以毫秒为单位设置 ``key`` 的生存时间,而不像 :doc:`expire` 命令那样,以秒为单位。 9 | 10 | **可用版本:** 11 | >= 2.6.0 12 | 13 | **时间复杂度:** 14 | O(1) 15 | 16 | **返回值:** 17 | | 设置成功,返回 ``1`` 18 | | ``key`` 不存在或设置失败,返回 ``0`` 19 | 20 | :: 21 | 22 | redis> SET mykey "Hello" 23 | OK 24 | 25 | redis> PEXPIRE mykey 1500 26 | (integer) 1 27 | 28 | redis> TTL mykey # TTL 的返回值以秒为单位 29 | (integer) 2 30 | 31 | redis> PTTL mykey # PTTL 可以给出准确的毫秒数 32 | (integer) 1499 33 | -------------------------------------------------------------------------------- /key/pexpireat.rst: -------------------------------------------------------------------------------- 1 | .. _pexpireat: 2 | 3 | PEXPIREAT 4 | ============ 5 | 6 | **PEXPIREAT key milliseconds-timestamp** 7 | 8 | 这个命令和 :doc:`expireat` 命令类似,但它以毫秒为单位设置 ``key`` 的过期 unix 时间戳,而不是像 :doc:`expireat` 那样,以秒为单位。 9 | 10 | **可用版本:** 11 | >= 2.6.0 12 | 13 | **时间复杂度:** 14 | O(1) 15 | 16 | **返回值:** 17 | | 如果生存时间设置成功,返回 ``1`` 。 18 | | 当 ``key`` 不存在或没办法设置生存时间时,返回 ``0`` 。(查看 :doc:`expire` 命令获取更多信息) 19 | 20 | :: 21 | 22 | redis> SET mykey "Hello" 23 | OK 24 | 25 | redis> PEXPIREAT mykey 1555555555005 26 | (integer) 1 27 | 28 | redis> TTL mykey # TTL 返回秒 29 | (integer) 223157079 30 | 31 | redis> PTTL mykey # PTTL 返回毫秒 32 | (integer) 223157079318 33 | -------------------------------------------------------------------------------- /key/pttl.rst: -------------------------------------------------------------------------------- 1 | .. _pttl: 2 | 3 | PTTL 4 | ====== 5 | 6 | **PTTL key** 7 | 8 | 这个命令类似于 :ref:`TTL` 命令,但它以毫秒为单位返回 ``key`` 的剩余生存时间,而不是像 :ref:`TTL` 命令那样,以秒为单位。 9 | 10 | **可用版本:** 11 | >= 2.6.0 12 | 13 | **复杂度:** 14 | O(1) 15 | 16 | **返回值:** 17 | | 当 ``key`` 不存在时,返回 ``-2`` 。 18 | | 当 ``key`` 存在但没有设置剩余生存时间时,返回 ``-1`` 。 19 | | 否则,以毫秒为单位,返回 ``key`` 的剩余生存时间。 20 | 21 | .. note:: 在 Redis 2.8 以前,当 ``key`` 不存在,或者 ``key`` 没有设置剩余生存时间时,命令都返回 ``-1`` 。 22 | 23 | :: 24 | 25 | # 不存在的 key 26 | 27 | redis> FLUSHDB 28 | OK 29 | 30 | redis> PTTL key 31 | (integer) -2 32 | 33 | 34 | # key 存在,但没有设置剩余生存时间 35 | 36 | redis> SET key value 37 | OK 38 | 39 | redis> PTTL key 40 | (integer) -1 41 | 42 | 43 | # 有剩余生存时间的 key 44 | 45 | redis> PEXPIRE key 10086 46 | (integer) 1 47 | 48 | redis> PTTL key 49 | (integer) 6179 50 | -------------------------------------------------------------------------------- /key/randomkey.rst: -------------------------------------------------------------------------------- 1 | .. _randomkey: 2 | 3 | RANDOMKEY 4 | ========== 5 | 6 | **RANDOMKEY** 7 | 8 | 从当前数据库中随机返回(不删除)一个 ``key`` 。 9 | 10 | **可用版本:** 11 | >= 1.0.0 12 | 13 | **时间复杂度:** 14 | O(1) 15 | 16 | **返回值:** 17 | | 当数据库不为空时,返回一个 ``key`` 。 18 | | 当数据库为空时,返回 ``nil`` 。 19 | 20 | :: 21 | 22 | # 数据库不为空 23 | 24 | redis> MSET fruit "apple" drink "beer" food "cookies" # 设置多个 key 25 | OK 26 | 27 | redis> RANDOMKEY 28 | "fruit" 29 | 30 | redis> RANDOMKEY 31 | "food" 32 | 33 | redis> KEYS * # 查看数据库内所有key,证明 RANDOMKEY 并不删除 key 34 | 1) "food" 35 | 2) "drink" 36 | 3) "fruit" 37 | 38 | 39 | # 数据库为空 40 | 41 | redis> FLUSHDB # 删除当前数据库所有 key 42 | OK 43 | 44 | redis> RANDOMKEY 45 | (nil) 46 | -------------------------------------------------------------------------------- /key/rename.rst: -------------------------------------------------------------------------------- 1 | .. _rename: 2 | 3 | RENAME 4 | ======= 5 | 6 | **RENAME key newkey** 7 | 8 | 将 ``key`` 改名为 ``newkey`` 。 9 | 10 | 当 ``key`` 和 ``newkey`` 相同,或者 ``key`` 不存在时,返回一个错误。 11 | 12 | 当 ``newkey`` 已经存在时, `RENAME`_ 命令将覆盖旧值。 13 | 14 | **可用版本:** 15 | >= 1.0.0 16 | 17 | **时间复杂度:** 18 | O(1) 19 | 20 | **返回值:** 21 | 改名成功时提示 ``OK`` ,失败时候返回一个错误。 22 | 23 | :: 24 | 25 | # key 存在且 newkey 不存在 26 | 27 | redis> SET message "hello world" 28 | OK 29 | 30 | redis> RENAME message greeting 31 | OK 32 | 33 | redis> EXISTS message # message 不复存在 34 | (integer) 0 35 | 36 | redis> EXISTS greeting # greeting 取而代之 37 | (integer) 1 38 | 39 | 40 | # 当 key 不存在时,返回错误 41 | 42 | redis> RENAME fake_key never_exists 43 | (error) ERR no such key 44 | 45 | 46 | # newkey 已存在时, RENAME 会覆盖旧 newkey 47 | 48 | redis> SET pc "lenovo" 49 | OK 50 | 51 | redis> SET personal_computer "dell" 52 | OK 53 | 54 | redis> RENAME pc personal_computer 55 | OK 56 | 57 | redis> GET pc 58 | (nil) 59 | 60 | redis:1> GET personal_computer # 原来的值 dell 被覆盖了 61 | "lenovo" 62 | -------------------------------------------------------------------------------- /key/renamenx.rst: -------------------------------------------------------------------------------- 1 | .. _renamenx: 2 | 3 | RENAMENX 4 | ========= 5 | 6 | **RENAMENX key newkey** 7 | 8 | 当且仅当 ``newkey`` 不存在时,将 ``key`` 改名为 ``newkey`` 。 9 | 10 | 当 ``key`` 不存在时,返回一个错误。 11 | 12 | **可用版本:** 13 | >= 1.0.0 14 | 15 | **时间复杂度:** 16 | O(1) 17 | 18 | **返回值:** 19 | | 修改成功时,返回 ``1`` 。 20 | | 如果 ``newkey`` 已经存在,返回 ``0`` 。 21 | 22 | :: 23 | 24 | # newkey 不存在,改名成功 25 | 26 | redis> SET player "MPlyaer" 27 | OK 28 | 29 | redis> EXISTS best_player 30 | (integer) 0 31 | 32 | redis> RENAMENX player best_player 33 | (integer) 1 34 | 35 | 36 | # newkey存在时,失败 37 | 38 | redis> SET animal "bear" 39 | OK 40 | 41 | redis> SET favorite_animal "butterfly" 42 | OK 43 | 44 | redis> RENAMENX animal favorite_animal 45 | (integer) 0 46 | 47 | redis> get animal 48 | "bear" 49 | 50 | redis> get favorite_animal 51 | "butterfly" 52 | -------------------------------------------------------------------------------- /key/restore.rst: -------------------------------------------------------------------------------- 1 | .. _restore: 2 | 3 | RESTORE 4 | ============ 5 | 6 | **RESTORE key ttl serialized-value [REPLACE]** 7 | 8 | 反序列化给定的序列化值,并将它和给定的 ``key`` 关联。 9 | 10 | 参数 ``ttl`` 以毫秒为单位为 ``key`` 设置生存时间;如果 ``ttl`` 为 ``0`` ,那么不设置生存时间。 11 | 12 | `RESTORE`_ 在执行反序列化之前会先对序列化值的 RDB 版本和数据校验和进行检查,如果 RDB 版本不相同或者数据不完整的话,那么 `RESTORE`_ 会拒绝进行反序列化,并返回一个错误。 13 | 14 | 如果键 ``key`` 已经存在, 15 | 并且给定了 ``REPLACE`` 选项, 16 | 那么使用反序列化得出的值来代替键 ``key`` 原有的值; 17 | 相反地, 18 | 如果键 ``key`` 已经存在, 19 | 但是没有给定 ``REPLACE`` 选项, 20 | 那么命令返回一个错误。 21 | 22 | 更多信息可以参考 :doc:`dump` 命令。 23 | 24 | **可用版本:** 25 | >= 2.6.0 26 | 27 | **时间复杂度:** 28 | | 查找给定键的复杂度为 O(1) ,对键进行反序列化的复杂度为 O(N*M) ,其中 N 是构成 ``key`` 的 Redis 对象的数量,而 M 则是这些对象的平均大小。 29 | | 有序集合(sorted set)的反序列化复杂度为 O(N*M*log(N)) ,因为有序集合每次插入的复杂度为 O(log(N)) 。 30 | | 如果反序列化的对象是比较小的字符串,那么复杂度为 O(1) 。 31 | 32 | **返回值:** 33 | | 如果反序列化成功那么返回 ``OK`` ,否则返回一个错误。 34 | 35 | :: 36 | 37 | # 创建一个键,作为 DUMP 命令的输入 38 | 39 | redis> SET greeting "hello, dumping world!" 40 | OK 41 | 42 | redis> DUMP greeting 43 | "\x00\x15hello, dumping world!\x06\x00E\xa0Z\x82\xd8r\xc1\xde" 44 | 45 | # 将序列化数据 RESTORE 到另一个键上面 46 | 47 | redis> RESTORE greeting-again 0 "\x00\x15hello, dumping world!\x06\x00E\xa0Z\x82\xd8r\xc1\xde" 48 | OK 49 | 50 | redis> GET greeting-again 51 | "hello, dumping world!" 52 | 53 | # 在没有给定 REPLACE 选项的情况下,再次尝试反序列化到同一个键,失败 54 | 55 | redis> RESTORE greeting-again 0 "\x00\x15hello, dumping world!\x06\x00E\xa0Z\x82\xd8r\xc1\xde" 56 | (error) ERR Target key name is busy. 57 | 58 | # 给定 REPLACE 选项,对同一个键进行反序列化成功 59 | 60 | redis> RESTORE greeting-again 0 "\x00\x15hello, dumping world!\x06\x00E\xa0Z\x82\xd8r\xc1\xde" REPLACE 61 | OK 62 | 63 | # 尝试使用无效的值进行反序列化,出错 64 | 65 | redis> RESTORE fake-message 0 "hello moto moto blah blah" 66 | (error) ERR DUMP payload version or checksum are wrong 67 | 68 | -------------------------------------------------------------------------------- /key/ttl.rst: -------------------------------------------------------------------------------- 1 | .. _ttl: 2 | 3 | TTL 4 | ==== 5 | 6 | **TTL key** 7 | 8 | 以秒为单位,返回给定 ``key`` 的剩余生存时间(TTL, time to live)。 9 | 10 | **可用版本:** 11 | >= 1.0.0 12 | 13 | **时间复杂度:** 14 | O(1) 15 | 16 | **返回值:** 17 | | 当 ``key`` 不存在时,返回 ``-2`` 。 18 | | 当 ``key`` 存在但没有设置剩余生存时间时,返回 ``-1`` 。 19 | | 否则,以秒为单位,返回 ``key`` 的剩余生存时间。 20 | 21 | .. note:: 在 Redis 2.8 以前,当 ``key`` 不存在,或者 ``key`` 没有设置剩余生存时间时,命令都返回 ``-1`` 。 22 | 23 | :: 24 | 25 | # 不存在的 key 26 | 27 | redis> FLUSHDB 28 | OK 29 | 30 | redis> TTL key 31 | (integer) -2 32 | 33 | 34 | # key 存在,但没有设置剩余生存时间 35 | 36 | redis> SET key value 37 | OK 38 | 39 | redis> TTL key 40 | (integer) -1 41 | 42 | 43 | # 有剩余生存时间的 key 44 | 45 | redis> EXPIRE key 10086 46 | (integer) 1 47 | 48 | redis> TTL key 49 | (integer) 10084 50 | -------------------------------------------------------------------------------- /key/type.rst: -------------------------------------------------------------------------------- 1 | .. _type: 2 | 3 | TYPE 4 | ===== 5 | 6 | **TYPE key** 7 | 8 | 返回 ``key`` 所储存的值的类型。 9 | 10 | **可用版本:** 11 | >= 1.0.0 12 | 13 | **时间复杂度:** 14 | O(1) 15 | 16 | **返回值:** 17 | | ``none`` (key不存在) 18 | | ``string`` (字符串) 19 | | ``list`` (列表) 20 | | ``set`` (集合) 21 | | ``zset`` (有序集) 22 | | ``hash`` (哈希表) 23 | 24 | :: 25 | 26 | # 字符串 27 | 28 | redis> SET weather "sunny" 29 | OK 30 | 31 | redis> TYPE weather 32 | string 33 | 34 | 35 | # 列表 36 | 37 | redis> LPUSH book_list "programming in scala" 38 | (integer) 1 39 | 40 | redis> TYPE book_list 41 | list 42 | 43 | 44 | # 集合 45 | 46 | redis> SADD pat "dog" 47 | (integer) 1 48 | 49 | redis> TYPE pat 50 | set 51 | -------------------------------------------------------------------------------- /list/blpop.rst: -------------------------------------------------------------------------------- 1 | .. _blpop: 2 | 3 | BLPOP 4 | ======= 5 | 6 | **BLPOP key [key ...] timeout** 7 | 8 | `BLPOP`_ 是列表的阻塞式(blocking)弹出原语。 9 | 10 | 它是 :ref:`LPOP` 命令的阻塞版本,当给定列表内没有任何元素可供弹出的时候,连接将被 `BLPOP`_ 命令阻塞,直到等待超时或发现可弹出元素为止。 11 | 12 | 当给定多个 ``key`` 参数时,按参数 ``key`` 的先后顺序依次检查各个列表,弹出第一个非空列表的头元素。 13 | 14 | **非阻塞行为** 15 | 16 | 当 `BLPOP`_ 被调用时,如果给定 ``key`` 内至少有一个非空列表,那么弹出遇到的第一个非空列表的头元素,并和被弹出元素所属的列表的名字一起,组成结果返回给调用者。 17 | 18 | 当存在多个给定 ``key`` 时, `BLPOP`_ 按给定 ``key`` 参数排列的先后顺序,依次检查各个列表。 19 | 20 | 假设现在有 ``job`` 、 ``command`` 和 ``request`` 三个列表,其中 ``job`` 不存在, ``command`` 和 ``request`` 都持有非空列表。考虑以下命令: 21 | 22 | ``BLPOP job command request 0`` 23 | 24 | `BLPOP`_ 保证返回的元素来自 ``command`` ,因为它是按"查找 ``job`` -> 查找 ``command`` -> 查找 ``request`` "这样的顺序,第一个找到的非空列表。 25 | 26 | :: 27 | 28 | redis> DEL job command request # 确保key都被删除 29 | (integer) 0 30 | 31 | redis> LPUSH command "update system..." # 为command列表增加一个值 32 | (integer) 1 33 | 34 | redis> LPUSH request "visit page" # 为request列表增加一个值 35 | (integer) 1 36 | 37 | redis> BLPOP job command request 0 # job 列表为空,被跳过,紧接着 command 列表的第一个元素被弹出。 38 | 1) "command" # 弹出元素所属的列表 39 | 2) "update system..." # 弹出元素所属的值 40 | 41 | **阻塞行为** 42 | 43 | 如果所有给定 ``key`` 都不存在或包含空列表,那么 `BLPOP`_ 命令将阻塞连接,直到等待超时,或有另一个客户端对给定 ``key`` 的任意一个执行 :ref:`LPUSH` 或 :ref:`RPUSH` 命令为止。 44 | 45 | 超时参数 ``timeout`` 接受一个以秒为单位的数字作为值。超时参数设为 ``0`` 表示阻塞时间可以无限期延长(block indefinitely) 。 46 | 47 | :: 48 | 49 | redis> EXISTS job # 确保两个 key 都不存在 50 | (integer) 0 51 | redis> EXISTS command 52 | (integer) 0 53 | 54 | redis> BLPOP job command 300 # 因为key一开始不存在,所以操作会被阻塞,直到另一客户端对 job 或者 command 列表进行 PUSH 操作。 55 | 1) "job" # 这里被 push 的是 job 56 | 2) "do my home work" # 被弹出的值 57 | (26.26s) # 等待的秒数 58 | 59 | redis> BLPOP job command 5 # 等待超时的情况 60 | (nil) 61 | (5.66s) # 等待的秒数 62 | 63 | **相同的key被多个客户端同时阻塞** 64 | 65 | 相同的 ``key`` 可以被多个客户端同时阻塞。 66 | 67 | 不同的客户端被放进一个队列中,按『先阻塞先服务』(first-BLPOP,first-served)的顺序为 ``key`` 执行 `BLPOP`_ 命令。 68 | 69 | **在MULTI/EXEC事务中的BLPOP** 70 | 71 | `BLPOP`_ 可以用于流水线(pipline,批量地发送多个命令并读入多个回复),但把它用在 :ref:`multi` / :ref:`exec` 块当中没有意义。因为这要求整个服务器被阻塞以保证块执行时的原子性,该行为阻止了其他客户端执行 :ref:`LPUSH` 或 :ref:`RPUSH` 命令。 72 | 73 | 因此,一个被包裹在 :ref:`multi` / :ref:`exec` 块内的 `BLPOP`_ 命令,行为表现得就像 :ref:`LPOP` 一样,对空列表返回 ``nil`` ,对非空列表弹出列表元素,不进行任何阻塞操作。 74 | 75 | :: 76 | 77 | # 对非空列表进行操作 78 | 79 | redis> RPUSH job programming 80 | (integer) 1 81 | 82 | redis> MULTI 83 | OK 84 | 85 | redis> BLPOP job 30 86 | QUEUED 87 | 88 | redis> EXEC # 不阻塞,立即返回 89 | 1) 1) "job" 90 | 2) "programming" 91 | 92 | 93 | # 对空列表进行操作 94 | 95 | redis> LLEN job # 空列表 96 | (integer) 0 97 | 98 | redis> MULTI 99 | OK 100 | 101 | redis> BLPOP job 30 102 | QUEUED 103 | 104 | redis> EXEC # 不阻塞,立即返回 105 | 1) (nil) 106 | 107 | **可用版本:** 108 | >= 2.0.0 109 | 110 | **时间复杂度:** 111 | O(1) 112 | 113 | **返回值:** 114 | | 如果列表为空,返回一个 ``nil`` 。 115 | | 否则,返回一个含有两个元素的列表,第一个元素是被弹出元素所属的 ``key`` ,第二个元素是被弹出元素的值。 116 | 117 | 模式:事件提醒 118 | ------------------ 119 | 120 | 有时候,为了等待一个新元素到达数据中,需要使用轮询的方式对数据进行探查。 121 | 122 | 另一种更好的方式是,使用系统提供的阻塞原语,在新元素到达时立即进行处理,而新元素还没到达时,就一直阻塞住,避免轮询占用资源。 123 | 124 | 对于 Redis ,我们似乎需要一个阻塞版的 :ref:`SPOP` 命令,但实际上,使用 `BLPOP`_ 或者 :ref:`BRPOP` 就能很好地解决这个问题。 125 | 126 | 使用元素的客户端(消费者)可以执行类似以下的代码: 127 | 128 | :: 129 | 130 | LOOP forever 131 | WHILE SPOP(key) returns elements 132 | ... process elements ... 133 | END 134 | BRPOP helper_key 135 | END 136 | 137 | 添加元素的客户端(消费者)则执行以下代码: 138 | 139 | :: 140 | 141 | MULTI 142 | SADD key element 143 | LPUSH helper_key x 144 | EXEC 145 | -------------------------------------------------------------------------------- /list/brpop.rst: -------------------------------------------------------------------------------- 1 | .. _brpop: 2 | 3 | BRPOP 4 | ======= 5 | 6 | **BRPOP key [key ...] timeout** 7 | 8 | `BRPOP`_ 是列表的阻塞式(blocking)弹出原语。 9 | 10 | 它是 :ref:`RPOP` 命令的阻塞版本,当给定列表内没有任何元素可供弹出的时候,连接将被 `BRPOP`_ 命令阻塞,直到等待超时或发现可弹出元素为止。 11 | 12 | 当给定多个 ``key`` 参数时,按参数 ``key`` 的先后顺序依次检查各个列表,弹出第一个非空列表的尾部元素。 13 | 14 | 关于阻塞操作的更多信息,请查看 :ref:`BLPOP` 命令, `BRPOP`_ 除了弹出元素的位置和 :ref:`BLPOP` 不同之外,其他表现一致。 15 | 16 | **可用版本:** 17 | >= 2.0.0 18 | 19 | **时间复杂度:** 20 | O(1) 21 | 22 | **返回值:** 23 | | 假如在指定时间内没有任何元素被弹出,则返回一个 ``nil`` 和等待时长。 24 | | 反之,返回一个含有两个元素的列表,第一个元素是被弹出元素所属的 ``key`` ,第二个元素是被弹出元素的值。 25 | 26 | :: 27 | 28 | redis> LLEN course 29 | (integer) 0 30 | 31 | redis> RPUSH course algorithm001 32 | (integer) 1 33 | 34 | redis> RPUSH course c++101 35 | (integer) 2 36 | 37 | redis> BRPOP course 30 38 | 1) "course" # 被弹出元素所属的列表键 39 | 2) "c++101" # 被弹出的元素 40 | -------------------------------------------------------------------------------- /list/brpoplpush.rst: -------------------------------------------------------------------------------- 1 | .. _brpoplpush: 2 | 3 | BRPOPLPUSH 4 | =========== 5 | 6 | **BRPOPLPUSH source destination timeout** 7 | 8 | `BRPOPLPUSH`_ 是 :ref:`RPOPLPUSH` 的阻塞版本,当给定列表 ``source`` 不为空时, `BRPOPLPUSH`_ 的表现和 :ref:`RPOPLPUSH` 一样。 9 | 10 | 当列表 ``source`` 为空时, `BRPOPLPUSH`_ 命令将阻塞连接,直到等待超时,或有另一个客户端对 ``source`` 执行 :ref:`LPUSH` 或 :ref:`RPUSH` 命令为止。 11 | 12 | 超时参数 ``timeout`` 接受一个以秒为单位的数字作为值。超时参数设为 ``0`` 表示阻塞时间可以无限期延长(block indefinitely) 。 13 | 14 | 更多相关信息,请参考 :ref:`RPOPLPUSH` 命令。 15 | 16 | **可用版本:** 17 | >= 2.2.0 18 | 19 | **时间复杂度:** 20 | O(1) 21 | 22 | **返回值:** 23 | | 假如在指定时间内没有任何元素被弹出,则返回一个 ``nil`` 和等待时长。 24 | | 反之,返回一个含有两个元素的列表,第一个元素是被弹出元素的值,第二个元素是等待时长。 25 | 26 | :: 27 | 28 | # 非空列表 29 | 30 | redis> BRPOPLPUSH msg reciver 500 31 | "hello moto" # 弹出元素的值 32 | (3.38s) # 等待时长 33 | 34 | redis> LLEN reciver 35 | (integer) 1 36 | 37 | redis> LRANGE reciver 0 0 38 | 1) "hello moto" 39 | 40 | 41 | # 空列表 42 | 43 | redis> BRPOPLPUSH msg reciver 1 44 | (nil) 45 | (1.34s) 46 | 47 | 模式:安全队列 48 | --------------------- 49 | 50 | 参考 :ref:`RPOPLPUSH` 命令的『安全队列』模式。 51 | 52 | 模式:循环列表 53 | ------------------------ 54 | 55 | 参考 :ref:`RPOPLPUSH` 命令的『循环列表』模式。 56 | -------------------------------------------------------------------------------- /list/index.rst: -------------------------------------------------------------------------------- 1 | List(列表) 2 | ================ 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | 7 | blpop 8 | brpop 9 | brpoplpush 10 | lindex 11 | linsert 12 | llen 13 | lpop 14 | lpush 15 | lpushx 16 | lrange 17 | lrem 18 | lset 19 | ltrim 20 | rpop 21 | rpoplpush 22 | rpush 23 | rpushx 24 | -------------------------------------------------------------------------------- /list/lindex.rst: -------------------------------------------------------------------------------- 1 | .. _lindex: 2 | 3 | LINDEX 4 | ======= 5 | 6 | **LINDEX key index** 7 | 8 | 返回列表 ``key`` 中,下标为 ``index`` 的元素。 9 | 10 | 下标(index)参数 ``start`` 和 ``stop`` 都以 ``0`` 为底,也就是说,以 ``0`` 表示列表的第一个元素,以 ``1`` 表示列表的第二个元素,以此类推。 11 | 12 | 你也可以使用负数下标,以 ``-1`` 表示列表的最后一个元素, ``-2`` 表示列表的倒数第二个元素,以此类推。 13 | 14 | 如果 ``key`` 不是列表类型,返回一个错误。 15 | 16 | **可用版本:** 17 | >= 1.0.0 18 | 19 | **时间复杂度:** 20 | | O(N), ``N`` 为到达下标 ``index`` 过程中经过的元素数量。 21 | | 因此,对列表的头元素和尾元素执行 `LINDEX`_ 命令,复杂度为O(1)。 22 | 23 | **返回值:** 24 | | 列表中下标为 ``index`` 的元素。 25 | | 如果 ``index`` 参数的值不在列表的区间范围内(out of range),返回 ``nil`` 。 26 | 27 | :: 28 | 29 | redis> LPUSH mylist "World" 30 | (integer) 1 31 | 32 | redis> LPUSH mylist "Hello" 33 | (integer) 2 34 | 35 | redis> LINDEX mylist 0 36 | "Hello" 37 | 38 | redis> LINDEX mylist -1 39 | "World" 40 | 41 | redis> LINDEX mylist 3 # index不在 mylist 的区间范围内 42 | (nil) 43 | -------------------------------------------------------------------------------- /list/linsert.rst: -------------------------------------------------------------------------------- 1 | .. _linsert: 2 | 3 | LINSERT 4 | ========= 5 | 6 | **LINSERT key BEFORE|AFTER pivot value** 7 | 8 | 将值 ``value`` 插入到列表 ``key`` 当中,位于值 ``pivot`` 之前或之后。 9 | 10 | 当 ``pivot`` 不存在于列表 ``key`` 时,不执行任何操作。 11 | 12 | 当 ``key`` 不存在时, ``key`` 被视为空列表,不执行任何操作。 13 | 14 | 如果 ``key`` 不是列表类型,返回一个错误。 15 | 16 | **可用版本:** 17 | >= 2.2.0 18 | 19 | **时间复杂度:** 20 | O(N), ``N`` 为寻找 ``pivot`` 过程中经过的元素数量。 21 | 22 | **返回值:** 23 | | 如果命令执行成功,返回插入操作完成之后,列表的长度。 24 | | 如果没有找到 ``pivot`` ,返回 ``-1`` 。 25 | | 如果 ``key`` 不存在或为空列表,返回 ``0`` 。 26 | 27 | :: 28 | 29 | redis> RPUSH mylist "Hello" 30 | (integer) 1 31 | 32 | redis> RPUSH mylist "World" 33 | (integer) 2 34 | 35 | redis> LINSERT mylist BEFORE "World" "There" 36 | (integer) 3 37 | 38 | redis> LRANGE mylist 0 -1 39 | 1) "Hello" 40 | 2) "There" 41 | 3) "World" 42 | 43 | 44 | # 对一个非空列表插入,查找一个不存在的 pivot 45 | 46 | redis> LINSERT mylist BEFORE "go" "let's" 47 | (integer) -1 # 失败 48 | 49 | 50 | # 对一个空列表执行 LINSERT 命令 51 | 52 | redis> EXISTS fake_list 53 | (integer) 0 54 | 55 | redis> LINSERT fake_list BEFORE "nono" "gogogog" 56 | (integer) 0 # 失败 57 | -------------------------------------------------------------------------------- /list/llen.rst: -------------------------------------------------------------------------------- 1 | .. _llen: 2 | 3 | LLEN 4 | ======= 5 | 6 | **LLEN key** 7 | 8 | 返回列表 ``key`` 的长度。 9 | 10 | 如果 ``key`` 不存在,则 ``key`` 被解释为一个空列表,返回 ``0`` . 11 | 12 | 如果 ``key`` 不是列表类型,返回一个错误。 13 | 14 | **可用版本:** 15 | >= 1.0.0 16 | 17 | **时间复杂度:** 18 | O(1) 19 | 20 | **返回值:** 21 | 列表 ``key`` 的长度。 22 | 23 | :: 24 | 25 | # 空列表 26 | 27 | redis> LLEN job 28 | (integer) 0 29 | 30 | 31 | # 非空列表 32 | 33 | redis> LPUSH job "cook food" 34 | (integer) 1 35 | 36 | redis> LPUSH job "have lunch" 37 | (integer) 2 38 | 39 | redis> LLEN job 40 | (integer) 2 41 | -------------------------------------------------------------------------------- /list/lpop.rst: -------------------------------------------------------------------------------- 1 | .. _lpop: 2 | 3 | LPOP 4 | ======= 5 | 6 | **LPOP key** 7 | 8 | 移除并返回列表 ``key`` 的头元素。 9 | 10 | **可用版本:** 11 | >= 1.0.0 12 | 13 | **时间复杂度:** 14 | O(1) 15 | 16 | **返回值:** 17 | | 列表的头元素。 18 | | 当 ``key`` 不存在时,返回 ``nil`` 。 19 | 20 | :: 21 | 22 | redis> LLEN course 23 | (integer) 0 24 | 25 | redis> RPUSH course algorithm001 26 | (integer) 1 27 | 28 | redis> RPUSH course c++101 29 | (integer) 2 30 | 31 | redis> LPOP course # 移除头元素 32 | "algorithm001" 33 | -------------------------------------------------------------------------------- /list/lpush.rst: -------------------------------------------------------------------------------- 1 | .. _lpush: 2 | 3 | LPUSH 4 | ======= 5 | 6 | **LPUSH key value [value ...]** 7 | 8 | 将一个或多个值 ``value`` 插入到列表 ``key`` 的表头 9 | 10 | 如果有多个 ``value`` 值,那么各个 ``value`` 值按从左到右的顺序依次插入到表头: 11 | 比如说,对空列表 ``mylist`` 执行命令 ``LPUSH mylist a b c`` ,列表的值将是 ``c b a`` ,这等同于原子性地执行 ``LPUSH mylist a`` 、 ``LPUSH mylist b`` 和 ``LPUSH mylist c`` 三个命令。 12 | 13 | 如果 ``key`` 不存在,一个空列表会被创建并执行 `LPUSH`_ 操作。 14 | 15 | 当 ``key`` 存在但不是列表类型时,返回一个错误。 16 | 17 | .. note:: 在Redis 2.4版本以前的 `LPUSH`_ 命令,都只接受单个 ``value`` 值。 18 | 19 | **可用版本:** 20 | >= 1.0.0 21 | 22 | **时间复杂度:** 23 | O(1) 24 | 25 | **返回值:** 26 | 执行 `LPUSH`_ 命令后,列表的长度。 27 | 28 | :: 29 | 30 | # 加入单个元素 31 | 32 | redis> LPUSH languages python 33 | (integer) 1 34 | 35 | 36 | # 加入重复元素 37 | 38 | redis> LPUSH languages python 39 | (integer) 2 40 | 41 | redis> LRANGE languages 0 -1 # 列表允许重复元素 42 | 1) "python" 43 | 2) "python" 44 | 45 | 46 | # 加入多个元素 47 | 48 | redis> LPUSH mylist a b c 49 | (integer) 3 50 | 51 | redis> LRANGE mylist 0 -1 52 | 1) "c" 53 | 2) "b" 54 | 3) "a" 55 | -------------------------------------------------------------------------------- /list/lpushx.rst: -------------------------------------------------------------------------------- 1 | .. _lpushx: 2 | 3 | LPUSHX 4 | ======= 5 | 6 | **LPUSHX key value** 7 | 8 | 将值 ``value`` 插入到列表 ``key`` 的表头,当且仅当 ``key`` 存在并且是一个列表。 9 | 10 | 和 :ref:`LPUSH` 命令相反,当 ``key`` 不存在时, `LPUSHX`_ 命令什么也不做。 11 | 12 | **可用版本:** 13 | >= 2.2.0 14 | 15 | **时间复杂度:** 16 | O(1) 17 | 18 | **返回值:** 19 | `LPUSHX`_ 命令执行之后,表的长度。 20 | 21 | :: 22 | 23 | # 对空列表执行 LPUSHX 24 | 25 | redis> LLEN greet # greet 是一个空列表 26 | (integer) 0 27 | 28 | redis> LPUSHX greet "hello" # 尝试 LPUSHX,失败,因为列表为空 29 | (integer) 0 30 | 31 | 32 | # 对非空列表执行 LPUSHX 33 | 34 | redis> LPUSH greet "hello" # 先用 LPUSH 创建一个有一个元素的列表 35 | (integer) 1 36 | 37 | redis> LPUSHX greet "good morning" # 这次 LPUSHX 执行成功 38 | (integer) 2 39 | 40 | redis> LRANGE greet 0 -1 41 | 1) "good morning" 42 | 2) "hello" 43 | -------------------------------------------------------------------------------- /list/lrange.rst: -------------------------------------------------------------------------------- 1 | .. _lrange: 2 | 3 | LRANGE 4 | ======= 5 | 6 | **LRANGE key start stop** 7 | 8 | 返回列表 ``key`` 中指定区间内的元素,区间以偏移量 ``start`` 和 ``stop`` 指定。 9 | 10 | 下标(index)参数 ``start`` 和 ``stop`` 都以 ``0`` 为底,也就是说,以 ``0`` 表示列表的第一个元素,以 ``1`` 表示列表的第二个元素,以此类推。 11 | 12 | 你也可以使用负数下标,以 ``-1`` 表示列表的最后一个元素, ``-2`` 表示列表的倒数第二个元素,以此类推。 13 | 14 | **注意LRANGE命令和编程语言区间函数的区别** 15 | 16 | 假如你有一个包含一百个元素的列表,对该列表执行 ``LRANGE list 0 10`` ,结果是一个包含11个元素的列表,这表明 ``stop`` 下标也在 `LRANGE`_ 命令的取值范围之内(闭区间),这和某些语言的区间函数可能不一致,比如Ruby的 ``Range.new`` 、 ``Array#slice`` 和Python的 ``range()`` 函数。 17 | 18 | **超出范围的下标** 19 | 20 | 超出范围的下标值不会引起错误。 21 | 22 | 如果 ``start`` 下标比列表的最大下标 ``end`` ( ``LLEN list`` 减去 ``1`` )还要大,那么 `LRANGE`_ 返回一个空列表。 23 | 24 | 如果 ``stop`` 下标比 ``end`` 下标还要大,Redis将 ``stop`` 的值设置为 ``end`` 。 25 | 26 | **可用版本:** 27 | >= 1.0.0 28 | 29 | **时间复杂度:** 30 | O(S+N), ``S`` 为偏移量 ``start`` , ``N`` 为指定区间内元素的数量。 31 | 32 | **返回值:** 33 | 一个列表,包含指定区间内的元素。 34 | 35 | :: 36 | 37 | redis> RPUSH fp-language lisp 38 | (integer) 1 39 | 40 | redis> LRANGE fp-language 0 0 41 | 1) "lisp" 42 | 43 | redis> RPUSH fp-language scheme 44 | (integer) 2 45 | 46 | redis> LRANGE fp-language 0 1 47 | 1) "lisp" 48 | 2) "scheme" 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /list/lrem.rst: -------------------------------------------------------------------------------- 1 | .. _lrem: 2 | 3 | LREM 4 | ======= 5 | 6 | **LREM key count value** 7 | 8 | 根据参数 ``count`` 的值,移除列表中与参数 ``value`` 相等的元素。 9 | 10 | ``count`` 的值可以是以下几种: 11 | 12 | - ``count > 0`` : 从表头开始向表尾搜索,移除与 ``value`` 相等的元素,数量为 ``count`` 。 13 | - ``count < 0`` : 从表尾开始向表头搜索,移除与 ``value`` 相等的元素,数量为 ``count`` 的绝对值。 14 | - ``count = 0`` : 移除表中所有与 ``value`` 相等的值。 15 | 16 | **可用版本:** 17 | >= 1.0.0 18 | 19 | **时间复杂度:** 20 | O(N), ``N`` 为列表的长度。 21 | 22 | **返回值:** 23 | | 被移除元素的数量。 24 | | 因为不存在的 ``key`` 被视作空表(empty list),所以当 ``key`` 不存在时, `LREM`_ 命令总是返回 ``0`` 。 25 | 26 | :: 27 | 28 | # 先创建一个表,内容排列是 29 | # morning hello morning helllo morning 30 | 31 | redis> LPUSH greet "morning" 32 | (integer) 1 33 | redis> LPUSH greet "hello" 34 | (integer) 2 35 | redis> LPUSH greet "morning" 36 | (integer) 3 37 | redis> LPUSH greet "hello" 38 | (integer) 4 39 | redis> LPUSH greet "morning" 40 | (integer) 5 41 | 42 | redis> LRANGE greet 0 4 # 查看所有元素 43 | 1) "morning" 44 | 2) "hello" 45 | 3) "morning" 46 | 4) "hello" 47 | 5) "morning" 48 | 49 | redis> LREM greet 2 morning # 移除从表头到表尾,最先发现的两个 morning 50 | (integer) 2 # 两个元素被移除 51 | 52 | redis> LLEN greet # 还剩 3 个元素 53 | (integer) 3 54 | 55 | redis> LRANGE greet 0 2 56 | 1) "hello" 57 | 2) "hello" 58 | 3) "morning" 59 | 60 | redis> LREM greet -1 morning # 移除从表尾到表头,第一个 morning 61 | (integer) 1 62 | 63 | redis> LLEN greet # 剩下两个元素 64 | (integer) 2 65 | 66 | redis> LRANGE greet 0 1 67 | 1) "hello" 68 | 2) "hello" 69 | 70 | redis> LREM greet 0 hello # 移除表中所有 hello 71 | (integer) 2 # 两个 hello 被移除 72 | 73 | redis> LLEN greet 74 | (integer) 0 75 | -------------------------------------------------------------------------------- /list/lset.rst: -------------------------------------------------------------------------------- 1 | .. _lset: 2 | 3 | LSET 4 | ======= 5 | 6 | **LSET key index value** 7 | 8 | 将列表 ``key`` 下标为 ``index`` 的元素的值设置为 ``value`` 。 9 | 10 | 当 ``index`` 参数超出范围,或对一个空列表( ``key`` 不存在)进行 `LSET`_ 时,返回一个错误。 11 | 12 | 关于列表下标的更多信息,请参考 :ref:`LINDEX` 命令。 13 | 14 | **可用版本:** 15 | >= 1.0.0 16 | 17 | **时间复杂度:** 18 | | 对头元素或尾元素进行 `LSET`_ 操作,复杂度为 O(1)。 19 | | 其他情况下,为 O(N), ``N`` 为列表的长度。 20 | 21 | **返回值:** 22 | 操作成功返回 ``ok`` ,否则返回错误信息。 23 | 24 | :: 25 | 26 | # 对空列表(key 不存在)进行 LSET 27 | 28 | redis> EXISTS list 29 | (integer) 0 30 | 31 | redis> LSET list 0 item 32 | (error) ERR no such key 33 | 34 | 35 | # 对非空列表进行 LSET 36 | 37 | redis> LPUSH job "cook food" 38 | (integer) 1 39 | 40 | redis> LRANGE job 0 0 41 | 1) "cook food" 42 | 43 | redis> LSET job 0 "play game" 44 | OK 45 | 46 | redis> LRANGE job 0 0 47 | 1) "play game" 48 | 49 | 50 | # index 超出范围 51 | 52 | redis> LLEN list # 列表长度为 1 53 | (integer) 1 54 | 55 | redis> LSET list 3 'out of range' 56 | (error) ERR index out of range 57 | -------------------------------------------------------------------------------- /list/ltrim.rst: -------------------------------------------------------------------------------- 1 | .. _ltrim: 2 | 3 | LTRIM 4 | ======= 5 | 6 | **LTRIM key start stop** 7 | 8 | 对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。 9 | 10 | 举个例子,执行命令 ``LTRIM list 0 2`` ,表示只保留列表 ``list`` 的前三个元素,其余元素全部删除。 11 | 12 | 下标(index)参数 ``start`` 和 ``stop`` 都以 ``0`` 为底,也就是说,以 ``0`` 表示列表的第一个元素,以 ``1`` 表示列表的第二个元素,以此类推。 13 | 14 | 你也可以使用负数下标,以 ``-1`` 表示列表的最后一个元素, ``-2`` 表示列表的倒数第二个元素,以此类推。 15 | 16 | 当 ``key`` 不是列表类型时,返回一个错误。 17 | 18 | `LTRIM`_ 命令通常和 :ref:`LPUSH` 命令或 :ref:`RPUSH` 命令配合使用,举个例子: 19 | 20 | :: 21 | 22 | LPUSH log newest_log 23 | LTRIM log 0 99 24 | 25 | 这个例子模拟了一个日志程序,每次将最新日志 ``newest_log`` 放到 ``log`` 列表中,并且只保留最新的 ``100`` 项。注意当这样使用 ``LTRIM`` 命令时,时间复杂度是O(1),因为平均情况下,每次只有一个元素被移除。 26 | 27 | **注意LTRIM命令和编程语言区间函数的区别** 28 | 29 | 假如你有一个包含一百个元素的列表 ``list`` ,对该列表执行 ``LTRIM list 0 10`` ,结果是一个包含11个元素的列表,这表明 ``stop`` 下标也在 `LTRIM`_ 命令的取值范围之内(闭区间),这和某些语言的区间函数可能不一致,比如Ruby的 ``Range.new`` 、 ``Array#slice`` 和Python的 ``range()`` 函数。 30 | 31 | **超出范围的下标** 32 | 33 | 超出范围的下标值不会引起错误。 34 | 35 | 如果 ``start`` 下标比列表的最大下标 ``end`` ( ``LLEN list`` 减去 ``1`` )还要大,或者 ``start > stop`` , `LTRIM`_ 返回一个空列表(因为 `LTRIM`_ 已经将整个列表清空)。 36 | 37 | 如果 ``stop`` 下标比 ``end`` 下标还要大,Redis将 ``stop`` 的值设置为 ``end`` 。 38 | 39 | **可用版本:** 40 | >= 1.0.0 41 | 42 | **时间复杂度:** 43 | O(N), ``N`` 为被移除的元素的数量。 44 | 45 | **返回值:** 46 | | 命令执行成功时,返回 ``ok`` 。 47 | 48 | :: 49 | 50 | # 情况 1: 常见情况, start 和 stop 都在列表的索引范围之内 51 | 52 | redis> LRANGE alpha 0 -1 # alpha 是一个包含 5 个字符串的列表 53 | 1) "h" 54 | 2) "e" 55 | 3) "l" 56 | 4) "l" 57 | 5) "o" 58 | 59 | redis> LTRIM alpha 1 -1 # 删除 alpha 列表索引为 0 的元素 60 | OK 61 | 62 | redis> LRANGE alpha 0 -1 # "h" 被删除了 63 | 1) "e" 64 | 2) "l" 65 | 3) "l" 66 | 4) "o" 67 | 68 | 69 | # 情况 2: stop 比列表的最大下标还要大 70 | 71 | 72 | redis> LTRIM alpha 1 10086 # 保留 alpha 列表索引 1 至索引 10086 上的元素 73 | OK 74 | 75 | redis> LRANGE alpha 0 -1 # 只有索引 0 上的元素 "e" 被删除了,其他元素还在 76 | 1) "l" 77 | 2) "l" 78 | 3) "o" 79 | 80 | 81 | # 情况 3: start 和 stop 都比列表的最大下标要大,并且 start < stop 82 | 83 | redis> LTRIM alpha 10086 123321 84 | OK 85 | 86 | redis> LRANGE alpha 0 -1 # 列表被清空 87 | (empty list or set) 88 | 89 | 90 | # 情况 4: start 和 stop 都比列表的最大下标要大,并且 start > stop 91 | 92 | redis> RPUSH new-alpha "h" "e" "l" "l" "o" # 重新建立一个新列表 93 | (integer) 5 94 | 95 | redis> LRANGE new-alpha 0 -1 96 | 1) "h" 97 | 2) "e" 98 | 3) "l" 99 | 4) "l" 100 | 5) "o" 101 | 102 | redis> LTRIM new-alpha 123321 10086 # 执行 LTRIM 103 | OK 104 | 105 | redis> LRANGE new-alpha 0 -1 # 同样被清空 106 | (empty list or set) 107 | -------------------------------------------------------------------------------- /list/rpop.rst: -------------------------------------------------------------------------------- 1 | .. _rpop: 2 | 3 | RPOP 4 | ======= 5 | 6 | **RPOP key** 7 | 8 | 移除并返回列表 ``key`` 的尾元素。 9 | 10 | **可用版本:** 11 | >= 1.0.0 12 | 13 | **时间复杂度:** 14 | O(1) 15 | 16 | **返回值:** 17 | | 列表的尾元素。 18 | | 当 ``key`` 不存在时,返回 ``nil`` 。 19 | 20 | :: 21 | 22 | redis> RPUSH mylist "one" 23 | (integer) 1 24 | 25 | redis> RPUSH mylist "two" 26 | (integer) 2 27 | 28 | redis> RPUSH mylist "three" 29 | (integer) 3 30 | 31 | redis> RPOP mylist # 返回被弹出的元素 32 | "three" 33 | 34 | redis> LRANGE mylist 0 -1 # 列表剩下的元素 35 | 1) "one" 36 | 2) "two" 37 | -------------------------------------------------------------------------------- /list/rpoplpush.rst: -------------------------------------------------------------------------------- 1 | .. _rpoplpush: 2 | 3 | RPOPLPUSH 4 | =========== 5 | 6 | **RPOPLPUSH source destination** 7 | 8 | 命令 `RPOPLPUSH`_ 在一个原子时间内,执行以下两个动作: 9 | 10 | - 将列表 ``source`` 中的最后一个元素(尾元素)弹出,并返回给客户端。 11 | - 将 ``source`` 弹出的元素插入到列表 ``destination`` ,作为 ``destination`` 列表的的头元素。 12 | 13 | 举个例子,你有两个列表 ``source`` 和 ``destination`` , ``source`` 列表有元素 ``a, b, c`` , ``destination`` 列表有元素 ``x, y, z`` ,执行 ``RPOPLPUSH source destination`` 之后, ``source`` 列表包含元素 ``a, b`` , ``destination`` 列表包含元素 ``c, x, y, z`` ,并且元素 ``c`` 会被返回给客户端。 14 | 15 | 如果 ``source`` 不存在,值 ``nil`` 被返回,并且不执行其他动作。 16 | 17 | 如果 ``source`` 和 ``destination`` 相同,则列表中的表尾元素被移动到表头,并返回该元素,可以把这种特殊情况视作列表的旋转(rotation)操作。 18 | 19 | **可用版本:** 20 | >= 1.2.0 21 | 22 | **时间复杂度:** 23 | O(1) 24 | 25 | **返回值:** 26 | 被弹出的元素。 27 | 28 | :: 29 | 30 | 31 | # source 和 destination 不同 32 | 33 | redis> LRANGE alpha 0 -1 # 查看所有元素 34 | 1) "a" 35 | 2) "b" 36 | 3) "c" 37 | 4) "d" 38 | 39 | redis> RPOPLPUSH alpha reciver # 执行一次 RPOPLPUSH 看看 40 | "d" 41 | 42 | redis> LRANGE alpha 0 -1 43 | 1) "a" 44 | 2) "b" 45 | 3) "c" 46 | 47 | redis> LRANGE reciver 0 -1 48 | 1) "d" 49 | 50 | redis> RPOPLPUSH alpha reciver # 再执行一次,证实 RPOP 和 LPUSH 的位置正确 51 | "c" 52 | 53 | redis> LRANGE alpha 0 -1 54 | 1) "a" 55 | 2) "b" 56 | 57 | redis> LRANGE reciver 0 -1 58 | 1) "c" 59 | 2) "d" 60 | 61 | 62 | # source 和 destination 相同 63 | 64 | redis> LRANGE number 0 -1 65 | 1) "1" 66 | 2) "2" 67 | 3) "3" 68 | 4) "4" 69 | 70 | redis> RPOPLPUSH number number 71 | "4" 72 | 73 | redis> LRANGE number 0 -1 # 4 被旋转到了表头 74 | 1) "4" 75 | 2) "1" 76 | 3) "2" 77 | 4) "3" 78 | 79 | redis> RPOPLPUSH number number 80 | "3" 81 | 82 | redis> LRANGE number 0 -1 # 这次是 3 被旋转到了表头 83 | 1) "3" 84 | 2) "4" 85 | 3) "1" 86 | 4) "2" 87 | 88 | 模式: 安全的队列 89 | ---------------------------- 90 | 91 | Redis的列表经常被用作队列(queue),用于在不同程序之间有序地交换消息(message)。一个客户端通过 :ref:`LPUSH` 命令将消息放入队列中,而另一个客户端通过 :ref:`RPOP` 或者 :ref:`BRPOP` 命令取出队列中等待时间最长的消息。 92 | 93 | 不幸的是,上面的队列方法是『不安全』的,因为在这个过程中,一个客户端可能在取出一个消息之后崩溃,而未处理完的消息也就因此丢失。 94 | 95 | 使用 `RPOPLPUSH`_ 命令(或者它的阻塞版本 :ref:`BRPOPLPUSH` )可以解决这个问题:因为它不仅返回一个消息,同时还将这个消息添加到另一个备份列表当中,如果一切正常的话,当一个客户端完成某个消息的处理之后,可以用 :ref:`LREM` 命令将这个消息从备份表删除。 96 | 97 | 最后,还可以添加一个客户端专门用于监视备份表,它自动地将超过一定处理时限的消息重新放入队列中去(负责处理该消息的客户端可能已经崩溃),这样就不会丢失任何消息了。 98 | 99 | 模式:循环列表 100 | -------------------- 101 | 102 | 通过使用相同的 ``key`` 作为 `RPOPLPUSH`_ 命令的两个参数,客户端可以用一个接一个地获取列表元素的方式,取得列表的所有元素,而不必像 :ref:`LRANGE` 命令那样一下子将所有列表元素都从服务器传送到客户端中(两种方式的总复杂度都是 O(N))。 103 | 104 | 以上的模式甚至在以下的两个情况下也能正常工作: 105 | 106 | - 有多个客户端同时对同一个列表进行旋转(rotating),它们获取不同的元素,直到所有元素都被读取完,之后又从头开始。 107 | - 有客户端在向列表尾部(右边)添加新元素。 108 | 109 | 这个模式使得我们可以很容易实现这样一类系统:有 N 个客户端,需要连续不断地对一些元素进行处理,而且处理的过程必须尽可能地快。一个典型的例子就是服务器的监控程序:它们需要在尽可能短的时间内,并行地检查一组网站,确保它们的可访问性。 110 | 111 | 注意,使用这个模式的客户端是易于扩展(scala)且安全(reliable)的,因为就算接收到元素的客户端失败,元素还是保存在列表里面,不会丢失,等到下个迭代来临的时候,别的客户端又可以继续处理这些元素了。 112 | -------------------------------------------------------------------------------- /list/rpush.rst: -------------------------------------------------------------------------------- 1 | .. _rpush: 2 | 3 | RPUSH 4 | ======== 5 | 6 | **RPUSH key value [value ...]** 7 | 8 | 将一个或多个值 ``value`` 插入到列表 ``key`` 的表尾(最右边)。 9 | 10 | 如果有多个 ``value`` 值,那么各个 ``value`` 值按从左到右的顺序依次插入到表尾:比如对一个空列表 ``mylist`` 执行 ``RPUSH mylist a b c`` ,得出的结果列表为 ``a b c`` ,等同于执行命令 ``RPUSH mylist a`` 、 ``RPUSH mylist b`` 、 ``RPUSH mylist c`` 。 11 | 12 | 如果 ``key`` 不存在,一个空列表会被创建并执行 `RPUSH`_ 操作。 13 | 14 | 当 ``key`` 存在但不是列表类型时,返回一个错误。 15 | 16 | .. note:: 在 Redis 2.4 版本以前的 `RPUSH`_ 命令,都只接受单个 ``value`` 值。 17 | 18 | **可用版本:** 19 | >= 1.0.0 20 | 21 | **时间复杂度:** 22 | O(1) 23 | 24 | **返回值:** 25 | 执行 `RPUSH`_ 操作后,表的长度。 26 | 27 | :: 28 | 29 | # 添加单个元素 30 | 31 | redis> RPUSH languages c 32 | (integer) 1 33 | 34 | 35 | # 添加重复元素 36 | 37 | redis> RPUSH languages c 38 | (integer) 2 39 | 40 | redis> LRANGE languages 0 -1 # 列表允许重复元素 41 | 1) "c" 42 | 2) "c" 43 | 44 | 45 | # 添加多个元素 46 | 47 | redis> RPUSH mylist a b c 48 | (integer) 3 49 | 50 | redis> LRANGE mylist 0 -1 51 | 1) "a" 52 | 2) "b" 53 | 3) "c" 54 | -------------------------------------------------------------------------------- /list/rpushx.rst: -------------------------------------------------------------------------------- 1 | .. _rpushx: 2 | 3 | RPUSHX 4 | ======= 5 | 6 | **RPUSHX key value** 7 | 8 | 将值 ``value`` 插入到列表 ``key`` 的表尾,当且仅当 ``key`` 存在并且是一个列表。 9 | 10 | 和 :ref:`RPUSH` 命令相反,当 ``key`` 不存在时, `RPUSHX`_ 命令什么也不做。 11 | 12 | **可用版本:** 13 | >= 2.2.0 14 | 15 | **时间复杂度:** 16 | O(1) 17 | 18 | **返回值:** 19 | `RPUSHX`_ 命令执行之后,表的长度。 20 | 21 | :: 22 | 23 | # key不存在 24 | 25 | redis> LLEN greet 26 | (integer) 0 27 | 28 | redis> RPUSHX greet "hello" # 对不存在的 key 进行 RPUSHX,PUSH 失败。 29 | (integer) 0 30 | 31 | 32 | # key 存在且是一个非空列表 33 | 34 | redis> RPUSH greet "hi" # 先用 RPUSH 插入一个元素 35 | (integer) 1 36 | 37 | redis> RPUSHX greet "hello" # greet 现在是一个列表类型,RPUSHX 操作成功。 38 | (integer) 2 39 | 40 | redis> LRANGE greet 0 -1 41 | 1) "hi" 42 | 2) "hello" 43 | -------------------------------------------------------------------------------- /make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=_build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . 10 | if NOT "%PAPER%" == "" ( 11 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 12 | ) 13 | 14 | if "%1" == "" goto help 15 | 16 | if "%1" == "help" ( 17 | :help 18 | echo.Please use `make ^` where ^ is one of 19 | echo. html to make standalone HTML files 20 | echo. dirhtml to make HTML files named index.html in directories 21 | echo. singlehtml to make a single large HTML file 22 | echo. pickle to make pickle files 23 | echo. json to make JSON files 24 | echo. htmlhelp to make HTML files and a HTML help project 25 | echo. qthelp to make HTML files and a qthelp project 26 | echo. devhelp to make HTML files and a Devhelp project 27 | echo. epub to make an epub 28 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 29 | echo. text to make text files 30 | echo. man to make manual pages 31 | echo. changes to make an overview over all changed/added/deprecated items 32 | echo. linkcheck to check all external links for integrity 33 | echo. doctest to run all doctests embedded in the documentation if enabled 34 | goto end 35 | ) 36 | 37 | if "%1" == "clean" ( 38 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 39 | del /q /s %BUILDDIR%\* 40 | goto end 41 | ) 42 | 43 | if "%1" == "html" ( 44 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 45 | if errorlevel 1 exit /b 1 46 | echo. 47 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 48 | goto end 49 | ) 50 | 51 | if "%1" == "dirhtml" ( 52 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 53 | if errorlevel 1 exit /b 1 54 | echo. 55 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 56 | goto end 57 | ) 58 | 59 | if "%1" == "singlehtml" ( 60 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 61 | if errorlevel 1 exit /b 1 62 | echo. 63 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 64 | goto end 65 | ) 66 | 67 | if "%1" == "pickle" ( 68 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 69 | if errorlevel 1 exit /b 1 70 | echo. 71 | echo.Build finished; now you can process the pickle files. 72 | goto end 73 | ) 74 | 75 | if "%1" == "json" ( 76 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 77 | if errorlevel 1 exit /b 1 78 | echo. 79 | echo.Build finished; now you can process the JSON files. 80 | goto end 81 | ) 82 | 83 | if "%1" == "htmlhelp" ( 84 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 85 | if errorlevel 1 exit /b 1 86 | echo. 87 | echo.Build finished; now you can run HTML Help Workshop with the ^ 88 | .hhp project file in %BUILDDIR%/htmlhelp. 89 | goto end 90 | ) 91 | 92 | if "%1" == "qthelp" ( 93 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 94 | if errorlevel 1 exit /b 1 95 | echo. 96 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 97 | .qhcp project file in %BUILDDIR%/qthelp, like this: 98 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\rediscommandreferencechineseversion.qhcp 99 | echo.To view the help file: 100 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\rediscommandreferencechineseversion.ghc 101 | goto end 102 | ) 103 | 104 | if "%1" == "devhelp" ( 105 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 106 | if errorlevel 1 exit /b 1 107 | echo. 108 | echo.Build finished. 109 | goto end 110 | ) 111 | 112 | if "%1" == "epub" ( 113 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 114 | if errorlevel 1 exit /b 1 115 | echo. 116 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 117 | goto end 118 | ) 119 | 120 | if "%1" == "latex" ( 121 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 122 | if errorlevel 1 exit /b 1 123 | echo. 124 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 125 | goto end 126 | ) 127 | 128 | if "%1" == "text" ( 129 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 130 | if errorlevel 1 exit /b 1 131 | echo. 132 | echo.Build finished. The text files are in %BUILDDIR%/text. 133 | goto end 134 | ) 135 | 136 | if "%1" == "man" ( 137 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 138 | if errorlevel 1 exit /b 1 139 | echo. 140 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 141 | goto end 142 | ) 143 | 144 | if "%1" == "changes" ( 145 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 146 | if errorlevel 1 exit /b 1 147 | echo. 148 | echo.The overview file is in %BUILDDIR%/changes. 149 | goto end 150 | ) 151 | 152 | if "%1" == "linkcheck" ( 153 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 154 | if errorlevel 1 exit /b 1 155 | echo. 156 | echo.Link check complete; look for any errors in the above output ^ 157 | or in %BUILDDIR%/linkcheck/output.txt. 158 | goto end 159 | ) 160 | 161 | if "%1" == "doctest" ( 162 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 163 | if errorlevel 1 exit /b 1 164 | echo. 165 | echo.Testing of doctests in the sources finished, look at the ^ 166 | results in %BUILDDIR%/doctest/output.txt. 167 | goto end 168 | ) 169 | 170 | :end 171 | -------------------------------------------------------------------------------- /pay_to_huangz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/me115/redis/97747be488c7857e241d14b69ee5d3088bbe8136/pay_to_huangz.png -------------------------------------------------------------------------------- /pub_sub/index.rst: -------------------------------------------------------------------------------- 1 | Pub/Sub(发布/订阅) 2 | ======================= 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | 7 | psubscribe 8 | publish 9 | pubsub 10 | punsubscribe 11 | subscribe 12 | unsubscribe 13 | 14 | -------------------------------------------------------------------------------- /pub_sub/psubscribe.rst: -------------------------------------------------------------------------------- 1 | .. _psubscribe: 2 | 3 | PSUBSCRIBE 4 | =========== 5 | 6 | **PSUBSCRIBE pattern [pattern ...]** 7 | 8 | 订阅一个或多个符合给定模式的频道。 9 | 10 | 每个模式以 ``*`` 作为匹配符,比如 ``it*`` 匹配所有以 ``it`` 开头的频道( ``it.news`` 、 ``it.blog`` 、 ``it.tweets`` 等等), ``news.*`` 匹配所有以 ``news.`` 开头的频道( ``news.it`` 、 ``news.global.today`` 等等),诸如此类。 11 | 12 | **可用版本:** 13 | >= 2.0.0 14 | 15 | **时间复杂度:** 16 | O(N), ``N`` 是订阅的模式的数量。 17 | 18 | **返回值:** 19 | 接收到的信息(请参见下面的代码说明)。 20 | 21 | :: 22 | 23 | # 订阅 news.* 和 tweet.* 两个模式 24 | 25 | # 第 1 - 6 行是执行 psubscribe 之后的反馈信息 26 | # 第 7 - 10 才是接收到的第一条信息 27 | # 第 11 - 14 是第二条 28 | # 以此类推。。。 29 | 30 | redis> psubscribe news.* tweet.* 31 | Reading messages... (press Ctrl-C to quit) 32 | 1) "psubscribe" # 返回值的类型:显示订阅成功 33 | 2) "news.*" # 订阅的模式 34 | 3) (integer) 1 # 目前已订阅的模式的数量 35 | 36 | 1) "psubscribe" 37 | 2) "tweet.*" 38 | 3) (integer) 2 39 | 40 | 1) "pmessage" # 返回值的类型:信息 41 | 2) "news.*" # 信息匹配的模式 42 | 3) "news.it" # 信息本身的目标频道 43 | 4) "Google buy Motorola" # 信息的内容 44 | 45 | 1) "pmessage" 46 | 2) "tweet.*" 47 | 3) "tweet.huangz" 48 | 4) "hello" 49 | 50 | 1) "pmessage" 51 | 2) "tweet.*" 52 | 3) "tweet.joe" 53 | 4) "@huangz morning" 54 | 55 | 1) "pmessage" 56 | 2) "news.*" 57 | 3) "news.life" 58 | 4) "An apple a day, keep doctors away" 59 | -------------------------------------------------------------------------------- /pub_sub/publish.rst: -------------------------------------------------------------------------------- 1 | .. _publish: 2 | 3 | PUBLISH 4 | ========= 5 | 6 | **PUBLISH channel message** 7 | 8 | 将信息 ``message`` 发送到指定的频道 ``channel`` 。 9 | 10 | **可用版本:** 11 | >= 2.0.0 12 | 13 | **时间复杂度:** 14 | O(N+M),其中 ``N`` 是频道 ``channel`` 的订阅者数量,而 ``M`` 则是使用模式订阅(subscribed patterns)的客户端的数量。 15 | 16 | **返回值:** 17 | 接收到信息 ``message`` 的订阅者数量。 18 | 19 | :: 20 | 21 | # 对没有订阅者的频道发送信息 22 | 23 | redis> publish bad_channel "can any body hear me?" 24 | (integer) 0 25 | 26 | 27 | # 向有一个订阅者的频道发送信息 28 | 29 | redis> publish msg "good morning" 30 | (integer) 1 31 | 32 | 33 | # 向有多个订阅者的频道发送信息 34 | 35 | redis> publish chat_room "hello~ everyone" 36 | (integer) 3 37 | -------------------------------------------------------------------------------- /pub_sub/pubsub.rst: -------------------------------------------------------------------------------- 1 | .. _pubsub: 2 | 3 | PUBSUB 4 | ========= 5 | 6 | **PUBSUB [argument [argument ...]]** 7 | 8 | :ref:`PUBSUB` 是一个查看订阅与发布系统状态的内省命令, 9 | 它由数个不同格式的子命令组成, 10 | 以下将分别对这些子命令进行介绍。 11 | 12 | **可用版本:** >= 2.8.0 13 | 14 | 15 | PUBSUB CHANNELS [pattern] 16 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 17 | 18 | 列出当前的活跃频道。 19 | 20 | 活跃频道指的是那些至少有一个订阅者的频道, 21 | 订阅模式的客户端不计算在内。 22 | 23 | ``pattern`` 参数是可选的: 24 | 25 | - 如果不给出 ``pattern`` 参数,那么列出订阅与发布系统中的所有活跃频道。 26 | 27 | - 如果给出 ``pattern`` 参数,那么只列出和给定模式 ``pattern`` 相匹配的那些活跃频道。 28 | 29 | **复杂度:** O(N) , ``N`` 为活跃频道的数量(对于长度较短的频道和模式来说,将进行模式匹配的复杂度视为常数)。 30 | 31 | **返回值:** 一个由活跃频道组成的列表。 32 | 33 | :: 34 | 35 | # client-1 订阅 news.it 和 news.sport 两个频道 36 | 37 | client-1> SUBSCRIBE news.it news.sport 38 | Reading messages... (press Ctrl-C to quit) 39 | 1) "subscribe" 40 | 2) "news.it" 41 | 3) (integer) 1 42 | 1) "subscribe" 43 | 2) "news.sport" 44 | 3) (integer) 2 45 | 46 | # client-2 订阅 news.it 和 news.internet 两个频道 47 | 48 | client-2> SUBSCRIBE news.it news.internet 49 | Reading messages... (press Ctrl-C to quit) 50 | 1) "subscribe" 51 | 2) "news.it" 52 | 3) (integer) 1 53 | 1) "subscribe" 54 | 2) "news.internet" 55 | 3) (integer) 2 56 | 57 | # 首先, client-3 打印所有活跃频道 58 | # 注意,即使一个频道有多个订阅者,它也只输出一次,比如 news.it 59 | 60 | client-3> PUBSUB CHANNELS 61 | 1) "news.sport" 62 | 2) "news.internet" 63 | 3) "news.it" 64 | 65 | # 接下来, client-3 打印那些与模式 news.i* 相匹配的活跃频道 66 | # 因为 news.sport 不匹配 news.i* ,所以它没有被打印 67 | 68 | redis> PUBSUB CHANNELS news.i* 69 | 1) "news.internet" 70 | 2) "news.it" 71 | 72 | 73 | PUBSUB NUMSUB [channel-1 ... channel-N] 74 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 75 | 76 | 返回给定频道的订阅者数量, 77 | 订阅模式的客户端不计算在内。 78 | 79 | **复杂度:** O(N) , ``N`` 为给定频道的数量。 80 | 81 | **返回值:** 82 | 一个多条批量回复(Multi-bulk reply),回复中包含给定的频道,以及频道的订阅者数量。 83 | 格式为:频道 ``channel-1`` , ``channel-1`` 的订阅者数量,频道 ``channel-2`` , ``channel-2`` 的订阅者数量,诸如此类。 84 | 回复中频道的排列顺序和执行命令时给定频道的排列顺序一致。 85 | 不给定任何频道而直接调用这个命令也是可以的, 86 | 在这种情况下, 87 | 命令只返回一个空列表。 88 | 89 | :: 90 | 91 | # client-1 订阅 news.it 和 news.sport 两个频道 92 | 93 | client-1> SUBSCRIBE news.it news.sport 94 | Reading messages... (press Ctrl-C to quit) 95 | 1) "subscribe" 96 | 2) "news.it" 97 | 3) (integer) 1 98 | 1) "subscribe" 99 | 2) "news.sport" 100 | 3) (integer) 2 101 | 102 | # client-2 订阅 news.it 和 news.internet 两个频道 103 | 104 | client-2> SUBSCRIBE news.it news.internet 105 | Reading messages... (press Ctrl-C to quit) 106 | 1) "subscribe" 107 | 2) "news.it" 108 | 3) (integer) 1 109 | 1) "subscribe" 110 | 2) "news.internet" 111 | 3) (integer) 2 112 | 113 | # client-3 打印各个频道的订阅者数量 114 | 115 | client-3> PUBSUB NUMSUB news.it news.internet news.sport news.music 116 | 1) "news.it" # 频道 117 | 2) "2" # 订阅该频道的客户端数量 118 | 3) "news.internet" 119 | 4) "1" 120 | 5) "news.sport" 121 | 6) "1" 122 | 7) "news.music" # 没有任何订阅者 123 | 8) "0" 124 | 125 | 126 | PUBSUB NUMPAT 127 | ^^^^^^^^^^^^^^^^^ 128 | 129 | 返回订阅模式的数量。 130 | 131 | 注意, 132 | 这个命令返回的不是订阅模式的客户端的数量, 133 | 而是客户端订阅的所有模式的数量总和。 134 | 135 | **复杂度:** O(1) 。 136 | 137 | **返回值:** 一个整数回复(Integer reply)。 138 | 139 | :: 140 | 141 | # client-1 订阅 news.* 和 discount.* 两个模式 142 | 143 | client-1> PSUBSCRIBE news.* discount.* 144 | Reading messages... (press Ctrl-C to quit) 145 | 1) "psubscribe" 146 | 2) "news.*" 147 | 3) (integer) 1 148 | 1) "psubscribe" 149 | 2) "discount.*" 150 | 3) (integer) 2 151 | 152 | # client-2 订阅 tweet.* 一个模式 153 | 154 | client-2> PSUBSCRIBE tweet.* 155 | Reading messages... (press Ctrl-C to quit) 156 | 1) "psubscribe" 157 | 2) "tweet.*" 158 | 3) (integer) 1 159 | 160 | # client-3 返回当前订阅模式的数量为 3 161 | 162 | client-3> PUBSUB NUMPAT 163 | (integer) 3 164 | 165 | # 注意,当有多个客户端订阅相同的模式时,相同的订阅也被计算在 PUBSUB NUMPAT 之内 166 | # 比如说,再新建一个客户端 client-4 ,让它也订阅 news.* 频道 167 | 168 | client-4> PSUBSCRIBE news.* 169 | Reading messages... (press Ctrl-C to quit) 170 | 1) "psubscribe" 171 | 2) "news.*" 172 | 3) (integer) 1 173 | 174 | # 这时再计算被订阅模式的数量,就会得到数量为 4 175 | 176 | client-3> PUBSUB NUMPAT 177 | (integer) 4 178 | -------------------------------------------------------------------------------- /pub_sub/punsubscribe.rst: -------------------------------------------------------------------------------- 1 | .. _punsubscribe: 2 | 3 | PUNSUBSCRIBE 4 | =============== 5 | 6 | **PUNSUBSCRIBE [pattern [pattern ...]]** 7 | 8 | 指示客户端退订所有给定模式。 9 | 10 | 如果没有模式被指定,也即是,一个无参数的 ``PUNSUBSCRIBE`` 调用被执行,那么客户端使用 :ref:`PSUBSCRIBE` 命令订阅的所有模式都会被退订。在这种情况下,命令会返回一个信息,告知客户端所有被退订的模式。 11 | 12 | **可用版本:** 13 | >= 2.0.0 14 | 15 | **时间复杂度:** 16 | O(N+M) ,其中 ``N`` 是客户端已订阅的模式的数量, ``M`` 则是系统中所有客户端订阅的模式的数量。 17 | 18 | **返回值:** 19 | 这个命令在不同的客户端中有不同的表现。 20 | -------------------------------------------------------------------------------- /pub_sub/subscribe.rst: -------------------------------------------------------------------------------- 1 | .. _subscribe: 2 | 3 | SUBSCRIBE 4 | ========== 5 | 6 | **SUBSCRIBE channel [channel ...]** 7 | 8 | 订阅给定的一个或多个频道的信息。 9 | 10 | **可用版本:** 11 | >= 2.0.0 12 | 13 | **时间复杂度:** 14 | O(N),其中 ``N`` 是订阅的频道的数量。 15 | 16 | **返回值:** 17 | 接收到的信息(请参见下面的代码说明)。 18 | 19 | :: 20 | 21 | # 订阅 msg 和 chat_room 两个频道 22 | 23 | # 1 - 6 行是执行 subscribe 之后的反馈信息 24 | # 第 7 - 9 行才是接收到的第一条信息 25 | # 第 10 - 12 行是第二条 26 | 27 | redis> subscribe msg chat_room 28 | Reading messages... (press Ctrl-C to quit) 29 | 1) "subscribe" # 返回值的类型:显示订阅成功 30 | 2) "msg" # 订阅的频道名字 31 | 3) (integer) 1 # 目前已订阅的频道数量 32 | 33 | 1) "subscribe" 34 | 2) "chat_room" 35 | 3) (integer) 2 36 | 37 | 1) "message" # 返回值的类型:信息 38 | 2) "msg" # 来源(从那个频道发送过来) 39 | 3) "hello moto" # 信息内容 40 | 41 | 1) "message" 42 | 2) "chat_room" 43 | 3) "testing...haha" 44 | -------------------------------------------------------------------------------- /pub_sub/unsubscribe.rst: -------------------------------------------------------------------------------- 1 | .. _unsubscribe: 2 | 3 | UNSUBSCRIBE 4 | ============= 5 | 6 | **UNSUBSCRIBE [channel [channel ...]]** 7 | 8 | 指示客户端退订给定的频道。 9 | 10 | 如果没有频道被指定,也即是,一个无参数的 ``UNSUBSCRIBE`` 调用被执行,那么客户端使用 :ref:`SUBSCRIBE` 命令订阅的所有频道都会被退订。在这种情况下,命令会返回一个信息,告知客户端所有被退订的频道。 11 | 12 | **可用版本:** 13 | >= 2.0.0 14 | 15 | **时间复杂度:** 16 | O(N) , ``N`` 是客户端已订阅的频道的数量。 17 | 18 | **返回值:** 19 | 这个命令在不同的客户端中有不同的表现。 20 | -------------------------------------------------------------------------------- /readme.rst: -------------------------------------------------------------------------------- 1 | 关于 2 | ================== 3 | 4 | 本文档是 Redis 命令参考手册的中文翻译版, 5 | 可以在 `www.RedisDoc.com `_ 在线阅读本文档。 6 | 7 | 8 | 版权声明 9 | =================== 10 | 11 | 本文档由 `huangz `_ 翻译,版权归 Redis 官方所有。 12 | -------------------------------------------------------------------------------- /redis-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/me115/redis/97747be488c7857e241d14b69ee5d3088bbe8136/redis-logo.jpg -------------------------------------------------------------------------------- /script/evalsha.rst: -------------------------------------------------------------------------------- 1 | .. _evalsha: 2 | 3 | EVALSHA 4 | ============ 5 | 6 | **EVALSHA sha1 numkeys key [key ...] arg [arg ...]** 7 | 8 | 根据给定的 sha1 校验码,对缓存在服务器中的脚本进行求值。 9 | 10 | 将脚本缓存到服务器的操作可以通过 :ref:`script_load` 命令进行。 11 | 12 | 这个命令的其他地方,比如参数的传入方式,都和 :ref:`eval` 命令一样。 13 | 14 | **可用版本:** 15 | >= 2.6.0 16 | 17 | **时间复杂度:** 18 | 根据脚本的复杂度而定。 19 | 20 | :: 21 | 22 | redis> SCRIPT LOAD "return 'hello moto'" 23 | "232fd51614574cf0867b83d384a5e898cfd24e5a" 24 | 25 | redis> EVALSHA "232fd51614574cf0867b83d384a5e898cfd24e5a" 0 26 | "hello moto" 27 | -------------------------------------------------------------------------------- /script/index.rst: -------------------------------------------------------------------------------- 1 | Script(脚本) 2 | ====================== 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | 7 | eval 8 | evalsha 9 | script_exists 10 | script_flush 11 | script_kill 12 | script_load 13 | -------------------------------------------------------------------------------- /script/script_exists.rst: -------------------------------------------------------------------------------- 1 | .. _script_exists: 2 | 3 | SCRIPT EXISTS 4 | ================= 5 | 6 | **SCRIPT EXISTS script [script ...]** 7 | 8 | 给定一个或多个脚本的 SHA1 校验和,返回一个包含 ``0`` 和 ``1`` 的列表,表示校验和所指定的脚本是否已经被保存在缓存当中。 9 | 10 | 关于使用 Redis 对 Lua 脚本进行求值的更多信息,请参见 :ref:`EVAL` 命令。 11 | 12 | **可用版本:** 13 | >= 2.6.0 14 | 15 | **时间复杂度:** 16 | O(N) , ``N`` 为给定的 SHA1 校验和的数量。 17 | 18 | **返回值:** 19 | | 一个列表,包含 ``0`` 和 ``1`` ,前者表示脚本不存在于缓存,后者表示脚本已经在缓存里面了。 20 | | 列表中的元素和给定的 SHA1 校验和保持对应关系,比如列表的第三个元素的值就表示第三个 SHA1 校验和所指定的脚本在缓存中的状态。 21 | 22 | :: 23 | 24 | redis> SCRIPT LOAD "return 'hello moto'" # 载入一个脚本 25 | "232fd51614574cf0867b83d384a5e898cfd24e5a" 26 | 27 | redis> SCRIPT EXISTS 232fd51614574cf0867b83d384a5e898cfd24e5a 28 | 1) (integer) 1 29 | 30 | redis> SCRIPT FLUSH # 清空缓存 31 | OK 32 | 33 | redis> SCRIPT EXISTS 232fd51614574cf0867b83d384a5e898cfd24e5a 34 | 1) (integer) 0 35 | -------------------------------------------------------------------------------- /script/script_flush.rst: -------------------------------------------------------------------------------- 1 | .. _script_flush: 2 | 3 | SCRIPT FLUSH 4 | ============== 5 | 6 | **SCRIPT FLUSH** 7 | 8 | 清除所有 Lua 脚本缓存。 9 | 10 | 关于使用 Redis 对 Lua 脚本进行求值的更多信息,请参见 :ref:`EVAL` 命令。 11 | 12 | **可用版本:** 13 | >= 2.6.0 14 | 15 | **复杂度:** 16 | O(N) , ``N`` 为缓存中脚本的数量。 17 | 18 | **返回值:** 19 | 总是返回 ``OK`` 20 | 21 | :: 22 | 23 | redis> SCRIPT FLUSH 24 | OK 25 | -------------------------------------------------------------------------------- /script/script_kill.rst: -------------------------------------------------------------------------------- 1 | .. _script_kill: 2 | 3 | SCRIPT KILL 4 | ============= 5 | 6 | **SCRIPT KILL** 7 | 8 | 杀死当前正在运行的 Lua 脚本,当且仅当这个脚本没有执行过任何写操作时,这个命令才生效。 9 | 10 | 这个命令主要用于终止运行时间过长的脚本,比如一个因为 BUG 而发生无限 loop 的脚本,诸如此类。 11 | 12 | `SCRIPT KILL`_ 执行之后,当前正在运行的脚本会被杀死,执行这个脚本的客户端会从 :ref:`EVAL` 命令的阻塞当中退出,并收到一个错误作为返回值。 13 | 14 | 另一方面,假如当前正在运行的脚本已经执行过写操作,那么即使执行 `SCRIPT KILL`_ ,也无法将它杀死,因为这是违反 Lua 脚本的原子性执行原则的。在这种情况下,唯一可行的办法是使用 ``SHUTDOWN NOSAVE`` 命令,通过停止整个 Redis 进程来停止脚本的运行,并防止不完整(half-written)的信息被写入数据库中。 15 | 16 | 关于使用 Redis 对 Lua 脚本进行求值的更多信息,请参见 :ref:`EVAL` 命令。 17 | 18 | **可用版本:** 19 | >= 2.6.0 20 | 21 | **时间复杂度:** 22 | O(1) 23 | 24 | **返回值:** 25 | 执行成功返回 ``OK`` ,否则返回一个错误。 26 | 27 | :: 28 | 29 | # 没有脚本在执行时 30 | 31 | redis> SCRIPT KILL 32 | (error) ERR No scripts in execution right now. 33 | 34 | # 成功杀死脚本时 35 | 36 | redis> SCRIPT KILL 37 | OK 38 | (1.30s) 39 | 40 | # 尝试杀死一个已经执行过写操作的脚本,失败 41 | 42 | redis> SCRIPT KILL 43 | (error) ERR Sorry the script already executed write commands against the dataset. You can either wait the script termination or kill the server in an hard way using the SHUTDOWN NOSAVE command. 44 | (1.69s) 45 | 46 | 以下是脚本被杀死之后,返回给执行脚本的客户端的错误: 47 | 48 | :: 49 | 50 | redis> EVAL "while true do end" 0 51 | (error) ERR Error running script (call to f_694a5fe1ddb97a4c6a1bf299d9537c7d3d0f84e7): Script killed by user with SCRIPT KILL... 52 | (5.00s) 53 | 54 | -------------------------------------------------------------------------------- /script/script_load.rst: -------------------------------------------------------------------------------- 1 | .. _script_load: 2 | 3 | SCRIPT LOAD 4 | =============== 5 | 6 | **SCRIPT LOAD script** 7 | 8 | 将脚本 ``script`` 添加到脚本缓存中,但并不立即执行这个脚本。 9 | 10 | :ref:`EVAL` 命令也会将脚本添加到脚本缓存中,但是它会立即对输入的脚本进行求值。 11 | 12 | 如果给定的脚本已经在缓存里面了,那么不做动作。 13 | 14 | 在脚本被加入到缓存之后,通过 EVALSHA 命令,可以使用脚本的 SHA1 校验和来调用这个脚本。 15 | 16 | 脚本可以在缓存中保留无限长的时间,直到执行 :ref:`script_flush` 为止。 17 | 18 | 关于使用 Redis 对 Lua 脚本进行求值的更多信息,请参见 :ref:`EVAL` 命令。 19 | 20 | **可用版本:** 21 | >= 2.6.0 22 | 23 | **时间复杂度:** 24 | O(N) , ``N`` 为脚本的长度(以字节为单位)。 25 | 26 | **返回值:** 27 | 给定 ``script`` 的 SHA1 校验和 28 | 29 | :: 30 | 31 | redis> SCRIPT LOAD "return 'hello moto'" 32 | "232fd51614574cf0867b83d384a5e898cfd24e5a" 33 | 34 | redis> EVALSHA 232fd51614574cf0867b83d384a5e898cfd24e5a 0 35 | "hello moto" 36 | -------------------------------------------------------------------------------- /server/bgrewriteaof.rst: -------------------------------------------------------------------------------- 1 | .. _bgrewriteaof: 2 | 3 | BGREWRITEAOF 4 | ============= 5 | 6 | **BGREWRITEAOF** 7 | 8 | 执行一个 `AOF文件 `_ 重写操作。重写会创建一个当前 AOF 文件的体积优化版本。 9 | 10 | 即使 `BGREWRITEAOF`_ 执行失败,也不会有任何数据丢失,因为旧的 AOF 文件在 `BGREWRITEAOF`_ 成功之前不会被修改。 11 | 12 | 重写操作只会在没有其他持久化工作在后台执行时被触发,也就是说: 13 | 14 | - 如果 Redis 的子进程正在执行快照的保存工作,那么 AOF 重写的操作会被预定(scheduled),等到保存工作完成之后再执行 AOF 重写。在这种情况下, `BGREWRITEAOF`_ 的返回值仍然是 ``OK`` ,但还会加上一条额外的信息,说明 `BGREWRITEAOF`_ 要等到保存操作完成之后才能执行。在 Redis 2.6 或以上的版本,可以使用 :ref:`INFO` 命令查看 `BGREWRITEAOF`_ 是否被预定。 15 | 16 | - 如果已经有别的 AOF 文件重写在执行,那么 `BGREWRITEAOF`_ 返回一个错误,并且这个新的 `BGREWRITEAOF`_ 请求也不会被预定到下次执行。 17 | 18 | 从 Redis 2.4 开始, AOF 重写由 Redis 自行触发, `BGREWRITEAOF`_ 仅仅用于手动触发重写操作。 19 | 20 | 请移步 `持久化文档(英文) `_ 查看更多相关细节。 21 | 22 | **可用版本:** 23 | >= 1.0.0 24 | 25 | **时间复杂度:** 26 | O(N), ``N`` 为要追加到 AOF 文件中的数据数量。 27 | 28 | **返回值:** 29 | 反馈信息。 30 | 31 | :: 32 | 33 | redis> BGREWRITEAOF 34 | Background append only file rewriting started 35 | -------------------------------------------------------------------------------- /server/bgsave.rst: -------------------------------------------------------------------------------- 1 | .. _bgsave: 2 | 3 | BGSAVE 4 | ======= 5 | 6 | 在后台异步(Asynchronously)保存当前数据库的数据到磁盘。 7 | 8 | `BGSAVE`_ 命令执行之后立即返回 ``OK`` ,然后 Redis fork 出一个新子进程,原来的 Redis 进程(父进程)继续处理客户端请求,而子进程则负责将数据保存到磁盘,然后退出。 9 | 10 | 客户端可以通过 :ref:`LASTSAVE` 命令查看相关信息,判断 `BGSAVE`_ 命令是否执行成功。 11 | 12 | 请移步 `持久化文档 `_ 查看更多相关细节。 13 | 14 | **可用版本:** 15 | >= 1.0.0 16 | 17 | **时间复杂度:** 18 | O(N), ``N`` 为要保存到数据库中的 key 的数量。 19 | 20 | **返回值:** 21 | 反馈信息。 22 | 23 | :: 24 | 25 | redis> BGSAVE 26 | Background saving started 27 | -------------------------------------------------------------------------------- /server/client_getname.rst: -------------------------------------------------------------------------------- 1 | .. _client_getname: 2 | 3 | CLIENT GETNAME 4 | =================== 5 | 6 | **CLIENT GETNAME** 7 | 8 | 返回 :ref:`client_setname` 命令为连接设置的名字。 9 | 10 | 因为新创建的连接默认是没有名字的, 11 | 对于没有名字的连接, 12 | :ref:`client_getname` 返回空白回复。 13 | 14 | **可用版本** 15 | >= 2.6.9 16 | 17 | **时间复杂度** 18 | O(1) 19 | 20 | **返回值** 21 | | 如果连接没有设置名字,那么返回空白回复; 22 | | 如果有设置名字,那么返回名字。 23 | 24 | :: 25 | 26 | # 新连接默认没有名字 27 | 28 | redis 127.0.0.1:6379> CLIENT GETNAME 29 | (nil) 30 | 31 | # 设置名字 32 | 33 | redis 127.0.0.1:6379> CLIENT SETNAME hello-world-connection 34 | OK 35 | 36 | # 返回名字 37 | 38 | redis 127.0.0.1:6379> CLIENT GETNAME 39 | "hello-world-connection" 40 | -------------------------------------------------------------------------------- /server/client_kill.rst: -------------------------------------------------------------------------------- 1 | .. _client_kill: 2 | 3 | CLIENT KILL 4 | =============== 5 | 6 | **CLIENT KILL ip:port** 7 | 8 | 关闭地址为 ``ip:port`` 的客户端。 9 | 10 | ``ip:port`` 应该和 :ref:`client_list` 命令输出的其中一行匹配。 11 | 12 | 因为 Redis 使用单线程设计,所以当 Redis 正在执行命令的时候,不会有客户端被断开连接。 13 | 14 | 如果要被断开连接的客户端正在执行命令,那么当这个命令执行之后,在发送下一个命令的时候,它就会收到一个网络错误,告知它自身的连接已被关闭。 15 | 16 | **可用版本** 17 | >= 2.4.0 18 | 19 | **时间复杂度** 20 | O(N) , N 为已连接的客户端数量。 21 | 22 | **返回值** 23 | 当指定的客户端存在,且被成功关闭时,返回 ``OK`` 。 24 | 25 | :: 26 | 27 | # 列出所有已连接客户端 28 | 29 | redis 127.0.0.1:6379> CLIENT LIST 30 | addr=127.0.0.1:43501 fd=5 age=10 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 events=r cmd=client 31 | 32 | # 杀死当前客户端的连接 33 | 34 | redis 127.0.0.1:6379> CLIENT KILL 127.0.0.1:43501 35 | OK 36 | 37 | # 之前的连接已经被关闭,CLI 客户端又重新建立了连接 38 | # 之前的端口是 43501 ,现在是 43504 39 | 40 | redis 127.0.0.1:6379> CLIENT LIST 41 | addr=127.0.0.1:43504 fd=5 age=0 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 events=r cmd=client 42 | -------------------------------------------------------------------------------- /server/client_list.rst: -------------------------------------------------------------------------------- 1 | .. _client_list: 2 | 3 | CLIENT LIST 4 | ================ 5 | 6 | **CLIENT LIST** 7 | 8 | 以人类可读的格式,返回所有连接到服务器的客户端信息和统计数据。 9 | 10 | :: 11 | 12 | redis> CLIENT LIST 13 | addr=127.0.0.1:43143 fd=6 age=183 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 events=r cmd=client 14 | addr=127.0.0.1:43163 fd=5 age=35 idle=15 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=ping 15 | addr=127.0.0.1:43167 fd=7 age=24 idle=6 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=get 16 | 17 | 18 | **可用版本** 19 | >= 2.4.0 20 | 21 | **时间复杂度** 22 | O(N) , N 为连接到服务器的客户端数量。 23 | 24 | **返回值** 25 | 命令返回多行字符串,这些字符串按以下形式被格式化: 26 | 27 | * 每个已连接客户端对应一行(以 ``LF`` 分割) 28 | * 每行字符串由一系列 ``属性=值`` 形式的域组成,每个域之间以空格分开 29 | 30 | 以下是域的含义: 31 | 32 | * ``addr`` : 客户端的地址和端口 33 | * ``fd`` : 套接字所使用的文件描述符 34 | * ``age`` : 以秒计算的已连接时长 35 | * ``idle`` : 以秒计算的空闲时长 36 | * ``flags`` : 客户端 flag (见下文) 37 | * ``db`` : 该客户端正在使用的数据库 ID 38 | * ``sub`` : 已订阅频道的数量 39 | * ``psub`` : 已订阅模式的数量 40 | * ``multi`` : 在事务中被执行的命令数量 41 | * ``qbuf`` : 查询缓冲区的长度(字节为单位, ``0`` 表示没有分配查询缓冲区) 42 | * ``qbuf-free`` : 查询缓冲区剩余空间的长度(字节为单位, ``0`` 表示没有剩余空间) 43 | * ``obl`` : 输出缓冲区的长度(字节为单位, ``0`` 表示没有分配输出缓冲区) 44 | * ``oll`` : 输出列表包含的对象数量(当输出缓冲区没有剩余空间时,命令回复会以字符串对象的形式被入队到这个队列里) 45 | * ``omem`` : 输出缓冲区和输出列表占用的内存总量 46 | * ``events`` : 文件描述符事件(见下文) 47 | * ``cmd`` : 最近一次执行的命令 48 | 49 | 客户端 flag 可以由以下部分组成: 50 | 51 | * ``O`` : 客户端是 MONITOR 模式下的附属节点(slave) 52 | * ``S`` : 客户端是一般模式下(normal)的附属节点 53 | * ``M`` : 客户端是主节点(master) 54 | * ``x`` : 客户端正在执行事务 55 | * ``b`` : 客户端正在等待阻塞事件 56 | * ``i`` : 客户端正在等待 VM I/O 操作(已废弃) 57 | * ``d`` : 一个受监视(watched)的键已被修改, ``EXEC`` 命令将失败 58 | * ``c`` : 在将回复完整地写出之后,关闭链接 59 | * ``u`` : 客户端未被阻塞(unblocked) 60 | * ``A`` : 尽可能快地关闭连接 61 | * ``N`` : 未设置任何 flag 62 | 63 | 文件描述符事件可以是: 64 | 65 | * ``r`` : 客户端套接字(在事件 loop 中)是可读的(readable) 66 | * ``w`` : 客户端套接字(在事件 loop 中)是可写的(writeable) 67 | 68 | .. note:: 69 | 70 | 为了 debug 的需要,经常会对域进行添加和删除,一个安全的 Redis 客户端应该可以对 ``CLIENT LIST`` 的输出进行相应的处理(parse),比如忽略不存在的域,跳过未知域,诸如此类。 71 | -------------------------------------------------------------------------------- /server/client_setname.rst: -------------------------------------------------------------------------------- 1 | .. _client_setname: 2 | 3 | CLIENT SETNAME 4 | ================ 5 | 6 | **CLIENT SETNAME connection-name** 7 | 8 | 为当前连接分配一个名字。 9 | 10 | 这个名字会显示在 :ref:`client_list` 命令的结果中, 11 | 用于识别当前正在与服务器进行连接的客户端。 12 | 13 | 举个例子, 14 | 在使用 Redis 构建队列(queue)时, 15 | 可以根据连接负责的任务(role), 16 | 为信息生产者(producer)和信息消费者(consumer)分别设置不同的名字。 17 | 18 | 名字使用 Redis 的字符串类型来保存, 19 | 最大可以占用 512 MB 。 20 | 另外, 21 | 为了避免和 :ref:`client_list` 命令的输出格式发生冲突, 22 | 名字里不允许使用空格。 23 | 24 | 要移除一个连接的名字, 25 | 可以将连接的名字设为空字符串 ``""`` 。 26 | 27 | 使用 :ref:`client_getname` 命令可以取出连接的名字。 28 | 29 | 新创建的连接默认是没有名字的。 30 | 31 | .. tip:: 32 | 33 | 在 Redis 应用程序发生连接泄漏时,为连接设置名字是一种很好的 debug 手段。 34 | 35 | **可用版本** 36 | >= 2.6.9 37 | 38 | **时间复杂度** 39 | O(1) 40 | 41 | **返回值** 42 | 设置成功时返回 ``OK`` 。 43 | 44 | :: 45 | 46 | # 新连接默认没有名字 47 | 48 | redis 127.0.0.1:6379> CLIENT GETNAME 49 | (nil) 50 | 51 | # 设置名字 52 | 53 | redis 127.0.0.1:6379> CLIENT SETNAME hello-world-connection 54 | OK 55 | 56 | # 返回名字 57 | 58 | redis 127.0.0.1:6379> CLIENT GETNAME 59 | "hello-world-connection" 60 | 61 | # 在客户端列表中查看 62 | 63 | redis 127.0.0.1:6379> CLIENT LIST 64 | addr=127.0.0.1:36851 65 | fd=5 66 | name=hello-world-connection # <- 名字 67 | age=51 68 | ... 69 | 70 | # 清除名字 71 | 72 | redis 127.0.0.1:6379> CLIENT SETNAME # 只用空格是不行的! 73 | (error) ERR Syntax error, try CLIENT (LIST | KILL ip:port) 74 | 75 | redis 127.0.0.1:6379> CLIENT SETNAME "" # 必须双引号显示包围 76 | OK 77 | 78 | redis 127.0.0.1:6379> CLIENT GETNAME # 清除完毕 79 | (nil) 80 | -------------------------------------------------------------------------------- /server/config_get.rst: -------------------------------------------------------------------------------- 1 | .. _config_get: 2 | 3 | CONFIG GET 4 | ============= 5 | 6 | **CONFIG GET parameter** 7 | 8 | `CONFIG GET`_ 命令用于取得运行中的 Redis 服务器的配置参数(configuration parameters),在 Redis 2.4 版本中, 有部分参数没有办法用 ``CONFIG GET`` 访问,但是在最新的 Redis 2.6 版本中,所有配置参数都已经可以用 ``CONFIG GET`` 访问了。 9 | 10 | `CONFIG GET`_ 接受单个参数 ``parameter`` 作为搜索关键字,查找所有匹配的配置参数,其中参数和值以“键-值对”(key-value pairs)的方式排列。 11 | 12 | 比如执行 ``CONFIG GET s*`` 命令,服务器就会返回所有以 ``s`` 开头的配置参数及参数的值: 13 | 14 | :: 15 | 16 | redis> CONFIG GET s* 17 | 1) "save" # 参数名:save 18 | 2) "900 1 300 10 60 10000" # save 参数的值 19 | 3) "slave-serve-stale-data" # 参数名: slave-serve-stale-data 20 | 4) "yes" # slave-serve-stale-data 参数的值 21 | 5) "set-max-intset-entries" # ... 22 | 6) "512" 23 | 7) "slowlog-log-slower-than" 24 | 8) "1000" 25 | 9) "slowlog-max-len" 26 | 10) "1000" 27 | 28 | 如果你只是寻找特定的某个参数的话,你当然也可以直接指定参数的名字: 29 | 30 | :: 31 | 32 | redis> CONFIG GET slowlog-max-len 33 | 1) "slowlog-max-len" 34 | 2) "1000" 35 | 36 | 使用命令 ``CONFIG GET *`` ,可以列出 ``CONFIG GET`` 命令支持的所有参数: 37 | 38 | :: 39 | 40 | redis> CONFIG GET * 41 | 1) "dir" 42 | 2) "/var/lib/redis" 43 | 3) "dbfilename" 44 | 4) "dump.rdb" 45 | 5) "requirepass" 46 | 6) (nil) 47 | 7) "masterauth" 48 | 8) (nil) 49 | 9) "maxmemory" 50 | 10) "0" 51 | 11) "maxmemory-policy" 52 | 12) "volatile-lru" 53 | 13) "maxmemory-samples" 54 | 14) "3" 55 | 15) "timeout" 56 | 16) "0" 57 | 17) "appendonly" 58 | 18) "no" 59 | # ... 60 | 49) "loglevel" 61 | 50) "verbose" 62 | 63 | 64 | 所有被 ``CONFIG SET`` 所支持的配置参数都可以在配置文件 redis.conf 中找到,不过 ``CONFIG GET`` 和 ``CONFIG SET`` 使用的格式和 redis.conf 文件所使用的格式有以下两点不同: 65 | 66 | - | ``10kb`` 、 ``2gb`` 这些在配置文件中所使用的储存单位缩写,不可以用在 ``CONFIG`` 命令中, ``CONFIG SET`` 的值只能通过数字值显式地设定。 67 | | 68 | | 像 ``CONFIG SET xxx 1k`` 这样的命令是错误的,正确的格式是 ``CONFIG SET xxx 1000`` 。 69 | 70 | - | ``save`` 选项在 redis.conf 中是用多行文字储存的,但在 ``CONFIG GET`` 命令中,它只打印一行文字。 71 | | 72 | | 以下是 ``save`` 选项在 redis.conf 文件中的表示: 73 | | 74 | | ``save 900 1`` 75 | | ``save 300 10`` 76 | | ``save 60 10000`` 77 | | 78 | | 但是 ``CONFIG GET`` 命令的输出只有一行: 79 | | 80 | | ``redis> CONFIG GET save`` 81 | | ``1) "save"`` 82 | | ``2) "900 1 300 10 60 10000"`` 83 | | 84 | | 上面 ``save`` 参数的三个值表示:在 900 秒内最少有 1 个 key 被改动,或者 300 秒内最少有 10 个 key 被改动,又或者 60 秒内最少有 1000 个 key 被改动,以上三个条件随便满足一个,就触发一次保存操作。 85 | 86 | **可用版本:** 87 | >= 2.0.0 88 | 89 | **时间复杂度:** 90 | 不明确 91 | 92 | **返回值:** 93 | 给定配置参数的值。 94 | -------------------------------------------------------------------------------- /server/config_resetstat.rst: -------------------------------------------------------------------------------- 1 | .. _config_resetstat: 2 | 3 | CONFIG RESETSTAT 4 | ================= 5 | 6 | **CONFIG RESETSTAT** 7 | 8 | 重置 :ref:`INFO` 命令中的某些统计数据,包括: 9 | 10 | - Keyspace hits (键空间命中次数) 11 | - Keyspace misses (键空间不命中次数) 12 | - Number of commands processed (执行命令的次数) 13 | - Number of connections received (连接服务器的次数) 14 | - Number of expired keys (过期key的数量) 15 | - Number of rejected connections (被拒绝的连接数量) 16 | - Latest fork(2) time(最后执行 fork(2) 的时间) 17 | - The ``aof_delayed_fsync`` counter(``aof_delayed_fsync`` 计数器的值) 18 | 19 | **可用版本:** 20 | >= 2.0.0 21 | 22 | **时间复杂度:** 23 | O(1) 24 | 25 | **返回值:** 26 | 总是返回 ``OK`` 。 27 | 28 | :: 29 | 30 | # 重置前 31 | 32 | redis 127.0.0.1:6379> INFO 33 | # Server 34 | redis_version:2.5.3 35 | redis_git_sha1:d0407c2d 36 | redis_git_dirty:0 37 | arch_bits:32 38 | multiplexing_api:epoll 39 | gcc_version:4.6.3 40 | process_id:11095 41 | run_id:ef1f6b6c7392e52d6001eaf777acbe547d1192e2 42 | tcp_port:6379 43 | uptime_in_seconds:6 44 | uptime_in_days:0 45 | lru_clock:1205426 46 | 47 | # Clients 48 | connected_clients:1 49 | client_longest_output_list:0 50 | client_biggest_input_buf:0 51 | blocked_clients:0 52 | 53 | # Memory 54 | used_memory:331076 55 | used_memory_human:323.32K 56 | used_memory_rss:1568768 57 | used_memory_peak:293424 58 | used_memory_peak_human:286.55K 59 | used_memory_lua:16384 60 | mem_fragmentation_ratio:4.74 61 | mem_allocator:jemalloc-2.2.5 62 | 63 | # Persistence 64 | loading:0 65 | aof_enabled:0 66 | changes_since_last_save:0 67 | bgsave_in_progress:0 68 | last_save_time:1333260015 69 | last_bgsave_status:ok 70 | bgrewriteaof_in_progress:0 71 | 72 | # Stats 73 | total_connections_received:1 74 | total_commands_processed:0 75 | instantaneous_ops_per_sec:0 76 | rejected_connections:0 77 | expired_keys:0 78 | evicted_keys:0 79 | keyspace_hits:0 80 | keyspace_misses:0 81 | pubsub_channels:0 82 | pubsub_patterns:0 83 | latest_fork_usec:0 84 | 85 | # Replication 86 | role:master 87 | connected_slaves:0 88 | 89 | # CPU 90 | used_cpu_sys:0.01 91 | used_cpu_user:0.00 92 | used_cpu_sys_children:0.00 93 | used_cpu_user_children:0.00 94 | 95 | # Keyspace 96 | db0:keys=20,expires=0 97 | 98 | 99 | # 重置 100 | 101 | redis 127.0.0.1:6379> CONFIG RESETSTAT 102 | OK 103 | 104 | 105 | # 重置后 106 | 107 | redis 127.0.0.1:6379> INFO 108 | # Server 109 | redis_version:2.5.3 110 | redis_git_sha1:d0407c2d 111 | redis_git_dirty:0 112 | arch_bits:32 113 | multiplexing_api:epoll 114 | gcc_version:4.6.3 115 | process_id:11095 116 | run_id:ef1f6b6c7392e52d6001eaf777acbe547d1192e2 117 | tcp_port:6379 118 | uptime_in_seconds:134 119 | uptime_in_days:0 120 | lru_clock:1205438 121 | 122 | # Clients 123 | connected_clients:1 124 | client_longest_output_list:0 125 | client_biggest_input_buf:0 126 | blocked_clients:0 127 | 128 | # Memory 129 | used_memory:331076 130 | used_memory_human:323.32K 131 | used_memory_rss:1568768 132 | used_memory_peak:330280 133 | used_memory_peak_human:322.54K 134 | used_memory_lua:16384 135 | mem_fragmentation_ratio:4.74 136 | mem_allocator:jemalloc-2.2.5 137 | 138 | # Persistence 139 | loading:0 140 | aof_enabled:0 141 | changes_since_last_save:0 142 | bgsave_in_progress:0 143 | last_save_time:1333260015 144 | last_bgsave_status:ok 145 | bgrewriteaof_in_progress:0 146 | 147 | # Stats 148 | total_connections_received:0 149 | total_commands_processed:1 150 | instantaneous_ops_per_sec:0 151 | rejected_connections:0 152 | expired_keys:0 153 | evicted_keys:0 154 | keyspace_hits:0 155 | keyspace_misses:0 156 | pubsub_channels:0 157 | pubsub_patterns:0 158 | latest_fork_usec:0 159 | 160 | # Replication 161 | role:master 162 | connected_slaves:0 163 | 164 | # CPU 165 | used_cpu_sys:0.05 166 | used_cpu_user:0.02 167 | used_cpu_sys_children:0.00 168 | used_cpu_user_children:0.00 169 | 170 | # Keyspace 171 | db0:keys=20,expires=0 172 | -------------------------------------------------------------------------------- /server/config_rewrite.rst: -------------------------------------------------------------------------------- 1 | .. _config_rewrite: 2 | 3 | CONFIG REWRITE 4 | =================== 5 | 6 | **CONFIG REWRITE** 7 | 8 | :ref:`CONFIG_REWRITE` 命令对启动 Redis 服务器时所指定的 ``redis.conf`` 文件进行改写: 9 | 因为 :ref:`CONFIG_SET` 命令可以对服务器的当前配置进行修改, 10 | 而修改后的配置可能和 ``redis.conf`` 文件中所描述的配置不一样, 11 | :ref:`CONFIG_REWRITE` 的作用就是通过尽可能少的修改, 12 | 将服务器当前所使用的配置记录到 ``redis.conf`` 文件中。 13 | 14 | 重写会以非常保守的方式进行: 15 | 16 | - 原有 ``redis.conf`` 文件的整体结构和注释会被尽可能地保留。 17 | 18 | - 如果一个选项已经存在于原有 ``redis.conf`` 文件中 , 19 | 那么对该选项的重写会在选项原本所在的位置(行号)上进行。 20 | 21 | - 如果一个选项不存在于原有 ``redis.conf`` 文件中, 22 | 并且该选项被设置为默认值, 23 | 那么重写程序不会将这个选项添加到重写后的 ``redis.conf`` 文件中。 24 | 25 | - 如果一个选项不存在于原有 ``redis.conf`` 文件中, 26 | 并且该选项被设置为非默认值, 27 | 那么这个选项将被添加到重写后的 ``redis.conf`` 文件的末尾。 28 | 29 | - 未使用的行会被留白。 30 | 比如说, 31 | 如果你在原有 ``redis.conf`` 文件上设置了数个关于 ``save`` 选项的参数, 32 | 但现在你将这些 ``save`` 参数的一个或全部都关闭了, 33 | 那么这些不再使用的参数原本所在的行就会变成空白的。 34 | 35 | 即使启动服务器时所指定的 ``redis.conf`` 文件已经不再存在, 36 | :ref:`CONFIG_REWRITE` 命令也可以重新构建并生成出一个新的 ``redis.conf`` 文件。 37 | 38 | 另一方面, 39 | 如果启动服务器时没有载入 ``redis.conf`` 文件, 40 | 那么执行 :ref:`CONFIG_REWRITE` 命令将引发一个错误。 41 | 42 | 43 | 原子性重写 44 | ------------------------ 45 | 46 | 对 ``redis.conf`` 文件的重写是原子性的, 47 | 并且是一致的: 48 | 如果重写出错或重写期间服务器崩溃, 49 | 那么重写失败, 50 | 原有 ``redis.conf`` 文件不会被修改。 51 | 如果重写成功, 52 | 那么 ``redis.conf`` 文件为重写后的新文件。 53 | 54 | 55 | 可用版本 56 | ----------------------- 57 | 58 | >= 2.8.0 59 | 60 | 61 | 返回值 62 | ---------------------- 63 | 64 | 一个状态值:如果配置重写成功则返回 ``OK`` ,失败则返回一个错误。 65 | 66 | 67 | 测试 68 | ---------------------- 69 | 70 | 以下是执行 :ref:`CONFIG_REWRITE` 前, 71 | 被载入到 Redis 服务器的 ``redis.conf`` 文件中关于 ``appendonly`` 选项的设置: 72 | 73 | :: 74 | 75 | # ... 其他选项 76 | 77 | appendonly no 78 | 79 | # ... 其他选项 80 | 81 | 在执行以下命令之后: 82 | 83 | :: 84 | 85 | 127.0.0.1:6379> CONFIG GET appendonly # appendonly 处于关闭状态 86 | 1) "appendonly" 87 | 2) "no" 88 | 89 | 127.0.0.1:6379> CONFIG SET appendonly yes # 打开 appendonly 90 | OK 91 | 92 | 127.0.0.1:6379> CONFIG GET appendonly 93 | 1) "appendonly" 94 | 2) "yes" 95 | 96 | 127.0.0.1:6379> CONFIG REWRITE # 将 appendonly 的修改写入到 redis.conf 中 97 | OK 98 | 99 | 重写后的 ``redis.conf`` 文件中的 ``appendonly`` 选项将被改写: 100 | 101 | :: 102 | 103 | # ... 其他选项 104 | 105 | appendonly yes 106 | 107 | # ... 其他选项 108 | -------------------------------------------------------------------------------- /server/config_set.rst: -------------------------------------------------------------------------------- 1 | .. _config_set: 2 | 3 | CONFIG SET 4 | ============ 5 | 6 | **CONFIG SET parameter value** 7 | 8 | `CONFIG SET`_ 命令可以动态地调整 Redis 服务器的配置(configuration)而无须重启。 9 | 10 | 你可以使用它修改配置参数,或者改变 Redis 的持久化(Persistence)方式。 11 | 12 | `CONFIG SET`_ 可以修改的配置参数可以使用命令 ``CONFIG GET *`` 来列出,所有被 `CONFIG SET`_ 修改的配置参数都会立即生效。 13 | 14 | 关于 `CONFIG SET`_ 命令的更多消息,请参见命令 :ref:`config_get` 的说明。 15 | 16 | 关于如何使用 `CONFIG SET`_ 命令修改 Redis 持久化方式,请参见 `Redis Persistence `_ 。 17 | 18 | **可用版本:** 19 | >= 2.0.0 20 | 21 | **时间复杂度:** 22 | 不明确 23 | 24 | **返回值:** 25 | 当设置成功时返回 ``OK`` ,否则返回一个错误。 26 | 27 | :: 28 | 29 | redis> CONFIG GET slowlog-max-len 30 | 1) "slowlog-max-len" 31 | 2) "1024" 32 | 33 | redis> CONFIG SET slowlog-max-len 10086 34 | OK 35 | 36 | redis> CONFIG GET slowlog-max-len 37 | 1) "slowlog-max-len" 38 | 2) "10086" 39 | 40 | 41 | -------------------------------------------------------------------------------- /server/dbsize.rst: -------------------------------------------------------------------------------- 1 | .. _dbsize: 2 | 3 | DBSIZE 4 | ======= 5 | 6 | **DBSIZE** 7 | 8 | 返回当前数据库的 key 的数量。 9 | 10 | **可用版本:** 11 | >= 1.0.0 12 | 13 | **时间复杂度:** 14 | O(1) 15 | 16 | **返回值:** 17 | 当前数据库的 key 的数量。 18 | 19 | :: 20 | 21 | redis> DBSIZE 22 | (integer) 5 23 | 24 | redis> SET new_key "hello_moto" # 增加一个 key 试试 25 | OK 26 | 27 | redis> DBSIZE 28 | (integer) 6 29 | -------------------------------------------------------------------------------- /server/debug_object.rst: -------------------------------------------------------------------------------- 1 | .. _debug_object: 2 | 3 | DEBUG OBJECT 4 | =============== 5 | 6 | **DEBUG OBJECT key** 7 | 8 | `DEBUG OBJECT`_ 是一个调试命令,它不应被客户端所使用。 9 | 10 | 查看 :ref:`OBJECT` 命令获取更多信息。 11 | 12 | **可用版本:** 13 | >= 1.0.0 14 | 15 | **时间复杂度:** 16 | O(1) 17 | 18 | **返回值:** 19 | | 当 ``key`` 存在时,返回有关信息。 20 | | 当 ``key`` 不存在时,返回一个错误。 21 | 22 | :: 23 | 24 | redis> DEBUG OBJECT my_pc 25 | Value at:0xb6838d20 refcount:1 encoding:raw serializedlength:9 lru:283790 lru_seconds_idle:150 26 | 27 | redis> DEBUG OBJECT your_mac 28 | (error) ERR no such key 29 | 30 | 31 | -------------------------------------------------------------------------------- /server/debug_segfault.rst: -------------------------------------------------------------------------------- 1 | .. _debug_segfault: 2 | 3 | DEBUG SEGFAULT 4 | =============== 5 | 6 | **DEBUG SEGFAULT** 7 | 8 | 执行一个不合法的内存访问从而让 Redis 崩溃,仅在开发时用于 BUG 模拟。 9 | 10 | **可用版本:** 11 | >= 1.0.0 12 | 13 | **时间复杂度:** 14 | 不明确 15 | 16 | **返回值:** 17 | 无 18 | 19 | :: 20 | 21 | redis> DEBUG SEGFAULT 22 | Could not connect to Redis at: Connection refused 23 | 24 | not connected> 25 | 26 | 27 | -------------------------------------------------------------------------------- /server/flushall.rst: -------------------------------------------------------------------------------- 1 | .. _flushall: 2 | 3 | FLUSHALL 4 | ========= 5 | 6 | **FLUSHALL** 7 | 8 | 清空整个 Redis 服务器的数据(删除所有数据库的所有 key )。 9 | 10 | 此命令从不失败。 11 | 12 | **可用版本:** 13 | >= 1.0.0 14 | 15 | **时间复杂度:** 16 | 尚未明确 17 | 18 | **返回值:** 19 | 总是返回 ``OK`` 。 20 | 21 | :: 22 | 23 | redis> DBSIZE # 0 号数据库的 key 数量 24 | (integer) 9 25 | 26 | redis> SELECT 1 # 切换到 1 号数据库 27 | OK 28 | 29 | redis[1]> DBSIZE # 1 号数据库的 key 数量 30 | (integer) 6 31 | 32 | redis[1]> flushall # 清空所有数据库的所有 key 33 | OK 34 | 35 | redis[1]> DBSIZE # 不但 1 号数据库被清空了 36 | (integer) 0 37 | 38 | redis[1]> SELECT 0 # 0 号数据库(以及其他所有数据库)也一样 39 | OK 40 | 41 | redis> DBSIZE 42 | (integer) 0 43 | -------------------------------------------------------------------------------- /server/flushdb.rst: -------------------------------------------------------------------------------- 1 | .. _flushdb: 2 | 3 | FLUSHDB 4 | ========= 5 | 6 | **FLUSHDB** 7 | 8 | 清空当前数据库中的所有 key。 9 | 10 | 此命令从不失败。 11 | 12 | **可用版本:** 13 | >= 1.0.0 14 | 15 | **时间复杂度:** 16 | O(1) 17 | 18 | **返回值:** 19 | 总是返回 ``OK`` 。 20 | 21 | :: 22 | 23 | redis> DBSIZE # 清空前的 key 数量 24 | (integer) 4 25 | 26 | redis> FLUSHDB 27 | OK 28 | 29 | redis> DBSIZE # 清空后的 key 数量 30 | (integer) 0 31 | -------------------------------------------------------------------------------- /server/index.rst: -------------------------------------------------------------------------------- 1 | Server(服务器) 2 | =================== 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | 7 | bgrewriteaof 8 | bgsave 9 | client_getname 10 | client_kill 11 | client_list 12 | client_setname 13 | config_get 14 | config_resetstat 15 | config_rewrite 16 | config_set 17 | dbsize 18 | debug_object 19 | debug_segfault 20 | flushall 21 | flushdb 22 | info 23 | lastsave 24 | monitor 25 | psync 26 | save 27 | shutdown 28 | slaveof 29 | slowlog 30 | sync 31 | time 32 | 33 | -------------------------------------------------------------------------------- /server/info.rst: -------------------------------------------------------------------------------- 1 | .. _info: 2 | 3 | INFO 4 | ====== 5 | 6 | **INFO [section]** 7 | 8 | 以一种易于解释(parse)且易于阅读的格式,返回关于 Redis 服务器的各种信息和统计数值。 9 | 10 | 通过给定可选的参数 ``section`` ,可以让命令只返回某一部分的信息: 11 | 12 | - ``server`` : 一般 Redis 服务器信息,包含以下域: 13 | 14 | - ``redis_version`` : Redis 服务器版本 15 | - ``redis_git_sha1`` : Git SHA1 16 | - ``redis_git_dirty`` : Git dirty flag 17 | - ``os`` : Redis 服务器的宿主操作系统 18 | - ``arch_bits`` : 架构(32 或 64 位) 19 | - ``multiplexing_api`` : Redis 所使用的事件处理机制 20 | - ``gcc_version`` : 编译 Redis 时所使用的 GCC 版本 21 | - ``process_id`` : 服务器进程的 PID 22 | - ``run_id`` : Redis 服务器的随机标识符(用于 Sentinel 和集群) 23 | - ``tcp_port`` : TCP/IP 监听端口 24 | - ``uptime_in_seconds`` : 自 Redis 服务器启动以来,经过的秒数 25 | - ``uptime_in_days`` : 自 Redis 服务器启动以来,经过的天数 26 | - ``lru_clock`` : 以分钟为单位进行自增的时钟,用于 LRU 管理 27 | 28 | - ``clients`` : 已连接客户端信息,包含以下域: 29 | 30 | - ``connected_clients`` : 已连接客户端的数量(不包括通过从属服务器连接的客户端) 31 | - ``client_longest_output_list`` : 当前连接的客户端当中,最长的输出列表 32 | - ``client_longest_input_buf`` : 当前连接的客户端当中,最大输入缓存 33 | - ``blocked_clients`` : 正在等待阻塞命令(BLPOP、BRPOP、BRPOPLPUSH)的客户端的数量 34 | 35 | - ``memory`` : 内存信息,包含以下域: 36 | 37 | - ``used_memory`` : 由 Redis 分配器分配的内存总量,以字节(byte)为单位 38 | - ``used_memory_human`` : 以人类可读的格式返回 Redis 分配的内存总量 39 | - ``used_memory_rss`` : 从操作系统的角度,返回 Redis 已分配的内存总量(俗称常驻集大小)。这个值和 ``top`` 、 ``ps`` 等命令的输出一致。 40 | - ``used_memory_peak`` : Redis 的内存消耗峰值(以字节为单位) 41 | - ``used_memory_peak_human`` : 以人类可读的格式返回 Redis 的内存消耗峰值 42 | - ``used_memory_lua`` : Lua 引擎所使用的内存大小(以字节为单位) 43 | - ``mem_fragmentation_ratio`` : ``used_memory_rss`` 和 ``used_memory`` 之间的比率 44 | - ``mem_allocator`` : 在编译时指定的, Redis 所使用的内存分配器。可以是 libc 、 jemalloc 或者 tcmalloc 。 45 | 46 | | 在理想情况下, ``used_memory_rss`` 的值应该只比 ``used_memory`` 稍微高一点儿。 47 | | 当 ``rss > used`` ,且两者的值相差较大时,表示存在(内部或外部的)内存碎片。 48 | | 内存碎片的比率可以通过 ``mem_fragmentation_ratio`` 的值看出。 49 | | 当 ``used > rss`` 时,表示 Redis 的部分内存被操作系统换出到交换空间了,在这种情况下,操作可能会产生明显的延迟。 50 | 51 | Because Redis does not have control over how its allocations are mapped to memory pages, high ``used_memory_rss`` is often the result of a spike in memory usage. 52 | 53 | | 当 Redis 释放内存时,分配器可能会,也可能不会,将内存返还给操作系统。 54 | | 如果 Redis 释放了内存,却没有将内存返还给操作系统,那么 ``used_memory`` 的值可能和操作系统显示的 Redis 内存占用并不一致。 55 | | 查看 ``used_memory_peak`` 的值可以验证这种情况是否发生。 56 | 57 | 58 | - ``persistence`` : ``RDB`` 和 ``AOF`` 的相关信息 59 | - ``stats`` : 一般统计信息 60 | - ``replication`` : 主/从复制信息 61 | - ``cpu`` : CPU 计算量统计信息 62 | - ``commandstats`` : Redis 命令统计信息 63 | - ``cluster`` : Redis 集群信息 64 | - ``keyspace`` : 数据库相关的统计信息 65 | 66 | 除上面给出的这些值以外,参数还可以是下面这两个: 67 | 68 | - ``all`` : 返回所有信息 69 | - ``default`` : 返回默认选择的信息 70 | 71 | 当不带参数直接调用 `INFO`_ 命令时,使用 ``default`` 作为默认参数。 72 | 73 | .. note:: 74 | 75 | 不同版本的 Redis 可能对返回的一些域进行了增加或删减。 76 | 77 | 因此,一个健壮的客户端程序在对 :ref:`info` 命令的输出进行分析时,应该能够跳过不认识的域,并且妥善地处理丢失不见的域。 78 | 79 | **可用版本:** 80 | >= 1.0.0 81 | 82 | **时间复杂度:** 83 | O(1) 84 | 85 | **返回值:** 86 | 具体请参见下面的测试代码。 87 | 88 | :: 89 | 90 | redis> INFO 91 | # Server 92 | redis_version:2.5.9 93 | redis_git_sha1:473f3090 94 | redis_git_dirty:0 95 | os:Linux 3.3.7-1-ARCH i686 96 | arch_bits:32 97 | multiplexing_api:epoll 98 | gcc_version:4.7.0 99 | process_id:8104 100 | run_id:bc9e20c6f0aac67d0d396ab950940ae4d1479ad1 101 | tcp_port:6379 102 | uptime_in_seconds:7 103 | uptime_in_days:0 104 | lru_clock:1680564 105 | 106 | # Clients 107 | connected_clients:1 108 | client_longest_output_list:0 109 | client_biggest_input_buf:0 110 | blocked_clients:0 111 | 112 | # Memory 113 | used_memory:439304 114 | used_memory_human:429.01K 115 | used_memory_rss:13897728 116 | used_memory_peak:401776 117 | used_memory_peak_human:392.36K 118 | used_memory_lua:20480 119 | mem_fragmentation_ratio:31.64 120 | mem_allocator:jemalloc-3.0.0 121 | 122 | # Persistence 123 | loading:0 124 | rdb_changes_since_last_save:0 125 | rdb_bgsave_in_progress:0 126 | rdb_last_save_time:1338011402 127 | rdb_last_bgsave_status:ok 128 | rdb_last_bgsave_time_sec:-1 129 | rdb_current_bgsave_time_sec:-1 130 | aof_enabled:0 131 | aof_rewrite_in_progress:0 132 | aof_rewrite_scheduled:0 133 | aof_last_rewrite_time_sec:-1 134 | aof_current_rewrite_time_sec:-1 135 | 136 | # Stats 137 | total_connections_received:1 138 | total_commands_processed:0 139 | instantaneous_ops_per_sec:0 140 | rejected_connections:0 141 | expired_keys:0 142 | evicted_keys:0 143 | keyspace_hits:0 144 | keyspace_misses:0 145 | pubsub_channels:0 146 | pubsub_patterns:0 147 | latest_fork_usec:0 148 | 149 | # Replication 150 | role:master 151 | connected_slaves:0 152 | 153 | # CPU 154 | used_cpu_sys:0.03 155 | used_cpu_user:0.01 156 | used_cpu_sys_children:0.00 157 | used_cpu_user_children:0.00 158 | 159 | # Keyspace 160 | -------------------------------------------------------------------------------- /server/lastsave.rst: -------------------------------------------------------------------------------- 1 | .. _lastsave: 2 | 3 | LASTSAVE 4 | ========= 5 | 6 | **LASTSAVE** 7 | 8 | 返回最近一次 Redis 成功将数据保存到磁盘上的时间,以 UNIX 时间戳格式表示。 9 | 10 | **可用版本:** 11 | >= 1.0.0 12 | 13 | **时间复杂度:** 14 | O(1) 15 | 16 | **返回值:** 17 | 一个 UNIX 时间戳。 18 | 19 | :: 20 | 21 | redis> LASTSAVE 22 | (integer) 1324043588 23 | 24 | 25 | -------------------------------------------------------------------------------- /server/monitor.rst: -------------------------------------------------------------------------------- 1 | .. _monitor: 2 | 3 | MONITOR 4 | ======== 5 | 6 | **MONITOR** 7 | 8 | 实时打印出 Redis 服务器接收到的命令,调试用。 9 | 10 | **可用版本:** 11 | >= 1.0.0 12 | 13 | **时间复杂度:** 14 | 不明确 15 | 16 | **返回值:** 17 | 总是返回 ``OK`` 。 18 | 19 | :: 20 | 21 | 127.0.0.1:6379> MONITOR 22 | OK 23 | # 以第一个打印值为例 24 | # 1378822099.421623 是时间戳 25 | # [0 127.0.0.1:56604] 中的 0 是数据库号码, 127... 是 IP 地址和端口 26 | # "PING" 是被执行的命令 27 | 1378822099.421623 [0 127.0.0.1:56604] "PING" 28 | 1378822105.089572 [0 127.0.0.1:56604] "SET" "msg" "hello world" 29 | 1378822109.036925 [0 127.0.0.1:56604] "SET" "number" "123" 30 | 1378822140.649496 [0 127.0.0.1:56604] "SADD" "fruits" "Apple" "Banana" "Cherry" 31 | 1378822154.117160 [0 127.0.0.1:56604] "EXPIRE" "msg" "10086" 32 | 1378822257.329412 [0 127.0.0.1:56604] "KEYS" "*" 33 | 1378822258.690131 [0 127.0.0.1:56604] "DBSIZE" 34 | -------------------------------------------------------------------------------- /server/psync.rst: -------------------------------------------------------------------------------- 1 | .. _psync: 2 | 3 | PSYNC 4 | ======= 5 | 6 | **PSYNC ** 7 | 8 | 用于复制功能(replication)的内部命令。 9 | 10 | 更多信息请参考 :ref:`replication_topic` 文档。 11 | 12 | **可用版本:** 13 | >= 2.8.0 14 | 15 | **时间复杂度:** 16 | 不明确 17 | 18 | **返回值:** 19 | 不明确 20 | 21 | :: 22 | 23 | 127.0.0.1:6379> PSYNC ? -1 24 | "REDIS0006\xfe\x00\x00\x02kk\x02vv\x00\x03msg\x05hello\xff\xc3\x96P\x12h\bK\xef" 25 | -------------------------------------------------------------------------------- /server/save.rst: -------------------------------------------------------------------------------- 1 | .. _save: 2 | 3 | SAVE 4 | ===== 5 | 6 | **SAVE** 7 | 8 | `SAVE`_ 命令执行一个同步保存操作,将当前 Redis 实例的所有数据快照(snapshot)以 RDB 文件的形式保存到硬盘。 9 | 10 | 一般来说,在生产环境很少执行 `SAVE`_ 操作,因为它会阻塞所有客户端,保存数据库的任务通常由 :ref:`BGSAVE` 命令异步地执行。然而,如果负责保存数据的后台子进程不幸出现问题时, `SAVE`_ 可以作为保存数据的最后手段来使用。 11 | 12 | 请参考文档: `Redis 的持久化运作方式(英文) `_ 以获取更多消息。 13 | 14 | **可用版本:** 15 | >= 1.0.0 16 | 17 | **时间复杂度:** 18 | O(N), ``N`` 为要保存到数据库中的 key 的数量。 19 | 20 | **返回值:** 21 | 保存成功时返回 ``OK`` 。 22 | 23 | :: 24 | 25 | redis> SAVE 26 | OK 27 | -------------------------------------------------------------------------------- /server/shutdown.rst: -------------------------------------------------------------------------------- 1 | .. _shutdown: 2 | 3 | SHUTDOWN 4 | ========= 5 | 6 | **SHUTDOWN** 7 | 8 | `SHUTDOWN`_ 命令执行以下操作: 9 | 10 | - 停止所有客户端 11 | - 如果有至少一个保存点在等待,执行 :ref:`SAVE` 命令 12 | - 如果 AOF 选项被打开,更新 AOF 文件 13 | - 关闭 redis 服务器(server) 14 | 15 | 如果持久化被打开的话, `SHUTDOWN`_ 命令会保证服务器正常关闭而不丢失任何数据。 16 | 17 | 另一方面,假如只是单纯地执行 :ref:`SAVE` 命令,然后再执行 :ref:`QUIT` 命令,则没有这一保证 —— 因为在执行 :ref:`SAVE` 之后、执行 :ref:`QUIT` 之前的这段时间中间,其他客户端可能正在和服务器进行通讯,这时如果执行 :ref:`QUIT` 就会造成数据丢失。 18 | 19 | **SAVE 和 NOSAVE 修饰符** 20 | 21 | 通过使用可选的修饰符,可以修改 `SHUTDOWN`_ 命令的表现。比如说: 22 | 23 | - 执行 ``SHUTDOWN SAVE`` 会强制让数据库执行保存操作,即使没有设定(configure)保存点 24 | - 执行 ``SHUTDOWN NOSAVE`` 会阻止数据库执行保存操作,即使已经设定有一个或多个保存点(你可以将这一用法看作是强制停止服务器的一个假想的 ABORT 命令) 25 | 26 | **可用版本:** 27 | >= 1.0.0 28 | 29 | **时间复杂度:** 30 | 不明确 31 | 32 | **返回值:** 33 | | 执行失败时返回错误。 34 | | 执行成功时不返回任何信息,服务器和客户端的连接断开,客户端自动退出。 35 | 36 | :: 37 | 38 | redis> PING 39 | PONG 40 | 41 | redis> SHUTDOWN 42 | 43 | $ 44 | 45 | $ redis 46 | Could not connect to Redis at: Connection refused 47 | not connected> 48 | -------------------------------------------------------------------------------- /server/slaveof.rst: -------------------------------------------------------------------------------- 1 | .. _slaveof: 2 | 3 | SLAVEOF 4 | ======== 5 | 6 | .. function:: SLAVEOF host port 7 | 8 | `SLAVEOF`_ 命令用于在 Redis 运行时动态地修改复制(replication)功能的行为。 9 | 10 | 通过执行 ``SLAVEOF host port`` 命令,可以将当前服务器转变为指定服务器的从属服务器(slave server)。 11 | 12 | 如果当前服务器已经是某个主服务器(master server)的从属服务器,那么执行 ``SLAVEOF host port`` 将使当前服务器停止对旧主服务器的同步,丢弃旧数据集,转而开始对新主服务器进行同步。 13 | 14 | 另外,对一个从属服务器执行命令 ``SLAVEOF NO ONE`` 将使得这个从属服务器关闭复制功能,并从从属服务器转变回主服务器,原来同步所得的数据集\ *不会*\ 被丢弃。 15 | 16 | 利用『 ``SLAVEOF NO ONE`` 不会丢弃同步所得数据集』这个特性,可以在主服务器失败的时候,将从属服务器用作新的主服务器,从而实现无间断运行。 17 | 18 | **可用版本:** 19 | >= 1.0.0 20 | 21 | **时间复杂度:** 22 | | ``SLAVEOF host port`` ,O(N), ``N`` 为要同步的数据数量。 23 | | ``SLAVEOF NO ONE`` , O(1) 。 24 | 25 | **返回值:** 26 | 总是返回 ``OK`` 。 27 | 28 | :: 29 | 30 | redis> SLAVEOF 127.0.0.1 6379 31 | OK 32 | 33 | redis> SLAVEOF NO ONE 34 | OK 35 | 36 | 37 | -------------------------------------------------------------------------------- /server/slowlog.rst: -------------------------------------------------------------------------------- 1 | .. _slowlog: 2 | 3 | SLOWLOG 4 | ========== 5 | 6 | **SLOWLOG subcommand [argument]** 7 | 8 | **什么是 SLOWLOG** 9 | 10 | Slow log 是 Redis 用来记录查询执行时间的日志系统。 11 | 12 | 查询执行时间指的是不包括像客户端响应(talking)、发送回复等 IO 操作,而单单是执行一个查询命令所耗费的时间。 13 | 14 | 另外,slow log 保存在内存里面,读写速度非常快,因此你可以放心地使用它,不必担心因为开启 slow log 而损害 Redis 的速度。 15 | 16 | **设置 SLOWLOG** 17 | 18 | Slow log 的行为由两个配置参数(configuration parameter)指定,可以通过改写 redis.conf 文件或者用 ``CONFIG GET`` 和 ``CONFIG SET`` 命令对它们动态地进行修改。 19 | 20 | 第一个选项是 ``slowlog-log-slower-than`` ,它决定要对执行时间大于多少微秒(microsecond,1秒 = 1,000,000 微秒)的查询进行记录。 21 | 22 | 比如执行以下命令将让 slow log 记录所有查询时间大于等于 100 微秒的查询: 23 | 24 | ``CONFIG SET slowlog-log-slower-than 100`` 25 | 26 | 而以下命令记录所有查询时间大于 1000 微秒的查询: 27 | 28 | ``CONFIG SET slowlog-log-slower-than 1000`` 29 | 30 | 另一个选项是 ``slowlog-max-len`` ,它决定 slow log *最多*\ 能保存多少条日志, slow log 本身是一个 FIFO 队列,当队列大小超过 ``slowlog-max-len`` 时,最旧的一条日志将被删除,而最新的一条日志加入到 slow log ,以此类推。 31 | 32 | 以下命令让 slow log 最多保存 1000 条日志: 33 | 34 | ``CONFIG SET slowlog-max-len 1000`` 35 | 36 | 使用 ``CONFIG GET`` 命令可以查询两个选项的当前值: 37 | 38 | :: 39 | 40 | redis> CONFIG GET slowlog-log-slower-than 41 | 1) "slowlog-log-slower-than" 42 | 2) "1000" 43 | 44 | redis> CONFIG GET slowlog-max-len 45 | 1) "slowlog-max-len" 46 | 2) "1000" 47 | 48 | **查看 slow log** 49 | 50 | 要查看 slow log ,可以使用 ``SLOWLOG GET`` 或者 ``SLOWLOG GET number`` 命令,前者打印所有 slow log ,最大长度取决于 ``slowlog-max-len`` 选项的值,而 ``SLOWLOG GET number`` 则只打印指定数量的日志。 51 | 52 | 最新的日志会最先被打印: 53 | 54 | :: 55 | 56 | # 为测试需要,将 slowlog-log-slower-than 设成了 10 微秒 57 | 58 | redis> SLOWLOG GET 59 | 1) 1) (integer) 12 # 唯一性(unique)的日志标识符 60 | 2) (integer) 1324097834 # 被记录命令的执行时间点,以 UNIX 时间戳格式表示 61 | 3) (integer) 16 # 查询执行时间,以微秒为单位 62 | 4) 1) "CONFIG" # 执行的命令,以数组的形式排列 63 | 2) "GET" # 这里完整的命令是 CONFIG GET slowlog-log-slower-than 64 | 3) "slowlog-log-slower-than" 65 | 66 | 2) 1) (integer) 11 67 | 2) (integer) 1324097825 68 | 3) (integer) 42 69 | 4) 1) "CONFIG" 70 | 2) "GET" 71 | 3) "*" 72 | 73 | 3) 1) (integer) 10 74 | 2) (integer) 1324097820 75 | 3) (integer) 11 76 | 4) 1) "CONFIG" 77 | 2) "GET" 78 | 3) "slowlog-log-slower-than" 79 | 80 | # ... 81 | 82 | 日志的唯一 id 只有在 Redis 服务器重启的时候才会重置,这样可以避免对日志的重复处理(比如你可能会想在每次发现新的慢查询时发邮件通知你)。 83 | 84 | **查看当前日志的数量** 85 | 86 | 使用命令 ``SLOWLOG LEN`` 可以查看当前日志的数量。 87 | 88 | 请注意这个值和 ``slower-max-len`` 的区别,它们一个是当前日志的数量,一个是允许记录的最大日志的数量。 89 | 90 | :: 91 | 92 | redis> SLOWLOG LEN 93 | (integer) 14 94 | 95 | **清空日志** 96 | 97 | 使用命令 ``SLOWLOG RESET`` 可以清空 slow log 。 98 | 99 | :: 100 | 101 | redis> SLOWLOG LEN 102 | (integer) 14 103 | 104 | redis> SLOWLOG RESET 105 | OK 106 | 107 | redis> SLOWLOG LEN 108 | (integer) 0 109 | 110 | **可用版本:** 111 | >= 2.2.12 112 | 113 | **时间复杂度:** 114 | O(1) 115 | 116 | **返回值:** 117 | 取决于不同命令,返回不同的值。 118 | -------------------------------------------------------------------------------- /server/sync.rst: -------------------------------------------------------------------------------- 1 | .. _sync: 2 | 3 | SYNC 4 | ===== 5 | 6 | **SYNC** 7 | 8 | 用于复制功能(replication)的内部命令。 9 | 10 | 更多信息请参考 `Redis 官网的 Replication 章节 `_ 。 11 | 12 | **可用版本:** 13 | >= 1.0.0 14 | 15 | **时间复杂度:** 16 | 不明确 17 | 18 | **返回值:** 19 | 不明确 20 | 21 | :: 22 | 23 | redis> SYNC 24 | "REDIS0002\xfe\x00\x00\auser_id\xc0\x03\x00\anumbers\xc2\xf3\xe0\x01\x00\x00\tdb_number\xc0\x00\x00\x04name\x06huangz\x00\anew_key\nhello_moto\x00\bgreeting\nhello moto\x00\x05my_pc\bthinkpad\x00\x04lock\xc0\x01\x00\nlock_times\xc0\x04\xfe\x01\t\x04info\x19\x02\x04name\b\x00zhangyue\x03age\x02\x0022\xff\t\aooredis,\x03\x04name\a\x00ooredis\aversion\x03\x001.0\x06author\x06\x00huangz\xff\x00\tdb_number\xc0\x01\x00\x05greet\x0bhello world\x02\nmy_friends\x02\x05marry\x04jack\x00\x04name\x05value\xfe\x02\x0c\x01s\x12\x12\x00\x00\x00\r\x00\x00\x00\x02\x00\x00\x01a\x03\xc0f'\xff\xff" 25 | (1.90s) 26 | -------------------------------------------------------------------------------- /server/time.rst: -------------------------------------------------------------------------------- 1 | .. _time: 2 | 3 | TIME 4 | ====== 5 | 6 | **TIME** 7 | 8 | 返回当前服务器时间。 9 | 10 | **可用版本:** 11 | >= 2.6.0 12 | 13 | **时间复杂度:** 14 | O(1) 15 | 16 | **返回值:** 17 | 一个包含两个字符串的列表: 第一个字符串是当前时间(以 UNIX 时间戳格式表示),而第二个字符串是当前这一秒钟已经逝去的微秒数。 18 | 19 | :: 20 | 21 | redis> TIME 22 | 1) "1332395997" 23 | 2) "952581" 24 | redis> TIME 25 | 1) "1332395997" 26 | 2) "953148" 27 | 28 | 29 | -------------------------------------------------------------------------------- /set/index.rst: -------------------------------------------------------------------------------- 1 | Set(集合) 2 | ====================== 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | 7 | sadd 8 | scard 9 | sdiff 10 | sdiffstore 11 | sinter 12 | sinterstore 13 | sismember 14 | smembers 15 | smove 16 | spop 17 | srandmember 18 | srem 19 | sunion 20 | sunionstore 21 | sscan 22 | -------------------------------------------------------------------------------- /set/sadd.rst: -------------------------------------------------------------------------------- 1 | .. _sadd: 2 | 3 | SADD 4 | ===== 5 | 6 | **SADD key member [member ...]** 7 | 8 | 将一个或多个 ``member`` 元素加入到集合 ``key`` 当中,已经存在于集合的 ``member`` 元素将被忽略。 9 | 10 | 假如 ``key`` 不存在,则创建一个只包含 ``member`` 元素作成员的集合。 11 | 12 | 当 ``key`` 不是集合类型时,返回一个错误。 13 | 14 | .. note:: 在Redis2.4版本以前, `SADD`_ 只接受单个 ``member`` 值。 15 | 16 | **可用版本:** 17 | >= 1.0.0 18 | 19 | **时间复杂度:** 20 | O(N), ``N`` 是被添加的元素的数量。 21 | 22 | **返回值:** 23 | 被添加到集合中的新元素的数量,不包括被忽略的元素。 24 | 25 | :: 26 | 27 | # 添加单个元素 28 | 29 | redis> SADD bbs "discuz.net" 30 | (integer) 1 31 | 32 | 33 | # 添加重复元素 34 | 35 | redis> SADD bbs "discuz.net" 36 | (integer) 0 37 | 38 | 39 | # 添加多个元素 40 | 41 | redis> SADD bbs "tianya.cn" "groups.google.com" 42 | (integer) 2 43 | 44 | redis> SMEMBERS bbs 45 | 1) "discuz.net" 46 | 2) "groups.google.com" 47 | 3) "tianya.cn" 48 | -------------------------------------------------------------------------------- /set/scard.rst: -------------------------------------------------------------------------------- 1 | .. _scard: 2 | 3 | SCARD 4 | ====== 5 | 6 | **SCARD key** 7 | 8 | 返回集合 ``key`` 的基数(集合中元素的数量)。 9 | 10 | **可用版本:** 11 | >= 1.0.0 12 | 13 | **时间复杂度:** 14 | O(1) 15 | 16 | **返回值:** 17 | | 集合的基数。 18 | | 当 ``key`` 不存在时,返回 ``0`` 。 19 | 20 | :: 21 | 22 | redis> SADD tool pc printer phone 23 | (integer) 3 24 | 25 | redis> SCARD tool # 非空集合 26 | (integer) 3 27 | 28 | redis> DEL tool 29 | (integer) 1 30 | 31 | redis> SCARD tool # 空集合 32 | (integer) 0 33 | -------------------------------------------------------------------------------- /set/sdiff.rst: -------------------------------------------------------------------------------- 1 | .. _sdiff: 2 | 3 | SDIFF 4 | ====== 5 | 6 | **SDIFF key [key ...]** 7 | 8 | 返回一个集合的全部成员,该集合是所有给定集合之间的差集。 9 | 10 | 不存在的 ``key`` 被视为空集。 11 | 12 | **可用版本:** 13 | >= 1.0.0 14 | 15 | **时间复杂度:** 16 | O(N), ``N`` 是所有给定集合的成员数量之和。 17 | 18 | **返回值:** 19 | 一个包含差集成员的列表。 20 | 21 | :: 22 | 23 | redis> SMEMBERS peter's_movies 24 | 1) "bet man" 25 | 2) "start war" 26 | 3) "2012" 27 | 28 | redis> SMEMBERS joe's_movies 29 | 1) "hi, lady" 30 | 2) "Fast Five" 31 | 3) "2012" 32 | 33 | redis> SDIFF peter's_movies joe's_movies 34 | 1) "bet man" 35 | 2) "start war" 36 | -------------------------------------------------------------------------------- /set/sdiffstore.rst: -------------------------------------------------------------------------------- 1 | .. _sdiffstore: 2 | 3 | SDIFFSTORE 4 | ============ 5 | 6 | **SDIFFSTORE destination key [key ...]** 7 | 8 | 这个命令的作用和 :ref:`SDIFF` 类似,但它将结果保存到 ``destination`` 集合,而不是简单地返回结果集。 9 | 10 | 如果 ``destination`` 集合已经存在,则将其覆盖。 11 | 12 | ``destination`` 可以是 ``key`` 本身。 13 | 14 | **可用版本:** 15 | >= 1.0.0 16 | 17 | **时间复杂度:** 18 | O(N), ``N`` 是所有给定集合的成员数量之和。 19 | 20 | **返回值:** 21 | 结果集中的元素数量。 22 | 23 | :: 24 | 25 | redis> SMEMBERS joe's_movies 26 | 1) "hi, lady" 27 | 2) "Fast Five" 28 | 3) "2012" 29 | 30 | redis> SMEMBERS peter's_movies 31 | 1) "bet man" 32 | 2) "start war" 33 | 3) "2012" 34 | 35 | redis> SDIFFSTORE joe_diff_peter joe's_movies peter's_movies 36 | (integer) 2 37 | 38 | redis> SMEMBERS joe_diff_peter 39 | 1) "hi, lady" 40 | 2) "Fast Five" 41 | -------------------------------------------------------------------------------- /set/sinter.rst: -------------------------------------------------------------------------------- 1 | .. _sinter: 2 | 3 | SINTER 4 | ======== 5 | 6 | **SINTER key [key ...]** 7 | 8 | 返回一个集合的全部成员,该集合是所有给定集合的交集。 9 | 10 | 不存在的 ``key`` 被视为空集。 11 | 12 | 当给定集合当中有一个空集时,结果也为空集(根据集合运算定律)。 13 | 14 | **可用版本:** 15 | >= 1.0.0 16 | 17 | **时间复杂度:** 18 | O(N * M), ``N`` 为给定集合当中基数最小的集合, ``M`` 为给定集合的个数。 19 | 20 | **返回值:** 21 | 交集成员的列表。 22 | 23 | :: 24 | 25 | redis> SMEMBERS group_1 26 | 1) "LI LEI" 27 | 2) "TOM" 28 | 3) "JACK" 29 | 30 | redis> SMEMBERS group_2 31 | 1) "HAN MEIMEI" 32 | 2) "JACK" 33 | 34 | redis> SINTER group_1 group_2 35 | 1) "JACK" 36 | -------------------------------------------------------------------------------- /set/sinterstore.rst: -------------------------------------------------------------------------------- 1 | .. _sinterstore: 2 | 3 | SINTERSTORE 4 | ============ 5 | 6 | **SINTERSTORE destination key [key ...]** 7 | 8 | 这个命令类似于 :ref:`SINTER` 命令,但它将结果保存到 ``destination`` 集合,而不是简单地返回结果集。 9 | 10 | 如果 ``destination`` 集合已经存在,则将其覆盖。 11 | 12 | ``destination`` 可以是 ``key`` 本身。 13 | 14 | **可用版本:** 15 | >= 1.0.0 16 | 17 | **时间复杂度:** 18 | O(N * M), ``N`` 为给定集合当中基数最小的集合, ``M`` 为给定集合的个数。 19 | 20 | **返回值:** 21 | 结果集中的成员数量。 22 | 23 | :: 24 | 25 | redis> SMEMBERS songs 26 | 1) "good bye joe" 27 | 2) "hello,peter" 28 | 29 | redis> SMEMBERS my_songs 30 | 1) "good bye joe" 31 | 2) "falling" 32 | 33 | redis> SINTERSTORE song_interset songs my_songs 34 | (integer) 1 35 | 36 | redis> SMEMBERS song_interset 37 | 1) "good bye joe" 38 | -------------------------------------------------------------------------------- /set/sismember.rst: -------------------------------------------------------------------------------- 1 | .. _sismember: 2 | 3 | SISMEMBER 4 | ========== 5 | 6 | **SISMEMBER key member** 7 | 8 | 判断 ``member`` 元素是否集合 ``key`` 的成员。 9 | 10 | **可用版本:** 11 | >= 1.0.0 12 | 13 | **时间复杂度:** 14 | O(1) 15 | 16 | **返回值:** 17 | | 如果 ``member`` 元素是集合的成员,返回 ``1`` 。 18 | | 如果 ``member`` 元素不是集合的成员,或 ``key`` 不存在,返回 ``0`` 。 19 | 20 | :: 21 | 22 | redis> SMEMBERS joe's_movies 23 | 1) "hi, lady" 24 | 2) "Fast Five" 25 | 3) "2012" 26 | 27 | redis> SISMEMBER joe's_movies "bet man" 28 | (integer) 0 29 | 30 | redis> SISMEMBER joe's_movies "Fast Five" 31 | (integer) 1 32 | -------------------------------------------------------------------------------- /set/smembers.rst: -------------------------------------------------------------------------------- 1 | .. _smembers: 2 | 3 | SMEMBERS 4 | ========= 5 | 6 | **SMEMBERS key** 7 | 8 | 返回集合 ``key`` 中的所有成员。 9 | 10 | 不存在的 ``key`` 被视为空集合。 11 | 12 | **可用版本:** 13 | >= 1.0.0 14 | 15 | **时间复杂度:** 16 | O(N), ``N`` 为集合的基数。 17 | 18 | **返回值:** 19 | 集合中的所有成员。 20 | 21 | :: 22 | 23 | # key 不存在或集合为空 24 | 25 | redis> EXISTS not_exists_key 26 | (integer) 0 27 | 28 | redis> SMEMBERS not_exists_key 29 | (empty list or set) 30 | 31 | 32 | # 非空集合 33 | 34 | redis> SADD language Ruby Python Clojure 35 | (integer) 3 36 | 37 | redis> SMEMBERS language 38 | 1) "Python" 39 | 2) "Ruby" 40 | 3) "Clojure" 41 | -------------------------------------------------------------------------------- /set/smove.rst: -------------------------------------------------------------------------------- 1 | .. _smove: 2 | 3 | SMOVE 4 | ======== 5 | 6 | **SMOVE source destination member** 7 | 8 | 将 ``member`` 元素从 ``source`` 集合移动到 ``destination`` 集合。 9 | 10 | `SMOVE`_ 是原子性操作。 11 | 12 | 如果 ``source`` 集合不存在或不包含指定的 ``member`` 元素,则 `SMOVE`_ 命令不执行任何操作,仅返回 ``0`` 。否则, ``member`` 元素从 ``source`` 集合中被移除,并添加到 ``destination`` 集合中去。 13 | 14 | 当 ``destination`` 集合已经包含 ``member`` 元素时, `SMOVE`_ 命令只是简单地将 ``source`` 集合中的 ``member`` 元素删除。 15 | 16 | 当 ``source`` 或 ``destination`` 不是集合类型时,返回一个错误。 17 | 18 | **可用版本:** 19 | >= 1.0.0 20 | 21 | **时间复杂度:** 22 | O(1) 23 | 24 | **返回值:** 25 | | 如果 ``member`` 元素被成功移除,返回 ``1`` 。 26 | | 如果 ``member`` 元素不是 ``source`` 集合的成员,并且没有任何操作对 ``destination`` 集合执行,那么返回 ``0`` 。 27 | 28 | :: 29 | 30 | redis> SMEMBERS songs 31 | 1) "Billie Jean" 32 | 2) "Believe Me" 33 | 34 | redis> SMEMBERS my_songs 35 | (empty list or set) 36 | 37 | redis> SMOVE songs my_songs "Believe Me" 38 | (integer) 1 39 | 40 | redis> SMEMBERS songs 41 | 1) "Billie Jean" 42 | 43 | redis> SMEMBERS my_songs 44 | 1) "Believe Me" 45 | -------------------------------------------------------------------------------- /set/spop.rst: -------------------------------------------------------------------------------- 1 | .. _spop: 2 | 3 | SPOP 4 | ===== 5 | 6 | **SPOP key** 7 | 8 | 移除并返回集合中的一个随机元素。 9 | 10 | 如果只想获取一个随机元素,但不想该元素从集合中被移除的话,可以使用 :ref:`SRANDMEMBER` 命令。 11 | 12 | **可用版本:** 13 | >= 1.0.0 14 | 15 | **时间复杂度:** 16 | O(1) 17 | 18 | **返回值:** 19 | | 被移除的随机元素。 20 | | 当 ``key`` 不存在或 ``key`` 是空集时,返回 ``nil`` 。 21 | 22 | :: 23 | 24 | redis> SMEMBERS db 25 | 1) "MySQL" 26 | 2) "MongoDB" 27 | 3) "Redis" 28 | 29 | redis> SPOP db 30 | "Redis" 31 | 32 | redis> SMEMBERS db 33 | 1) "MySQL" 34 | 2) "MongoDB" 35 | 36 | redis> SPOP db 37 | "MySQL" 38 | 39 | redis> SMEMBERS db 40 | 1) "MongoDB" 41 | -------------------------------------------------------------------------------- /set/srandmember.rst: -------------------------------------------------------------------------------- 1 | .. _srandmember: 2 | 3 | SRANDMEMBER 4 | ============ 5 | 6 | **SRANDMEMBER key [count]** 7 | 8 | 如果命令执行时,只提供了 ``key`` 参数,那么返回集合中的一个随机元素。 9 | 10 | 从 Redis 2.6 版本开始, `SRANDMEMBER`_ 命令接受可选的 ``count`` 参数: 11 | 12 | - 如果 ``count`` 为正数,且小于集合基数,那么命令返回一个包含 ``count`` 个元素的数组,数组中的元素\ **各不相同**\ 。如果 ``count`` 大于等于集合基数,那么返回整个集合。 13 | 14 | - 如果 ``count`` 为负数,那么命令返回一个数组,数组中的元素\ **可能会重复出现多次**\ ,而数组的长度为 ``count`` 的绝对值。 15 | 16 | 该操作和 :ref:`SPOP` 相似,但 :ref:`SPOP` 将随机元素从集合中移除并返回,而 `SRANDMEMBER`_ 则仅仅返回随机元素,而不对集合进行任何改动。 17 | 18 | **可用版本:** 19 | >= 1.0.0 20 | 21 | **时间复杂度:** 22 | | 只提供 ``key`` 参数时为 O(1) 。 23 | | 如果提供了 ``count`` 参数,那么为 O(N) ,N 为返回数组的元素个数。 24 | 25 | **返回值:** 26 | | 只提供 ``key`` 参数时,返回一个元素;如果集合为空,返回 ``nil`` 。 27 | | 如果提供了 ``count`` 参数,那么返回一个数组;如果集合为空,返回空数组。 28 | 29 | :: 30 | 31 | # 添加元素 32 | 33 | redis> SADD fruit apple banana cherry 34 | (integer) 3 35 | 36 | # 只给定 key 参数,返回一个随机元素 37 | 38 | redis> SRANDMEMBER fruit 39 | "cherry" 40 | 41 | redis> SRANDMEMBER fruit 42 | "apple" 43 | 44 | # 给定 3 为 count 参数,返回 3 个随机元素 45 | # 每个随机元素都不相同 46 | 47 | redis> SRANDMEMBER fruit 3 48 | 1) "apple" 49 | 2) "banana" 50 | 3) "cherry" 51 | 52 | # 给定 -3 为 count 参数,返回 3 个随机元素 53 | # 元素可能会重复出现多次 54 | 55 | redis> SRANDMEMBER fruit -3 56 | 1) "banana" 57 | 2) "cherry" 58 | 3) "apple" 59 | 60 | redis> SRANDMEMBER fruit -3 61 | 1) "apple" 62 | 2) "apple" 63 | 3) "cherry" 64 | 65 | # 如果 count 是整数,且大于等于集合基数,那么返回整个集合 66 | 67 | redis> SRANDMEMBER fruit 10 68 | 1) "apple" 69 | 2) "banana" 70 | 3) "cherry" 71 | 72 | # 如果 count 是负数,且 count 的绝对值大于集合的基数 73 | # 那么返回的数组的长度为 count 的绝对值 74 | 75 | redis> SRANDMEMBER fruit -10 76 | 1) "banana" 77 | 2) "apple" 78 | 3) "banana" 79 | 4) "cherry" 80 | 5) "apple" 81 | 6) "apple" 82 | 7) "cherry" 83 | 8) "apple" 84 | 9) "apple" 85 | 10) "banana" 86 | 87 | # SRANDMEMBER 并不会修改集合内容 88 | 89 | redis> SMEMBERS fruit 90 | 1) "apple" 91 | 2) "cherry" 92 | 3) "banana" 93 | 94 | # 集合为空时返回 nil 或者空数组 95 | 96 | redis> SRANDMEMBER not-exists 97 | (nil) 98 | 99 | redis> SRANDMEMBER not-eixsts 10 100 | (empty list or set) 101 | -------------------------------------------------------------------------------- /set/srem.rst: -------------------------------------------------------------------------------- 1 | .. _srem: 2 | 3 | SREM 4 | ===== 5 | 6 | **SREM key member [member ...]** 7 | 8 | 移除集合 ``key`` 中的一个或多个 ``member`` 元素,不存在的 ``member`` 元素会被忽略。 9 | 10 | 当 ``key`` 不是集合类型,返回一个错误。 11 | 12 | .. note:: 在 Redis 2.4 版本以前, `SREM`_ 只接受单个 ``member`` 值。 13 | 14 | **可用版本:** 15 | >= 1.0.0 16 | 17 | **时间复杂度:** 18 | O(N), ``N`` 为给定 ``member`` 元素的数量。 19 | 20 | **返回值:** 21 | 被成功移除的元素的数量,不包括被忽略的元素。 22 | 23 | :: 24 | 25 | # 测试数据 26 | 27 | redis> SMEMBERS languages 28 | 1) "c" 29 | 2) "lisp" 30 | 3) "python" 31 | 4) "ruby" 32 | 33 | 34 | # 移除单个元素 35 | 36 | redis> SREM languages ruby 37 | (integer) 1 38 | 39 | 40 | # 移除不存在元素 41 | 42 | redis> SREM languages non-exists-language 43 | (integer) 0 44 | 45 | 46 | # 移除多个元素 47 | 48 | redis> SREM languages lisp python c 49 | (integer) 3 50 | 51 | redis> SMEMBERS languages 52 | (empty list or set) 53 | -------------------------------------------------------------------------------- /set/sscan.rst: -------------------------------------------------------------------------------- 1 | .. _sscan: 2 | 3 | SSCAN 4 | ========== 5 | 6 | **SSCAN key cursor [MATCH pattern] [COUNT count]** 7 | 8 | 详细信息请参考 :ref:`SCAN` 命令。 9 | -------------------------------------------------------------------------------- /set/sunion.rst: -------------------------------------------------------------------------------- 1 | .. _sunion: 2 | 3 | SUNION 4 | ======= 5 | 6 | **SUNION key [key ...]** 7 | 8 | 返回一个集合的全部成员,该集合是所有给定集合的并集。 9 | 10 | 不存在的 ``key`` 被视为空集。 11 | 12 | **可用版本:** 13 | >= 1.0.0 14 | 15 | **时间复杂度:** 16 | O(N), ``N`` 是所有给定集合的成员数量之和。 17 | 18 | **返回值:** 19 | 并集成员的列表。 20 | 21 | :: 22 | 23 | redis> SMEMBERS songs 24 | 1) "Billie Jean" 25 | 26 | redis> SMEMBERS my_songs 27 | 1) "Believe Me" 28 | 29 | redis> SUNION songs my_songs 30 | 1) "Billie Jean" 31 | 2) "Believe Me" 32 | -------------------------------------------------------------------------------- /set/sunionstore.rst: -------------------------------------------------------------------------------- 1 | .. _sunionstore: 2 | 3 | SUNIONSTORE 4 | ============ 5 | 6 | **SUNIONSTORE destination key [key ...]** 7 | 8 | 这个命令类似于 :ref:`SUNION` 命令,但它将结果保存到 ``destination`` 集合,而不是简单地返回结果集。 9 | 10 | 如果 ``destination`` 已经存在,则将其覆盖。 11 | 12 | ``destination`` 可以是 ``key`` 本身。 13 | 14 | **可用版本:** 15 | >= 1.0.0 16 | 17 | **时间复杂度:** 18 | O(N), ``N`` 是所有给定集合的成员数量之和。 19 | 20 | **返回值:** 21 | 结果集中的元素数量。 22 | 23 | :: 24 | 25 | redis> SMEMBERS NoSQL 26 | 1) "MongoDB" 27 | 2) "Redis" 28 | 29 | redis> SMEMBERS SQL 30 | 1) "sqlite" 31 | 2) "MySQL" 32 | 33 | redis> SUNIONSTORE db NoSQL SQL 34 | (integer) 4 35 | 36 | redis> SMEMBERS db 37 | 1) "MySQL" 38 | 2) "sqlite" 39 | 3) "MongoDB" 40 | 4) "Redis" 41 | -------------------------------------------------------------------------------- /sorted_set/index.rst: -------------------------------------------------------------------------------- 1 | SortedSet(有序集合) 2 | ========================== 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | 7 | zadd 8 | zcard 9 | zcount 10 | zincrby 11 | zrange 12 | zrangebyscore 13 | zrank 14 | zrem 15 | zremrangebyrank 16 | zremrangebyscore 17 | zrevrange 18 | zrevrangebyscore 19 | zrevrank 20 | zscore 21 | zunionstore 22 | zinterstore 23 | zscan 24 | -------------------------------------------------------------------------------- /sorted_set/zadd.rst: -------------------------------------------------------------------------------- 1 | .. _zadd: 2 | 3 | ZADD 4 | ==== 5 | 6 | **ZADD key score member [[score member] [score member] ...]** 7 | 8 | 将一个或多个 ``member`` 元素及其 ``score`` 值加入到有序集 ``key`` 当中。 9 | 10 | 如果某个 ``member`` 已经是有序集的成员,那么更新这个 ``member`` 的 ``score`` 值,并通过重新插入这个 ``member`` 元素,来保证该 ``member`` 在正确的位置上。 11 | 12 | ``score`` 值可以是整数值或双精度浮点数。 13 | 14 | 如果 ``key`` 不存在,则创建一个空的有序集并执行 `ZADD`_ 操作。 15 | 16 | 当 ``key`` 存在但不是有序集类型时,返回一个错误。 17 | 18 | 对有序集的更多介绍请参见 `sorted set `_ 。 19 | 20 | .. note:: 在 Redis 2.4 版本以前, `ZADD`_ 每次只能添加一个元素。 21 | 22 | **可用版本:** 23 | >= 1.2.0 24 | 25 | **时间复杂度:** 26 | O(M*log(N)), ``N`` 是有序集的基数, ``M`` 为成功添加的新成员的数量。 27 | 28 | **返回值:** 29 | 被成功添加的新成员的数量,不包括那些被更新的、已经存在的成员。 30 | 31 | :: 32 | 33 | # 添加单个元素 34 | 35 | redis> ZADD page_rank 10 google.com 36 | (integer) 1 37 | 38 | 39 | # 添加多个元素 40 | 41 | redis> ZADD page_rank 9 baidu.com 8 bing.com 42 | (integer) 2 43 | 44 | redis> ZRANGE page_rank 0 -1 WITHSCORES 45 | 1) "bing.com" 46 | 2) "8" 47 | 3) "baidu.com" 48 | 4) "9" 49 | 5) "google.com" 50 | 6) "10" 51 | 52 | 53 | # 添加已存在元素,且 score 值不变 54 | 55 | redis> ZADD page_rank 10 google.com 56 | (integer) 0 57 | 58 | redis> ZRANGE page_rank 0 -1 WITHSCORES # 没有改变 59 | 1) "bing.com" 60 | 2) "8" 61 | 3) "baidu.com" 62 | 4) "9" 63 | 5) "google.com" 64 | 6) "10" 65 | 66 | 67 | # 添加已存在元素,但是改变 score 值 68 | 69 | redis> ZADD page_rank 6 bing.com 70 | (integer) 0 71 | 72 | redis> ZRANGE page_rank 0 -1 WITHSCORES # bing.com 元素的 score 值被改变 73 | 1) "bing.com" 74 | 2) "6" 75 | 3) "baidu.com" 76 | 4) "9" 77 | 5) "google.com" 78 | 6) "10" 79 | -------------------------------------------------------------------------------- /sorted_set/zcard.rst: -------------------------------------------------------------------------------- 1 | .. _zcard: 2 | 3 | ZCARD 4 | ====== 5 | 6 | **ZCARD key** 7 | 8 | 返回有序集 ``key`` 的基数。 9 | 10 | **可用版本:** 11 | >= 1.2.0 12 | 13 | **时间复杂度:** 14 | O(1) 15 | 16 | **返回值:** 17 | | 当 ``key`` 存在且是有序集类型时,返回有序集的基数。 18 | | 当 ``key`` 不存在时,返回 ``0`` 。 19 | 20 | :: 21 | 22 | redis > ZADD salary 2000 tom # 添加一个成员 23 | (integer) 1 24 | 25 | redis > ZCARD salary 26 | (integer) 1 27 | 28 | redis > ZADD salary 5000 jack # 再添加一个成员 29 | (integer) 1 30 | 31 | redis > ZCARD salary 32 | (integer) 2 33 | 34 | redis > EXISTS non_exists_key # 对不存在的 key 进行 ZCARD 操作 35 | (integer) 0 36 | 37 | redis > ZCARD non_exists_key 38 | (integer) 0 39 | -------------------------------------------------------------------------------- /sorted_set/zcount.rst: -------------------------------------------------------------------------------- 1 | .. _zcount: 2 | 3 | ZCOUNT 4 | ======= 5 | 6 | **ZCOUNT key min max** 7 | 8 | 返回有序集 ``key`` 中, ``score`` 值在 ``min`` 和 ``max`` 之间(默认包括 ``score`` 值等于 ``min`` 或 ``max`` )的成员的数量。 9 | 10 | 关于参数 ``min`` 和 ``max`` 的详细使用方法,请参考 :ref:`ZRANGEBYSCORE` 命令。 11 | 12 | **可用版本:** 13 | >= 2.0.0 14 | 15 | **时间复杂度:** 16 | O(log(N)), ``N`` 为有序集的基数。 17 | 18 | **返回值:** 19 | ``score`` 值在 ``min`` 和 ``max`` 之间的成员的数量。 20 | 21 | :: 22 | 23 | redis> ZRANGE salary 0 -1 WITHSCORES # 测试数据 24 | 1) "jack" 25 | 2) "2000" 26 | 3) "peter" 27 | 4) "3500" 28 | 5) "tom" 29 | 6) "5000" 30 | 31 | redis> ZCOUNT salary 2000 5000 # 计算薪水在 2000-5000 之间的人数 32 | (integer) 3 33 | 34 | redis> ZCOUNT salary 3000 5000 # 计算薪水在 3000-5000 之间的人数 35 | (integer) 2 36 | -------------------------------------------------------------------------------- /sorted_set/zincrby.rst: -------------------------------------------------------------------------------- 1 | .. _zincrby: 2 | 3 | ZINCRBY 4 | ======== 5 | 6 | **ZINCRBY key increment member** 7 | 8 | 为有序集 ``key`` 的成员 ``member`` 的 ``score`` 值加上增量 ``increment`` 。 9 | 10 | 可以通过传递一个负数值 ``increment`` ,让 ``score`` 减去相应的值,比如 ``ZINCRBY key -5 member`` ,就是让 ``member`` 的 ``score`` 值减去 ``5`` 。 11 | 12 | 当 ``key`` 不存在,或 ``member`` 不是 ``key`` 的成员时, ``ZINCRBY key increment member`` 等同于 ``ZADD key increment member`` 。 13 | 14 | 当 ``key`` 不是有序集类型时,返回一个错误。 15 | 16 | ``score`` 值可以是整数值或双精度浮点数。 17 | 18 | **可用版本:** 19 | >= 1.2.0 20 | 21 | **时间复杂度:** 22 | O(log(N)) 23 | 24 | **返回值:** 25 | ``member`` 成员的新 ``score`` 值,以字符串形式表示。 26 | 27 | :: 28 | 29 | redis> ZSCORE salary tom 30 | "2000" 31 | 32 | redis> ZINCRBY salary 2000 tom # tom 加薪啦! 33 | "4000" 34 | -------------------------------------------------------------------------------- /sorted_set/zinterstore.rst: -------------------------------------------------------------------------------- 1 | .. _zinterstore: 2 | 3 | ZINTERSTORE 4 | ============= 5 | 6 | **ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]** 7 | 8 | 计算给定的一个或多个有序集的交集,其中给定 ``key`` 的数量必须以 ``numkeys`` 参数指定,并将该交集(结果集)储存到 ``destination`` 。 9 | 10 | 默认情况下,结果集中某个成员的 ``score`` 值是所有给定集下该成员 ``score`` 值之和. 11 | 12 | 关于 ``WEIGHTS`` 和 ``AGGREGATE`` 选项的描述,参见 :ref:`ZUNIONSTORE` 命令。 13 | 14 | **可用版本:** 15 | >= 2.0.0 16 | 17 | **时间复杂度:** 18 | O(N*K)+O(M*log(M)), ``N`` 为给定 ``key`` 中基数最小的有序集, ``K`` 为给定有序集的数量, ``M`` 为结果集的基数。 19 | 20 | **返回值:** 21 | 保存到 ``destination`` 的结果集的基数。 22 | 23 | :: 24 | 25 | redis > ZADD mid_test 70 "Li Lei" 26 | (integer) 1 27 | redis > ZADD mid_test 70 "Han Meimei" 28 | (integer) 1 29 | redis > ZADD mid_test 99.5 "Tom" 30 | (integer) 1 31 | 32 | redis > ZADD fin_test 88 "Li Lei" 33 | (integer) 1 34 | redis > ZADD fin_test 75 "Han Meimei" 35 | (integer) 1 36 | redis > ZADD fin_test 99.5 "Tom" 37 | (integer) 1 38 | 39 | redis > ZINTERSTORE sum_point 2 mid_test fin_test 40 | (integer) 3 41 | 42 | redis > ZRANGE sum_point 0 -1 WITHSCORES # 显示有序集内所有成员及其 score 值 43 | 1) "Han Meimei" 44 | 2) "145" 45 | 3) "Li Lei" 46 | 4) "158" 47 | 5) "Tom" 48 | 6) "199" 49 | -------------------------------------------------------------------------------- /sorted_set/zrange.rst: -------------------------------------------------------------------------------- 1 | .. _zrange: 2 | 3 | ZRANGE 4 | ======= 5 | 6 | **ZRANGE key start stop [WITHSCORES]** 7 | 8 | 返回有序集 ``key`` 中,指定区间内的成员。 9 | 10 | 其中成员的位置按 ``score`` 值递增(从小到大)来排序。 11 | 12 | 具有相同 ``score`` 值的成员按字典序(`lexicographical order `_ )来排列。 13 | 14 | 如果你需要成员按 ``score`` 值递减(从大到小)来排列,请使用 :ref:`ZREVRANGE` 命令。 15 | 16 | | 下标参数 ``start`` 和 ``stop`` 都以 ``0`` 为底,也就是说,以 ``0`` 表示有序集第一个成员,以 ``1`` 表示有序集第二个成员,以此类推。 17 | | 你也可以使用负数下标,以 ``-1`` 表示最后一个成员, ``-2`` 表示倒数第二个成员,以此类推。 18 | 19 | | 超出范围的下标并不会引起错误。 20 | | 比如说,当 ``start`` 的值比有序集的最大下标还要大,或是 ``start > stop`` 时, `ZRANGE`_ 命令只是简单地返回一个空列表。 21 | | 另一方面,假如 ``stop`` 参数的值比有序集的最大下标还要大,那么 Redis 将 ``stop`` 当作最大下标来处理。 22 | 23 | | 可以通过使用 ``WITHSCORES`` 选项,来让成员和它的 ``score`` 值一并返回,返回列表以 ``value1,score1, ..., valueN,scoreN`` 的格式表示。 24 | | 客户端库可能会返回一些更复杂的数据类型,比如数组、元组等。 25 | 26 | **可用版本:** 27 | >= 1.2.0 28 | 29 | **时间复杂度:** 30 | O(log(N)+M), ``N`` 为有序集的基数,而 ``M`` 为结果集的基数。 31 | 32 | **返回值:** 33 | 指定区间内,带有 ``score`` 值(可选)的有序集成员的列表。 34 | 35 | :: 36 | 37 | redis > ZRANGE salary 0 -1 WITHSCORES # 显示整个有序集成员 38 | 1) "jack" 39 | 2) "3500" 40 | 3) "tom" 41 | 4) "5000" 42 | 5) "boss" 43 | 6) "10086" 44 | 45 | redis > ZRANGE salary 1 2 WITHSCORES # 显示有序集下标区间 1 至 2 的成员 46 | 1) "tom" 47 | 2) "5000" 48 | 3) "boss" 49 | 4) "10086" 50 | 51 | redis > ZRANGE salary 0 200000 WITHSCORES # 测试 end 下标超出最大下标时的情况 52 | 1) "jack" 53 | 2) "3500" 54 | 3) "tom" 55 | 4) "5000" 56 | 5) "boss" 57 | 6) "10086" 58 | 59 | redis > ZRANGE salary 200000 3000000 WITHSCORES # 测试当给定区间不存在于有序集时的情况 60 | (empty list or set) 61 | -------------------------------------------------------------------------------- /sorted_set/zrangebyscore.rst: -------------------------------------------------------------------------------- 1 | .. _zrangebyscore: 2 | 3 | ZRANGEBYSCORE 4 | ============== 5 | 6 | **ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]** 7 | 8 | 返回有序集 ``key`` 中,所有 ``score`` 值介于 ``min`` 和 ``max`` 之间(包括等于 ``min`` 或 ``max`` )的成员。有序集成员按 ``score`` 值递增(从小到大)次序排列。 9 | 10 | 具有相同 ``score`` 值的成员按字典序(`lexicographical order `_)来排列(该属性是有序集提供的,不需要额外的计算)。 11 | 12 | 可选的 ``LIMIT`` 参数指定返回结果的数量及区间(就像SQL中的 ``SELECT LIMIT offset, count`` ),注意当 ``offset`` 很大时,定位 ``offset`` 的操作可能需要遍历整个有序集,此过程最坏复杂度为 O(N) 时间。 13 | 14 | | 可选的 ``WITHSCORES`` 参数决定结果集是单单返回有序集的成员,还是将有序集成员及其 ``score`` 值一起返回。 15 | | 该选项自 Redis 2.0 版本起可用。 16 | 17 | **区间及无限** 18 | 19 | ``min`` 和 ``max`` 可以是 ``-inf`` 和 ``+inf`` ,这样一来,你就可以在不知道有序集的最低和最高 ``score`` 值的情况下,使用 `ZRANGEBYSCORE`_ 这类命令。 20 | 21 | 默认情况下,区间的取值使用\ `闭区间 `_ (小于等于或大于等于),你也可以通过给参数前增加 ``(`` 符号来使用可选的\ `开区间 `_ (小于或大于)。 22 | 23 | 举个例子: 24 | 25 | :: 26 | 27 | ZRANGEBYSCORE zset (1 5 28 | 29 | 返回所有符合条件 ``1 < score <= 5`` 的成员,而 30 | 31 | :: 32 | 33 | ZRANGEBYSCORE zset (5 (10 34 | 35 | 则返回所有符合条件 ``5 < score < 10`` 的成员。 36 | 37 | **可用版本:** 38 | >= 1.0.5 39 | 40 | **时间复杂度:** 41 | O(log(N)+M), ``N`` 为有序集的基数, ``M`` 为被结果集的基数。 42 | 43 | **返回值:** 44 | 指定区间内,带有 ``score`` 值(可选)的有序集成员的列表。 45 | 46 | :: 47 | 48 | redis> ZADD salary 2500 jack # 测试数据 49 | (integer) 0 50 | redis> ZADD salary 5000 tom 51 | (integer) 0 52 | redis> ZADD salary 12000 peter 53 | (integer) 0 54 | 55 | redis> ZRANGEBYSCORE salary -inf +inf # 显示整个有序集 56 | 1) "jack" 57 | 2) "tom" 58 | 3) "peter" 59 | 60 | redis> ZRANGEBYSCORE salary -inf +inf WITHSCORES # 显示整个有序集及成员的 score 值 61 | 1) "jack" 62 | 2) "2500" 63 | 3) "tom" 64 | 4) "5000" 65 | 5) "peter" 66 | 6) "12000" 67 | 68 | redis> ZRANGEBYSCORE salary -inf 5000 WITHSCORES # 显示工资 <=5000 的所有成员 69 | 1) "jack" 70 | 2) "2500" 71 | 3) "tom" 72 | 4) "5000" 73 | 74 | redis> ZRANGEBYSCORE salary (5000 400000 # 显示工资大于 5000 小于等于 400000 的成员 75 | 1) "peter" 76 | -------------------------------------------------------------------------------- /sorted_set/zrank.rst: -------------------------------------------------------------------------------- 1 | .. _zrank: 2 | 3 | ZRANK 4 | ======= 5 | 6 | **ZRANK key member** 7 | 8 | 返回有序集 ``key`` 中成员 ``member`` 的排名。其中有序集成员按 ``score`` 值递增(从小到大)顺序排列。 9 | 10 | 排名以 ``0`` 为底,也就是说, ``score`` 值最小的成员排名为 ``0`` 。 11 | 12 | 使用 :ref:`ZREVRANK` 命令可以获得成员按 ``score`` 值递减(从大到小)排列的排名。 13 | 14 | **可用版本:** 15 | >= 2.0.0 16 | 17 | **时间复杂度:** 18 | O(log(N)) 19 | 20 | **返回值:** 21 | | 如果 ``member`` 是有序集 ``key`` 的成员,返回 ``member`` 的排名。 22 | | 如果 ``member`` 不是有序集 ``key`` 的成员,返回 ``nil`` 。 23 | 24 | :: 25 | 26 | redis> ZRANGE salary 0 -1 WITHSCORES # 显示所有成员及其 score 值 27 | 1) "peter" 28 | 2) "3500" 29 | 3) "tom" 30 | 4) "4000" 31 | 5) "jack" 32 | 6) "5000" 33 | 34 | redis> ZRANK salary tom # 显示 tom 的薪水排名,第二 35 | (integer) 1 36 | -------------------------------------------------------------------------------- /sorted_set/zrem.rst: -------------------------------------------------------------------------------- 1 | .. _zrem: 2 | 3 | ZREM 4 | ===== 5 | 6 | **ZREM key member [member ...]** 7 | 8 | 移除有序集 ``key`` 中的一个或多个成员,不存在的成员将被忽略。 9 | 10 | 当 ``key`` 存在但不是有序集类型时,返回一个错误。 11 | 12 | .. note:: 在 Redis 2.4 版本以前, `ZREM`_ 每次只能删除一个元素。 13 | 14 | **可用版本:** 15 | >= 1.2.0 16 | 17 | **时间复杂度:** 18 | O(M*log(N)), ``N`` 为有序集的基数, ``M`` 为被成功移除的成员的数量。 19 | 20 | **返回值:** 21 | 被成功移除的成员的数量,不包括被忽略的成员。 22 | 23 | 24 | :: 25 | 26 | # 测试数据 27 | 28 | redis> ZRANGE page_rank 0 -1 WITHSCORES 29 | 1) "bing.com" 30 | 2) "8" 31 | 3) "baidu.com" 32 | 4) "9" 33 | 5) "google.com" 34 | 6) "10" 35 | 36 | 37 | # 移除单个元素 38 | 39 | redis> ZREM page_rank google.com 40 | (integer) 1 41 | 42 | redis> ZRANGE page_rank 0 -1 WITHSCORES 43 | 1) "bing.com" 44 | 2) "8" 45 | 3) "baidu.com" 46 | 4) "9" 47 | 48 | 49 | # 移除多个元素 50 | 51 | redis> ZREM page_rank baidu.com bing.com 52 | (integer) 2 53 | 54 | redis> ZRANGE page_rank 0 -1 WITHSCORES 55 | (empty list or set) 56 | 57 | 58 | # 移除不存在元素 59 | 60 | redis> ZREM page_rank non-exists-element 61 | (integer) 0 62 | -------------------------------------------------------------------------------- /sorted_set/zremrangebyrank.rst: -------------------------------------------------------------------------------- 1 | .. _zremrangebyrank: 2 | 3 | ZREMRANGEBYRANK 4 | ================ 5 | 6 | **ZREMRANGEBYRANK key start stop** 7 | 8 | 移除有序集 ``key`` 中,指定排名(rank)区间内的所有成员。 9 | 10 | 区间分别以下标参数 ``start`` 和 ``stop`` 指出,包含 ``start`` 和 ``stop`` 在内。 11 | 12 | | 下标参数 ``start`` 和 ``stop`` 都以 ``0`` 为底,也就是说,以 ``0`` 表示有序集第一个成员,以 ``1`` 表示有序集第二个成员,以此类推。 13 | | 你也可以使用负数下标,以 ``-1`` 表示最后一个成员, ``-2`` 表示倒数第二个成员,以此类推。 14 | 15 | **可用版本:** 16 | >= 2.0.0 17 | 18 | **时间复杂度:** 19 | O(log(N)+M), ``N`` 为有序集的基数,而 ``M`` 为被移除成员的数量。 20 | 21 | **返回值:** 22 | 被移除成员的数量。 23 | 24 | :: 25 | 26 | redis> ZADD salary 2000 jack 27 | (integer) 1 28 | redis> ZADD salary 5000 tom 29 | (integer) 1 30 | redis> ZADD salary 3500 peter 31 | (integer) 1 32 | 33 | redis> ZREMRANGEBYRANK salary 0 1 # 移除下标 0 至 1 区间内的成员 34 | (integer) 2 35 | 36 | redis> ZRANGE salary 0 -1 WITHSCORES # 有序集只剩下一个成员 37 | 1) "tom" 38 | 2) "5000" 39 | -------------------------------------------------------------------------------- /sorted_set/zremrangebyscore.rst: -------------------------------------------------------------------------------- 1 | .. _zremrangebyscore: 2 | 3 | ZREMRANGEBYSCORE 4 | ================= 5 | 6 | **ZREMRANGEBYSCORE key min max** 7 | 8 | 移除有序集 ``key`` 中,所有 ``score`` 值介于 ``min`` 和 ``max`` 之间(包括等于 ``min`` 或 ``max`` )的成员。 9 | 10 | 自版本2.1.6开始, ``score`` 值等于 ``min`` 或 ``max`` 的成员也可以不包括在内,详情请参见 :ref:`ZRANGEBYSCORE` 命令。 11 | 12 | **可用版本:** 13 | >= 1.2.0 14 | 15 | **时间复杂度:** 16 | O(log(N)+M), ``N`` 为有序集的基数,而 ``M`` 为被移除成员的数量。 17 | 18 | **返回值:** 19 | 被移除成员的数量。 20 | 21 | :: 22 | 23 | redis> ZRANGE salary 0 -1 WITHSCORES # 显示有序集内所有成员及其 score 值 24 | 1) "tom" 25 | 2) "2000" 26 | 3) "peter" 27 | 4) "3500" 28 | 5) "jack" 29 | 6) "5000" 30 | 31 | redis> ZREMRANGEBYSCORE salary 1500 3500 # 移除所有薪水在 1500 到 3500 内的员工 32 | (integer) 2 33 | 34 | redis> ZRANGE salary 0 -1 WITHSCORES # 剩下的有序集成员 35 | 1) "jack" 36 | 2) "5000" 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /sorted_set/zrevrange.rst: -------------------------------------------------------------------------------- 1 | .. _zrevrange: 2 | 3 | ZREVRANGE 4 | =========== 5 | 6 | **ZREVRANGE key start stop [WITHSCORES]** 7 | 8 | 返回有序集 ``key`` 中,指定区间内的成员。 9 | 10 | | 其中成员的位置按 ``score`` 值递减(从大到小)来排列。 11 | | 具有相同 ``score`` 值的成员按字典序的逆序(`reverse lexicographical order `_)排列。 12 | 13 | 除了成员按 ``score`` 值递减的次序排列这一点外, `ZREVRANGE`_ 命令的其他方面和 :ref:`ZRANGE` 命令一样。 14 | 15 | **可用版本:** 16 | >= 1.2.0 17 | 18 | **时间复杂度:** 19 | O(log(N)+M), ``N`` 为有序集的基数,而 ``M`` 为结果集的基数。 20 | 21 | **返回值:** 22 | 指定区间内,带有 ``score`` 值(可选)的有序集成员的列表。 23 | 24 | :: 25 | 26 | redis> ZRANGE salary 0 -1 WITHSCORES # 递增排列 27 | 1) "peter" 28 | 2) "3500" 29 | 3) "tom" 30 | 4) "4000" 31 | 5) "jack" 32 | 6) "5000" 33 | 34 | redis> ZREVRANGE salary 0 -1 WITHSCORES # 递减排列 35 | 1) "jack" 36 | 2) "5000" 37 | 3) "tom" 38 | 4) "4000" 39 | 5) "peter" 40 | 6) "3500" 41 | -------------------------------------------------------------------------------- /sorted_set/zrevrangebyscore.rst: -------------------------------------------------------------------------------- 1 | .. _zrevrangebyscore: 2 | 3 | ZREVRANGEBYSCORE 4 | ================= 5 | 6 | **ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]** 7 | 8 | 返回有序集 ``key`` 中, ``score`` 值介于 ``max`` 和 ``min`` 之间(默认包括等于 ``max`` 或 ``min`` )的所有的成员。有序集成员按 ``score`` 值递减(从大到小)的次序排列。 9 | 10 | 具有相同 ``score`` 值的成员按字典序的逆序(`reverse lexicographical order `_ )排列。 11 | 12 | 除了成员按 ``score`` 值递减的次序排列这一点外, `ZREVRANGEBYSCORE`_ 命令的其他方面和 :ref:`ZRANGEBYSCORE` 命令一样。 13 | 14 | **可用版本:** 15 | >= 2.2.0 16 | 17 | **时间复杂度:** 18 | O(log(N)+M), ``N`` 为有序集的基数, ``M`` 为结果集的基数。 19 | 20 | **返回值:** 21 | 指定区间内,带有 ``score`` 值(可选)的有序集成员的列表。 22 | 23 | :: 24 | 25 | redis > ZADD salary 10086 jack 26 | (integer) 1 27 | redis > ZADD salary 5000 tom 28 | (integer) 1 29 | redis > ZADD salary 7500 peter 30 | (integer) 1 31 | redis > ZADD salary 3500 joe 32 | (integer) 1 33 | 34 | redis > ZREVRANGEBYSCORE salary +inf -inf # 逆序排列所有成员 35 | 1) "jack" 36 | 2) "peter" 37 | 3) "tom" 38 | 4) "joe" 39 | 40 | redis > ZREVRANGEBYSCORE salary 10000 2000 # 逆序排列薪水介于 10000 和 2000 之间的成员 41 | 1) "peter" 42 | 2) "tom" 43 | 3) "joe" 44 | -------------------------------------------------------------------------------- /sorted_set/zrevrank.rst: -------------------------------------------------------------------------------- 1 | .. _zrevrank: 2 | 3 | ZREVRANK 4 | ========= 5 | 6 | **ZREVRANK key member** 7 | 8 | 返回有序集 ``key`` 中成员 ``member`` 的排名。其中有序集成员按 ``score`` 值递减(从大到小)排序。 9 | 10 | 排名以 ``0`` 为底,也就是说, ``score`` 值最大的成员排名为 ``0`` 。 11 | 12 | 使用 :ref:`ZRANK` 命令可以获得成员按 ``score`` 值递增(从小到大)排列的排名。 13 | 14 | **可用版本:** 15 | >= 2.0.0 16 | 17 | **时间复杂度:** 18 | O(log(N)) 19 | 20 | **返回值:** 21 | | 如果 ``member`` 是有序集 ``key`` 的成员,返回 ``member`` 的排名。 22 | | 如果 ``member`` 不是有序集 ``key`` 的成员,返回 ``nil`` 。 23 | 24 | :: 25 | 26 | redis 127.0.0.1:6379> ZRANGE salary 0 -1 WITHSCORES # 测试数据 27 | 1) "jack" 28 | 2) "2000" 29 | 3) "peter" 30 | 4) "3500" 31 | 5) "tom" 32 | 6) "5000" 33 | 34 | redis> ZREVRANK salary peter # peter 的工资排第二 35 | (integer) 1 36 | 37 | redis> ZREVRANK salary tom # tom 的工资最高 38 | (integer) 0 39 | -------------------------------------------------------------------------------- /sorted_set/zscan.rst: -------------------------------------------------------------------------------- 1 | .. _zscan: 2 | 3 | ZSCAN 4 | ========= 5 | 6 | **ZSCAN key cursor [MATCH pattern] [COUNT count]** 7 | 8 | 详细信息请参考 :ref:`SCAN` 命令。 9 | -------------------------------------------------------------------------------- /sorted_set/zscore.rst: -------------------------------------------------------------------------------- 1 | .. _zscore: 2 | 3 | ZSCORE 4 | ====== 5 | 6 | **ZSCORE key member** 7 | 8 | 返回有序集 ``key`` 中,成员 ``member`` 的 ``score`` 值。 9 | 10 | 如果 ``member`` 元素不是有序集 ``key`` 的成员,或 ``key`` 不存在,返回 ``nil`` 。 11 | 12 | **可用版本:** 13 | >= 1.2.0 14 | 15 | **时间复杂度:** 16 | O(1) 17 | 18 | **返回值:** 19 | ``member`` 成员的 ``score`` 值,以字符串形式表示。 20 | 21 | :: 22 | 23 | redis> ZRANGE salary 0 -1 WITHSCORES # 测试数据 24 | 1) "tom" 25 | 2) "2000" 26 | 3) "peter" 27 | 4) "3500" 28 | 5) "jack" 29 | 6) "5000" 30 | 31 | redis> ZSCORE salary peter # 注意返回值是字符串 32 | "3500" 33 | -------------------------------------------------------------------------------- /sorted_set/zunionstore.rst: -------------------------------------------------------------------------------- 1 | .. _zunionstore: 2 | 3 | ZUNIONSTORE 4 | ============ 5 | 6 | **ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]** 7 | 8 | 计算给定的一个或多个有序集的并集,其中给定 ``key`` 的数量必须以 ``numkeys`` 参数指定,并将该并集(结果集)储存到 ``destination`` 。 9 | 10 | 默认情况下,结果集中某个成员的 ``score`` 值是所有给定集下该成员 ``score`` 值之 *和* 。 11 | 12 | **WEIGHTS** 13 | 14 | 使用 ``WEIGHTS`` 选项,你可以为 *每个* 给定有序集 *分别* 指定一个乘法因子(multiplication factor),每个给定有序集的所有成员的 ``score`` 值在传递给聚合函数(aggregation function)之前都要先乘以该有序集的因子。 15 | 16 | 如果没有指定 ``WEIGHTS`` 选项,乘法因子默认设置为 ``1`` 。 17 | 18 | **AGGREGATE** 19 | 20 | 使用 ``AGGREGATE`` 选项,你可以指定并集的结果集的聚合方式。 21 | 22 | 默认使用的参数 ``SUM`` ,可以将所有集合中某个成员的 ``score`` 值之 *和* 作为结果集中该成员的 ``score`` 值;使用参数 ``MIN`` ,可以将所有集合中某个成员的 *最小* ``score`` 值作为结果集中该成员的 ``score`` 值;而参数 ``MAX`` 则是将所有集合中某个成员的 *最大* ``score`` 值作为结果集中该成员的 ``score`` 值。 23 | 24 | **可用版本:** 25 | >= 2.0.0 26 | 27 | **时间复杂度:** 28 | O(N)+O(M log(M)), ``N`` 为给定有序集基数的总和, ``M`` 为结果集的基数。 29 | 30 | **返回值:** 31 | 保存到 ``destination`` 的结果集的基数。 32 | 33 | :: 34 | 35 | redis> ZRANGE programmer 0 -1 WITHSCORES 36 | 1) "peter" 37 | 2) "2000" 38 | 3) "jack" 39 | 4) "3500" 40 | 5) "tom" 41 | 6) "5000" 42 | 43 | redis> ZRANGE manager 0 -1 WITHSCORES 44 | 1) "herry" 45 | 2) "2000" 46 | 3) "mary" 47 | 4) "3500" 48 | 5) "bob" 49 | 6) "4000" 50 | 51 | redis> ZUNIONSTORE salary 2 programmer manager WEIGHTS 1 3 # 公司决定加薪。。。除了程序员。。。 52 | (integer) 6 53 | 54 | redis> ZRANGE salary 0 -1 WITHSCORES 55 | 1) "peter" 56 | 2) "2000" 57 | 3) "jack" 58 | 4) "3500" 59 | 5) "tom" 60 | 6) "5000" 61 | 7) "herry" 62 | 8) "6000" 63 | 9) "mary" 64 | 10) "10500" 65 | 11) "bob" 66 | 12) "12000" 67 | -------------------------------------------------------------------------------- /string/append.rst: -------------------------------------------------------------------------------- 1 | .. _append: 2 | 3 | APPEND 4 | ====== 5 | 6 | **APPEND key value** 7 | 8 | 如果 ``key`` 已经存在并且是一个字符串, `APPEND`_ 命令将 ``value`` 追加到 ``key`` 原来的值的末尾。 9 | 10 | 如果 ``key`` 不存在, `APPEND`_ 就简单地将给定 ``key`` 设为 ``value`` ,就像执行 ``SET key value`` 一样。 11 | 12 | **可用版本:** 13 | >= 2.0.0 14 | 15 | **时间复杂度:** 16 | 平摊O(1) 17 | 18 | **返回值:** 19 | 追加 ``value`` 之后, ``key`` 中字符串的长度。 20 | 21 | :: 22 | 23 | # 对不存在的 key 执行 APPEND 24 | 25 | redis> EXISTS myphone # 确保 myphone 不存在 26 | (integer) 0 27 | 28 | redis> APPEND myphone "nokia" # 对不存在的 key 进行 APPEND ,等同于 SET myphone "nokia" 29 | (integer) 5 # 字符长度 30 | 31 | 32 | # 对已存在的字符串进行 APPEND 33 | 34 | redis> APPEND myphone " - 1110" # 长度从 5 个字符增加到 12 个字符 35 | (integer) 12 36 | 37 | redis> GET myphone 38 | "nokia - 1110" 39 | 40 | 模式:时间序列(Time series) 41 | ------------------------------ 42 | 43 | `APPEND`_ 可以为一系列定长(fixed-size)数据(sample)提供一种紧凑的表示方式,通常称之为时间序列。 44 | 45 | 每当一个新数据到达的时候,执行以下命令: 46 | 47 | :: 48 | 49 | APPEND timeseries "fixed-size sample" 50 | 51 | 然后可以通过以下的方式访问时间序列的各项属性: 52 | 53 | - :ref:`STRLEN` 给出时间序列中数据的数量 54 | - :ref:`GETRANGE` 可以用于随机访问。只要有相关的时间信息的话,我们就可以在 Redis 2.6 中使用 Lua 脚本和 :ref:`GETRANGE` 命令实现二分查找。 55 | - :ref:`SETRANGE` 可以用于覆盖或修改已存在的的时间序列。 56 | 57 | 这个模式的唯一缺陷是我们只能增长时间序列,而不能对时间序列进行缩短,因为 Redis 目前还没有对字符串进行修剪(tirm)的命令,但是,不管怎么说,这个模式的储存方式还是可以节省下大量的空间。 58 | 59 | .. note:: 可以考虑使用 UNIX 时间戳作为时间序列的键名,这样一来,可以避免单个 ``key`` 因为保存过大的时间序列而占用大量内存,另一方面,也可以节省下大量命名空间。 60 | 61 | 下面是一个时间序列的例子: 62 | 63 | :: 64 | 65 | redis> APPEND ts "0043" 66 | (integer) 4 67 | 68 | redis> APPEND ts "0035" 69 | (integer) 8 70 | 71 | redis> GETRANGE ts 0 3 72 | "0043" 73 | 74 | redis> GETRANGE ts 4 7 75 | "0035" 76 | -------------------------------------------------------------------------------- /string/bitcount.rst: -------------------------------------------------------------------------------- 1 | .. _bitcount: 2 | 3 | BITCOUNT 4 | =========== 5 | 6 | **BITCOUNT key [start] [end]** 7 | 8 | 计算给定字符串中,被设置为 ``1`` 的比特位的数量。 9 | 10 | 一般情况下,给定的整个字符串都会被进行计数,通过指定额外的 ``start`` 或 ``end`` 参数,可以让计数只在特定的位上进行。 11 | 12 | ``start`` 和 ``end`` 参数的设置和 :ref:`getrange` 命令类似,都可以使用负数值: 13 | 比如 ``-1`` 表示最后一个字节, ``-2`` 表示倒数第二个字节,以此类推。 14 | 15 | 不存在的 ``key`` 被当成是空字符串来处理,因此对一个不存在的 ``key`` 进行 ``BITCOUNT`` 操作,结果为 ``0`` 。 16 | 17 | **可用版本:** 18 | >= 2.6.0 19 | 20 | **时间复杂度:** 21 | O(N) 22 | 23 | **返回值:** 24 | 被设置为 ``1`` 的位的数量。 25 | 26 | :: 27 | 28 | redis> BITCOUNT bits 29 | (integer) 0 30 | 31 | redis> SETBIT bits 0 1 # 0001 32 | (integer) 0 33 | 34 | redis> BITCOUNT bits 35 | (integer) 1 36 | 37 | redis> SETBIT bits 3 1 # 1001 38 | (integer) 0 39 | 40 | redis> BITCOUNT bits 41 | (integer) 2 42 | 43 | 44 | 模式:使用 bitmap 实现用户上线次数统计 45 | ------------------------------------------- 46 | 47 | Bitmap 对于一些特定类型的计算非常有效。 48 | 49 | 假设现在我们希望记录自己网站上的用户的上线频率,比如说,计算用户 A 上线了多少天,用户 B 上线了多少天,诸如此类,以此作为数据,从而决定让哪些用户参加 beta 测试等活动 —— 这个模式可以使用 :ref:`SETBIT` 和 :ref:`BITCOUNT` 来实现。 50 | 51 | 比如说,每当用户在某一天上线的时候,我们就使用 :ref:`SETBIT` ,以用户名作为 ``key`` ,将那天所代表的网站的上线日作为 ``offset`` 参数,并将这个 ``offset`` 上的为设置为 ``1`` 。 52 | 53 | 举个例子,如果今天是网站上线的第 100 天,而用户 peter 在今天阅览过网站,那么执行命令 ``SETBIT peter 100 1`` ;如果明天 peter 也继续阅览网站,那么执行命令 ``SETBIT peter 101 1`` ,以此类推。 54 | 55 | 当要计算 peter 总共以来的上线次数时,就使用 :ref:`BITCOUNT` 命令:执行 ``BITCOUNT peter`` ,得出的结果就是 peter 上线的总天数。 56 | 57 | 更详细的实现可以参考博文(墙外) `Fast, easy, realtime metrics using Redis bitmaps `_ 。 58 | 59 | 60 | 性能 61 | -------- 62 | 63 | 前面的上线次数统计例子,即使运行 10 年,占用的空间也只是每个用户 10*365 比特位(bit),也即是每个用户 456 字节。对于这种大小的数据来说, :ref:`BITCOUNT` 的处理速度就像 :ref:`GET` 和 :ref:`INCR` 这种 O(1) 复杂度的操作一样快。 64 | 65 | 如果你的 bitmap 数据非常大,那么可以考虑使用以下两种方法: 66 | 67 | 1. 将一个大的 bitmap 分散到不同的 key 中,作为小的 bitmap 来处理。使用 Lua 脚本可以很方便地完成这一工作。 68 | 69 | 2. 使用 :ref:`BITCOUNT` 的 ``start`` 和 ``end`` 参数,每次只对所需的部分位进行计算,将位的累积工作(accumulating)放到客户端进行,并且对结果进行缓存 (caching)。 70 | -------------------------------------------------------------------------------- /string/bitop.rst: -------------------------------------------------------------------------------- 1 | .. _bitop: 2 | 3 | BITOP 4 | ======= 5 | 6 | **BITOP operation destkey key [key ...]** 7 | 8 | 对一个或多个保存二进制位的字符串 ``key`` 进行位元操作,并将结果保存到 ``destkey`` 上。 9 | 10 | ``operation`` 可以是 ``AND`` 、 ``OR`` 、 ``NOT`` 、 ``XOR`` 这四种操作中的任意一种: 11 | 12 | - ``BITOP AND destkey key [key ...]`` ,对一个或多个 ``key`` 求逻辑并,并将结果保存到 ``destkey`` 。 13 | 14 | - ``BITOP OR destkey key [key ...]`` ,对一个或多个 ``key`` 求逻辑或,并将结果保存到 ``destkey`` 。 15 | 16 | - ``BITOP XOR destkey key [key ...]`` ,对一个或多个 ``key`` 求逻辑异或,并将结果保存到 ``destkey`` 。 17 | 18 | - ``BITOP NOT destkey key`` ,对给定 ``key`` 求逻辑非,并将结果保存到 ``destkey`` 。 19 | 20 | 除了 ``NOT`` 操作之外,其他操作都可以接受一个或多个 ``key`` 作为输入。 21 | 22 | **处理不同长度的字符串** 23 | 24 | 当 `BITOP`_ 处理不同长度的字符串时,较短的那个字符串所缺少的部分会被看作 ``0`` 。 25 | 26 | 空的 ``key`` 也被看作是包含 ``0`` 的字符串序列。 27 | 28 | **可用版本:** 29 | >= 2.6.0 30 | 31 | **时间复杂度:** 32 | O(N) 33 | 34 | **返回值:** 35 | 保存到 ``destkey`` 的字符串的长度,和输入 ``key`` 中最长的字符串长度相等。 36 | 37 | .. note:: `BITOP`_ 的复杂度为 O(N) ,当处理大型矩阵(matrix)或者进行大数据量的统计时,最好将任务指派到附属节点(slave)进行,避免阻塞主节点。 38 | 39 | :: 40 | 41 | redis> SETBIT bits-1 0 1 # bits-1 = 1001 42 | (integer) 0 43 | 44 | redis> SETBIT bits-1 3 1 45 | (integer) 0 46 | 47 | redis> SETBIT bits-2 0 1 # bits-2 = 1011 48 | (integer) 0 49 | 50 | redis> SETBIT bits-2 1 1 51 | (integer) 0 52 | 53 | redis> SETBIT bits-2 3 1 54 | (integer) 0 55 | 56 | redis> BITOP AND and-result bits-1 bits-2 57 | (integer) 1 58 | 59 | redis> GETBIT and-result 0 # and-result = 1001 60 | (integer) 1 61 | 62 | redis> GETBIT and-result 1 63 | (integer) 0 64 | 65 | redis> GETBIT and-result 2 66 | (integer) 0 67 | 68 | redis> GETBIT and-result 3 69 | (integer) 1 70 | -------------------------------------------------------------------------------- /string/decr.rst: -------------------------------------------------------------------------------- 1 | .. _decr: 2 | 3 | DECR 4 | ===== 5 | 6 | **DECR key** 7 | 8 | 将 ``key`` 中储存的数字值减一。 9 | 10 | 如果 ``key`` 不存在,那么 ``key`` 的值会先被初始化为 ``0`` ,然后再执行 `DECR`_ 操作。 11 | 12 | 如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。 13 | 14 | 本操作的值限制在 64 位(bit)有符号数字表示之内。 15 | 16 | 关于递增(increment) / 递减(decrement)操作的更多信息,请参见 :ref:`INCR` 命令。 17 | 18 | **可用版本:** 19 | >= 1.0.0 20 | 21 | **时间复杂度:** 22 | O(1) 23 | 24 | **返回值:** 25 | 执行 `DECR`_ 命令之后 ``key`` 的值。 26 | 27 | :: 28 | 29 | # 对存在的数字值 key 进行 DECR 30 | 31 | redis> SET failure_times 10 32 | OK 33 | 34 | redis> DECR failure_times 35 | (integer) 9 36 | 37 | 38 | # 对不存在的 key 值进行 DECR 39 | 40 | redis> EXISTS count 41 | (integer) 0 42 | 43 | redis> DECR count 44 | (integer) -1 45 | 46 | 47 | # 对存在但不是数值的 key 进行 DECR 48 | 49 | redis> SET company YOUR_CODE_SUCKS.LLC 50 | OK 51 | 52 | redis> DECR company 53 | (error) ERR value is not an integer or out of range 54 | -------------------------------------------------------------------------------- /string/decrby.rst: -------------------------------------------------------------------------------- 1 | .. _decrby: 2 | 3 | DECRBY 4 | ======= 5 | 6 | **DECRBY key decrement** 7 | 8 | 将 ``key`` 所储存的值减去减量 ``decrement`` 。 9 | 10 | 如果 ``key`` 不存在,那么 ``key`` 的值会先被初始化为 ``0`` ,然后再执行 `DECRBY`_ 操作。 11 | 12 | 如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。 13 | 14 | 本操作的值限制在 64 位(bit)有符号数字表示之内。 15 | 16 | 关于更多递增(increment) / 递减(decrement)操作的更多信息,请参见 :ref:`INCR` 命令。 17 | 18 | **可用版本:** 19 | >= 1.0.0 20 | 21 | **时间复杂度:** 22 | O(1) 23 | 24 | **返回值:** 25 | 减去 ``decrement`` 之后, ``key`` 的值。 26 | 27 | :: 28 | 29 | # 对已存在的 key 进行 DECRBY 30 | 31 | redis> SET count 100 32 | OK 33 | 34 | redis> DECRBY count 20 35 | (integer) 80 36 | 37 | 38 | # 对不存在的 key 进行DECRBY 39 | 40 | redis> EXISTS pages 41 | (integer) 0 42 | 43 | redis> DECRBY pages 10 44 | (integer) -10 45 | -------------------------------------------------------------------------------- /string/get.rst: -------------------------------------------------------------------------------- 1 | .. _get: 2 | 3 | GET 4 | ==== 5 | 6 | **GET key** 7 | 8 | 返回 ``key`` 所关联的字符串值。 9 | 10 | 如果 ``key`` 不存在那么返回特殊值 ``nil`` 。 11 | 12 | 假如 ``key`` 储存的值不是字符串类型,返回一个错误,因为 `GET`_ 只能用于处理字符串值。 13 | 14 | **可用版本:** 15 | >= 1.0.0 16 | 17 | **时间复杂度:** 18 | O(1) 19 | 20 | **返回值:** 21 | | 当 ``key`` 不存在时,返回 ``nil`` ,否则,返回 ``key`` 的值。 22 | | 如果 ``key`` 不是字符串类型,那么返回一个错误。 23 | 24 | :: 25 | 26 | # 对不存在的 key 或字符串类型 key 进行 GET 27 | 28 | redis> GET db 29 | (nil) 30 | 31 | redis> SET db redis 32 | OK 33 | 34 | redis> GET db 35 | "redis" 36 | 37 | 38 | # 对不是字符串类型的 key 进行 GET 39 | 40 | redis> DEL db 41 | (integer) 1 42 | 43 | redis> LPUSH db redis mongodb mysql 44 | (integer) 3 45 | 46 | redis> GET db 47 | (error) ERR Operation against a key holding the wrong kind of value 48 | -------------------------------------------------------------------------------- /string/getbit.rst: -------------------------------------------------------------------------------- 1 | .. _getbit: 2 | 3 | GETBIT 4 | ====== 5 | 6 | **GETBIT key offset** 7 | 8 | 对 ``key`` 所储存的字符串值,获取指定偏移量上的位(bit)。 9 | 10 | 当 ``offset`` 比字符串值的长度大,或者 ``key`` 不存在时,返回 ``0`` 。 11 | 12 | **可用版本:** 13 | >= 2.2.0 14 | 15 | **时间复杂度:** 16 | O(1) 17 | 18 | **返回值:** 19 | 字符串值指定偏移量上的位(bit)。 20 | 21 | :: 22 | 23 | # 对不存在的 key 或者不存在的 offset 进行 GETBIT, 返回 0 24 | 25 | redis> EXISTS bit 26 | (integer) 0 27 | 28 | redis> GETBIT bit 10086 29 | (integer) 0 30 | 31 | 32 | # 对已存在的 offset 进行 GETBIT 33 | 34 | redis> SETBIT bit 10086 1 35 | (integer) 0 36 | 37 | redis> GETBIT bit 10086 38 | (integer) 1 39 | -------------------------------------------------------------------------------- /string/getrange.rst: -------------------------------------------------------------------------------- 1 | .. _getrange: 2 | 3 | GETRANGE 4 | ========= 5 | 6 | **GETRANGE key start end** 7 | 8 | 返回 ``key`` 中字符串值的子字符串,字符串的截取范围由 ``start`` 和 ``end`` 两个偏移量决定(包括 ``start`` 和 ``end`` 在内)。 9 | 10 | 负数偏移量表示从字符串最后开始计数, ``-1`` 表示最后一个字符, ``-2`` 表示倒数第二个,以此类推。 11 | 12 | `GETRANGE`_ 通过保证子字符串的值域(range)不超过实际字符串的值域来处理超出范围的值域请求。 13 | 14 | .. note:: 15 | 在 <= 2.0 的版本里,GETRANGE 被叫作 SUBSTR。 16 | 17 | **可用版本:** 18 | >= 2.4.0 19 | 20 | **时间复杂度:** 21 | | O(N), ``N`` 为要返回的字符串的长度。 22 | | 复杂度最终由字符串的返回值长度决定,但因为从已有字符串中取出子字符串的操作非常廉价(cheap),所以对于长度不大的字符串,该操作的复杂度也可看作O(1)。 23 | 24 | **返回值:** 25 | 截取得出的子字符串。 26 | 27 | :: 28 | 29 | redis> SET greeting "hello, my friend" 30 | OK 31 | 32 | redis> GETRANGE greeting 0 4 # 返回索引0-4的字符,包括4。 33 | "hello" 34 | 35 | redis> GETRANGE greeting -1 -5 # 不支持回绕操作 36 | "" 37 | 38 | redis> GETRANGE greeting -3 -1 # 负数索引 39 | "end" 40 | 41 | redis> GETRANGE greeting 0 -1 # 从第一个到最后一个 42 | "hello, my friend" 43 | 44 | redis> GETRANGE greeting 0 1008611 # 值域范围不超过实际字符串,超过部分自动被符略 45 | "hello, my friend" 46 | -------------------------------------------------------------------------------- /string/getset.rst: -------------------------------------------------------------------------------- 1 | .. _getset: 2 | 3 | GETSET 4 | ======== 5 | 6 | **GETSET key value** 7 | 8 | 将给定 ``key`` 的值设为 ``value`` ,并返回 ``key`` 的旧值(old value)。 9 | 10 | 当 ``key`` 存在但不是字符串类型时,返回一个错误。 11 | 12 | **可用版本:** 13 | >= 1.0.0 14 | 15 | **时间复杂度:** 16 | O(1) 17 | 18 | **返回值:** 19 | | 返回给定 ``key`` 的旧值。 20 | | 当 ``key`` 没有旧值时,也即是, ``key`` 不存在时,返回 ``nil`` 。 21 | 22 | :: 23 | 24 | redis> GETSET db mongodb # 没有旧值,返回 nil 25 | (nil) 26 | 27 | redis> GET db 28 | "mongodb" 29 | 30 | redis> GETSET db redis # 返回旧值 mongodb 31 | "mongodb" 32 | 33 | redis> GET db 34 | "redis" 35 | 36 | 模式 37 | -------- 38 | 39 | `GETSET`_ 可以和 :ref:`INCR` 组合使用,实现一个有原子性(atomic)复位操作的计数器(counter)。 40 | 41 | 举例来说,每次当某个事件发生时,进程可能对一个名为 ``mycount`` 的 ``key`` 调用 :ref:`INCR` 操作,通常我们还要在一个原子时间内同时完成获得计数器的值和将计数器值复位为 ``0`` 两个操作。 42 | 43 | 可以用命令 ``GETSET mycounter 0`` 来实现这一目标。 44 | 45 | :: 46 | 47 | redis> INCR mycount 48 | (integer) 11 49 | 50 | redis> GETSET mycount 0 # 一个原子内完成 GET mycount 和 SET mycount 0 操作 51 | "11" 52 | 53 | redis> GET mycount # 计数器被重置 54 | "0" 55 | -------------------------------------------------------------------------------- /string/incr.rst: -------------------------------------------------------------------------------- 1 | .. _incr: 2 | 3 | INCR 4 | ===== 5 | 6 | **INCR key** 7 | 8 | 将 ``key`` 中储存的数字值增一。 9 | 10 | 如果 ``key`` 不存在,那么 ``key`` 的值会先被初始化为 ``0`` ,然后再执行 `INCR`_ 操作。 11 | 12 | 如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。 13 | 14 | 本操作的值限制在 64 位(bit)有符号数字表示之内。 15 | 16 | .. note:: 17 | 这是一个针对字符串的操作,因为 Redis 没有专用的整数类型,所以 key 内储存的字符串被解释为十进制 64 位有符号整数来执行 INCR 操作。 18 | 19 | **可用版本:** 20 | >= 1.0.0 21 | 22 | **时间复杂度:** 23 | O(1) 24 | 25 | **返回值:** 26 | 执行 `INCR`_ 命令之后 ``key`` 的值。 27 | 28 | :: 29 | 30 | redis> SET page_view 20 31 | OK 32 | 33 | redis> INCR page_view 34 | (integer) 21 35 | 36 | redis> GET page_view # 数字值在 Redis 中以字符串的形式保存 37 | "21" 38 | 39 | 模式:计数器 40 | --------------- 41 | 42 | 计数器是 Redis 的原子性自增操作可实现的最直观的模式了,它的想法相当简单:每当某个操作发生时,向 Redis 发送一个 `INCR`_ 命令。 43 | 44 | 比如在一个 web 应用程序中,如果想知道用户在一年中每天的点击量,那么只要将用户 ID 以及相关的日期信息作为键,并在每次用户点击页面时,执行一次自增操作即可。 45 | 46 | 比如用户名是 ``peter`` ,点击时间是 2012 年 3 月 22 日,那么执行命令 ``INCR peter::2012.3.22`` 。 47 | 48 | 可以用以下几种方式扩展这个简单的模式: 49 | 50 | - 可以通过组合使用 `INCR`_ 和 :ref:`expire` ,来达到只在规定的生存时间内进行计数(counting)的目的。 51 | - 客户端可以通过使用 :ref:`GETSET` 命令原子性地获取计数器的当前值并将计数器清零,更多信息请参考 :ref:`GETSET` 命令。 52 | - 使用其他自增/自减操作,比如 :ref:`DECR` 和 :ref:`INCRBY` ,用户可以通过执行不同的操作增加或减少计数器的值,比如在游戏中的记分器就可能用到这些命令。 53 | 54 | 模式:限速器 55 | ------------- 56 | 57 | 限速器是特殊化的计算器,它用于限制一个操作可以被执行的速率(rate)。 58 | 59 | 限速器的典型用法是限制公开 API 的请求次数,以下是一个限速器实现示例,它将 API 的最大请求数限制在每个 IP 地址每秒钟十个之内: 60 | 61 | :: 62 | 63 | FUNCTION LIMIT_API_CALL(ip) 64 | ts = CURRENT_UNIX_TIME() 65 | keyname = ip+":"+ts 66 | current = GET(keyname) 67 | 68 | IF current != NULL AND current > 10 THEN 69 | ERROR "too many requests per second" 70 | END 71 | 72 | IF current == NULL THEN 73 | MULTI 74 | INCR(keyname, 1) 75 | EXPIRE(keyname, 1) 76 | EXEC 77 | ELSE 78 | INCR(keyname, 1) 79 | END 80 | 81 | PERFORM_API_CALL() 82 | 83 | 这个实现每秒钟为每个 IP 地址使用一个不同的计数器,并用 :ref:`EXPIRE` 命令设置生存时间(这样 Redis 就会负责自动删除过期的计数器)。 84 | 85 | 注意,我们使用事务打包执行 :ref:`INCR` 命令和 :ref:`EXPIRE` 命令,避免引入竞争条件,保证每次调用 API 时都可以正确地对计数器进行自增操作并设置生存时间。 86 | 87 | 以下是另一个限速器实现: 88 | 89 | :: 90 | 91 | FUNCTION LIMIT_API_CALL(ip): 92 | current = GET(ip) 93 | IF current != NULL AND current > 10 THEN 94 | ERROR "too many requests per second" 95 | ELSE 96 | value = INCR(ip) 97 | IF value == 1 THEN 98 | EXPIRE(ip,1) 99 | END 100 | PERFORM_API_CALL() 101 | END 102 | 103 | 这个限速器只使用单个计数器,它的生存时间为一秒钟,如果在一秒钟内,这个计数器的值大于 ``10`` 的话,那么访问就会被禁止。 104 | 105 | 这个新的限速器在思路方面是没有问题的,但它在实现方面不够严谨,如果我们仔细观察一下的话,就会发现在 :ref:`INCR` 和 :ref:`EXPIRE` 之间存在着一个竞争条件,假如客户端在执行 :ref:`INCR` 之后,因为某些原因(比如客户端失败)而忘记设置 :ref:`EXPIRE` 的话,那么这个计数器就会一直存在下去,造成每个用户只能访问 ``10`` 次,噢,这简直是个灾难! 106 | 107 | 要消灭这个实现中的竞争条件,我们可以将它转化为一个 Lua 脚本,并放到 Redis 中运行(这个方法仅限于 Redis 2.6 及以上的版本): 108 | 109 | :: 110 | 111 | local current 112 | current = redis.call("incr",KEYS[1]) 113 | if tonumber(current) == 1 then 114 | redis.call("expire",KEYS[1],1) 115 | end 116 | 117 | 通过将计数器作为脚本放到 Redis 上运行,我们保证了 :ref:`INCR` 和 :ref:`EXPIRE` 两个操作的原子性,现在这个脚本实现不会引入竞争条件,它可以运作的很好。 118 | 119 | 关于在 Redis 中运行 Lua 脚本的更多信息,请参考 :ref:`EVAL` 命令。 120 | 121 | 还有另一种消灭竞争条件的方法,就是使用 Redis 的列表结构来代替 :ref:`INCR` 命令,这个方法无须脚本支持,因此它在 Redis 2.6 以下的版本也可以运行得很好: 122 | 123 | :: 124 | 125 | FUNCTION LIMIT_API_CALL(ip) 126 | current = LLEN(ip) 127 | IF current > 10 THEN 128 | ERROR "too many requests per second" 129 | ELSE 130 | IF EXISTS(ip) == FALSE 131 | MULTI 132 | RPUSH(ip,ip) 133 | EXPIRE(ip,1) 134 | EXEC 135 | ELSE 136 | RPUSHX(ip,ip) 137 | END 138 | PERFORM_API_CALL() 139 | END 140 | 141 | 新的限速器使用了列表结构作为容器, :ref:`LLEN` 用于对访问次数进行检查,一个事务包裹着 :ref:`RPUSH` 和 :ref:`EXPIRE` 两个命令,用于在第一次执行计数时创建列表,并正确设置地设置过期时间,最后, :ref:`RPUSHX` 在后续的计数操作中进行增加操作。 142 | -------------------------------------------------------------------------------- /string/incrby.rst: -------------------------------------------------------------------------------- 1 | .. _incrby: 2 | 3 | INCRBY 4 | ====== 5 | 6 | **INCRBY key increment** 7 | 8 | 将 ``key`` 所储存的值加上增量 ``increment`` 。 9 | 10 | 如果 ``key`` 不存在,那么 ``key`` 的值会先被初始化为 ``0`` ,然后再执行 `INCRBY`_ 命令。 11 | 12 | 如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。 13 | 14 | 本操作的值限制在 64 位(bit)有符号数字表示之内。 15 | 16 | 关于递增(increment) / 递减(decrement)操作的更多信息,参见 :ref:`INCR` 命令。 17 | 18 | **可用版本:** 19 | >= 1.0.0 20 | 21 | **时间复杂度:** 22 | O(1) 23 | 24 | **返回值:** 25 | 加上 ``increment`` 之后, ``key`` 的值。 26 | 27 | :: 28 | 29 | # key 存在且是数字值 30 | 31 | redis> SET rank 50 32 | OK 33 | 34 | redis> INCRBY rank 20 35 | (integer) 70 36 | 37 | redis> GET rank 38 | "70" 39 | 40 | 41 | # key 不存在时 42 | 43 | redis> EXISTS counter 44 | (integer) 0 45 | 46 | redis> INCRBY counter 30 47 | (integer) 30 48 | 49 | redis> GET counter 50 | "30" 51 | 52 | 53 | # key 不是数字值时 54 | 55 | redis> SET book "long long ago..." 56 | OK 57 | 58 | redis> INCRBY book 200 59 | (error) ERR value is not an integer or out of range 60 | -------------------------------------------------------------------------------- /string/incrbyfloat.rst: -------------------------------------------------------------------------------- 1 | .. _incrbyfloat: 2 | 3 | INCRBYFLOAT 4 | =============== 5 | 6 | **INCRBYFLOAT key increment** 7 | 8 | 为 ``key`` 中所储存的值加上浮点数增量 ``increment`` 。 9 | 10 | 如果 ``key`` 不存在,那么 `INCRBYFLOAT`_ 会先将 ``key`` 的值设为 ``0`` ,再执行加法操作。 11 | 12 | 如果命令执行成功,那么 ``key`` 的值会被更新为(执行加法之后的)新值,并且新值会以字符串的形式返回给调用者。 13 | 14 | 无论是 ``key`` 的值,还是增量 ``increment`` ,都可以使用像 ``2.0e7`` 、 ``3e5`` 、 ``90e-2`` 那样的指数符号(exponential notation)来表示,但是,\ **执行 INCRBYFLOAT 命令之后的值**\ 总是以同样的形式储存,也即是,它们总是由一个数字,一个(可选的)小数点和一个任意位的小数部分组成(比如 ``3.14`` 、 ``69.768`` ,诸如此类),小数部分尾随的 ``0`` 会被移除,如果有需要的话,还会将浮点数改为整数(比如 ``3.0`` 会被保存成 ``3`` )。 15 | 16 | 除此之外,无论加法计算所得的浮点数的实际精度有多长, `INCRBYFLOAT`_ 的计算结果也最多只能表示小数点的后十七位。 17 | 18 | 当以下任意一个条件发生时,返回一个错误: 19 | 20 | - ``key`` 的值不是字符串类型(因为 Redis 中的数字和浮点数都以字符串的形式保存,所以它们都属于字符串类型) 21 | - ``key`` 当前的值或者给定的增量 ``increment`` 不能解释(parse)为双精度浮点数(double precision floating point number) 22 | 23 | **可用版本:** 24 | >= 2.6.0 25 | 26 | **时间复杂度:** 27 | O(1) 28 | 29 | **返回值:** 30 | 执行命令之后 ``key`` 的值。 31 | 32 | :: 33 | 34 | # 值和增量都不是指数符号 35 | 36 | redis> SET mykey 10.50 37 | OK 38 | 39 | redis> INCRBYFLOAT mykey 0.1 40 | "10.6" 41 | 42 | 43 | # 值和增量都是指数符号 44 | 45 | redis> SET mykey 314e-2 46 | OK 47 | 48 | redis> GET mykey # 用 SET 设置的值可以是指数符号 49 | "314e-2" 50 | 51 | redis> INCRBYFLOAT mykey 0 # 但执行 INCRBYFLOAT 之后格式会被改成非指数符号 52 | "3.14" 53 | 54 | 55 | # 可以对整数类型执行 56 | 57 | redis> SET mykey 3 58 | OK 59 | 60 | redis> INCRBYFLOAT mykey 1.1 61 | "4.1" 62 | 63 | 64 | # 后跟的 0 会被移除 65 | 66 | redis> SET mykey 3.0 67 | OK 68 | 69 | redis> GET mykey # SET 设置的值小数部分可以是 0 70 | "3.0" 71 | 72 | redis> INCRBYFLOAT mykey 1.000000000000000000000 # 但 INCRBYFLOAT 会将无用的 0 忽略掉,有需要的话,将浮点变为整数 73 | "4" 74 | 75 | redis> GET mykey 76 | "4" 77 | -------------------------------------------------------------------------------- /string/index.rst: -------------------------------------------------------------------------------- 1 | String(字符串) 2 | =================== 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | 7 | append 8 | bitcount 9 | bitop 10 | decr 11 | decrby 12 | get 13 | getbit 14 | getrange 15 | getset 16 | incr 17 | incrby 18 | incrbyfloat 19 | mget 20 | mset 21 | msetnx 22 | psetex 23 | set 24 | setbit 25 | setex 26 | setnx 27 | setrange 28 | strlen 29 | -------------------------------------------------------------------------------- /string/mget.rst: -------------------------------------------------------------------------------- 1 | .. _mget: 2 | 3 | MGET 4 | ===== 5 | 6 | **MGET key [key ...]** 7 | 8 | 返回所有(一个或多个)给定 ``key`` 的值。 9 | 10 | 如果给定的 ``key`` 里面,有某个 ``key`` 不存在,那么这个 ``key`` 返回特殊值 ``nil`` 。因此,该命令永不失败。 11 | 12 | **可用版本:** 13 | >= 1.0.0 14 | 15 | **时间复杂度:** 16 | O(N) , ``N`` 为给定 ``key`` 的数量。 17 | 18 | **返回值:** 19 | 一个包含所有给定 ``key`` 的值的列表。 20 | 21 | :: 22 | 23 | redis> SET redis redis.com 24 | OK 25 | 26 | redis> SET mongodb mongodb.org 27 | OK 28 | 29 | redis> MGET redis mongodb 30 | 1) "redis.com" 31 | 2) "mongodb.org" 32 | 33 | redis> MGET redis mongodb mysql # 不存在的 mysql 返回 nil 34 | 1) "redis.com" 35 | 2) "mongodb.org" 36 | 3) (nil) 37 | -------------------------------------------------------------------------------- /string/mset.rst: -------------------------------------------------------------------------------- 1 | .. _mset: 2 | 3 | MSET 4 | ===== 5 | 6 | **MSET key value [key value ...]** 7 | 8 | 同时设置一个或多个 ``key-value`` 对。 9 | 10 | 如果某个给定 ``key`` 已经存在,那么 `MSET`_ 会用新值覆盖原来的旧值,如果这不是你所希望的效果,请考虑使用 :ref:`MSETNX` 命令:它只会在所有给定 ``key`` 都不存在的情况下进行设置操作。 11 | 12 | `MSET`_ 是一个原子性(atomic)操作,所有给定 ``key`` 都会在同一时间内被设置,某些给定 ``key`` 被更新而另一些给定 ``key`` 没有改变的情况,不可能发生。 13 | 14 | **可用版本:** 15 | >= 1.0.1 16 | 17 | **时间复杂度:** 18 | O(N), ``N`` 为要设置的 ``key`` 数量。 19 | 20 | **返回值:** 21 | 总是返回 ``OK`` (因为 ``MSET`` 不可能失败) 22 | 23 | :: 24 | 25 | redis> MSET date "2012.3.30" time "11:00 a.m." weather "sunny" 26 | OK 27 | 28 | redis> MGET date time weather 29 | 1) "2012.3.30" 30 | 2) "11:00 a.m." 31 | 3) "sunny" 32 | 33 | 34 | # MSET 覆盖旧值例子 35 | 36 | redis> SET google "google.hk" 37 | OK 38 | 39 | redis> MSET google "google.com" 40 | OK 41 | 42 | redis> GET google 43 | "google.com" 44 | -------------------------------------------------------------------------------- /string/msetnx.rst: -------------------------------------------------------------------------------- 1 | .. _msetnx: 2 | 3 | MSETNX 4 | ======== 5 | 6 | **MSETNX key value [key value ...]** 7 | 8 | 同时设置一个或多个 ``key-value`` 对,当且仅当所有给定 ``key`` 都不存在。 9 | 10 | 即使只有一个给定 ``key`` 已存在, `MSETNX`_ 也会拒绝执行所有给定 ``key`` 的设置操作。 11 | 12 | `MSETNX`_ 是原子性的,因此它可以用作设置多个不同 ``key`` 表示不同字段(field)的唯一性逻辑对象(unique logic object),所有字段要么全被设置,要么全不被设置。 13 | 14 | **可用版本:** 15 | >= 1.0.1 16 | 17 | **时间复杂度:** 18 | O(N), ``N`` 为要设置的 ``key`` 的数量。 19 | 20 | **返回值:** 21 | | 当所有 ``key`` 都成功设置,返回 ``1`` 。 22 | | 如果所有给定 ``key`` 都设置失败(至少有一个 ``key`` 已经存在),那么返回 ``0`` 。 23 | 24 | :: 25 | 26 | # 对不存在的 key 进行 MSETNX 27 | 28 | redis> MSETNX rmdbs "MySQL" nosql "MongoDB" key-value-store "redis" 29 | (integer) 1 30 | 31 | redis> MGET rmdbs nosql key-value-store 32 | 1) "MySQL" 33 | 2) "MongoDB" 34 | 3) "redis" 35 | 36 | 37 | # MSET 的给定 key 当中有已存在的 key 38 | 39 | redis> MSETNX rmdbs "Sqlite" language "python" # rmdbs 键已经存在,操作失败 40 | (integer) 0 41 | 42 | redis> EXISTS language # 因为 MSET 是原子性操作,language 没有被设置 43 | (integer) 0 44 | 45 | redis> GET rmdbs # rmdbs 也没有被修改 46 | "MySQL" 47 | -------------------------------------------------------------------------------- /string/psetex.rst: -------------------------------------------------------------------------------- 1 | .. _psetex: 2 | 3 | PSETEX 4 | ========== 5 | 6 | **PSETEX key milliseconds value** 7 | 8 | 这个命令和 :ref:`SETEX` 命令相似,但它以毫秒为单位设置 ``key`` 的生存时间,而不是像 :ref:`SETEX` 命令那样,以秒为单位。 9 | 10 | **可用版本:** 11 | >= 2.6.0 12 | 13 | **时间复杂度:** 14 | O(1) 15 | 16 | **返回值:** 17 | 设置成功时返回 ``OK`` 。 18 | 19 | :: 20 | 21 | redis> PSETEX mykey 1000 "Hello" 22 | OK 23 | 24 | redis> PTTL mykey 25 | (integer) 999 26 | 27 | redis> GET mykey 28 | "Hello" 29 | -------------------------------------------------------------------------------- /string/set.rst: -------------------------------------------------------------------------------- 1 | .. _set: 2 | 3 | SET 4 | ==== 5 | 6 | **SET key value [EX seconds] [PX milliseconds] [NX|XX]** 7 | 8 | 将字符串值 ``value`` 关联到 ``key`` 。 9 | 10 | 如果 ``key`` 已经持有其他值, `SET`_ 就覆写旧值,无视类型。 11 | 12 | 对于某个原本带有生存时间(TTL)的键来说, 13 | 当 :ref:`SET` 命令成功在这个键上执行时, 14 | 这个键原有的 TTL 将被清除。 15 | 16 | **可选参数** 17 | 18 | 从 Redis 2.6.12 版本开始, :ref:`SET` 命令的行为可以通过一系列参数来修改: 19 | 20 | - ``EX second`` :设置键的过期时间为 ``second`` 秒。 ``SET key value EX second`` 效果等同于 ``SETEX key second value`` 。 21 | 22 | - ``PX millisecond`` :设置键的过期时间为 ``millisecond`` 毫秒。 ``SET key value PX millisecond`` 效果等同于 ``PSETEX key millisecond value`` 。 23 | 24 | - ``NX`` :只在键不存在时,才对键进行设置操作。 ``SET key value NX`` 效果等同于 ``SETNX key value`` 。 25 | 26 | - ``XX`` :只在键已经存在时,才对键进行设置操作。 27 | 28 | .. note:: 因为 :ref:`SET` 命令可以通过参数来实现和 :ref:`SETNX` 、 :ref:`SETEX` 和 :ref:`PSETEX` 三个命令的效果,所以将来的 Redis 版本可能会废弃并最终移除 :ref:`SETNX` 、 :ref:`SETEX` 和 :ref:`PSETEX` 这三个命令。 29 | 30 | **可用版本:** 31 | >= 1.0.0 32 | 33 | **时间复杂度:** 34 | O(1) 35 | 36 | **返回值:** 37 | 在 Redis 2.6.12 版本以前, :ref:`SET` 命令总是返回 ``OK`` 。 38 | 39 | | 从 Redis 2.6.12 版本开始, :ref:`SET` 在设置操作成功完成时,才返回 ``OK`` 。 40 | | 如果设置了 ``NX`` 或者 ``XX`` ,但因为条件没达到而造成设置操作未执行,那么命令返回空批量回复(NULL Bulk Reply)。 41 | 42 | 43 | :: 44 | 45 | # 对不存在的键进行设置 46 | 47 | redis 127.0.0.1:6379> SET key "value" 48 | OK 49 | 50 | redis 127.0.0.1:6379> GET key 51 | "value" 52 | 53 | 54 | # 对已存在的键进行设置 55 | 56 | redis 127.0.0.1:6379> SET key "new-value" 57 | OK 58 | 59 | redis 127.0.0.1:6379> GET key 60 | "new-value" 61 | 62 | 63 | # 使用 EX 选项 64 | 65 | redis 127.0.0.1:6379> SET key-with-expire-time "hello" EX 10086 66 | OK 67 | 68 | redis 127.0.0.1:6379> GET key-with-expire-time 69 | "hello" 70 | 71 | redis 127.0.0.1:6379> TTL key-with-expire-time 72 | (integer) 10069 73 | 74 | 75 | # 使用 PX 选项 76 | 77 | redis 127.0.0.1:6379> SET key-with-pexpire-time "moto" PX 123321 78 | OK 79 | 80 | redis 127.0.0.1:6379> GET key-with-pexpire-time 81 | "moto" 82 | 83 | redis 127.0.0.1:6379> PTTL key-with-pexpire-time 84 | (integer) 111939 85 | 86 | 87 | # 使用 NX 选项 88 | 89 | redis 127.0.0.1:6379> SET not-exists-key "value" NX 90 | OK # 键不存在,设置成功 91 | 92 | redis 127.0.0.1:6379> GET not-exists-key 93 | "value" 94 | 95 | redis 127.0.0.1:6379> SET not-exists-key "new-value" NX 96 | (nil) # 键已经存在,设置失败 97 | 98 | redis 127.0.0.1:6379> GEt not-exists-key 99 | "value" # 维持原值不变 100 | 101 | 102 | # 使用 XX 选项 103 | 104 | redis 127.0.0.1:6379> EXISTS exists-key 105 | (integer) 0 106 | 107 | redis 127.0.0.1:6379> SET exists-key "value" XX 108 | (nil) # 因为键不存在,设置失败 109 | 110 | redis 127.0.0.1:6379> SET exists-key "value" 111 | OK # 先给键设置一个值 112 | 113 | redis 127.0.0.1:6379> SET exists-key "new-value" XX 114 | OK # 设置新值成功 115 | 116 | redis 127.0.0.1:6379> GET exists-key 117 | "new-value" 118 | 119 | 120 | # NX 或 XX 可以和 EX 或者 PX 组合使用 121 | 122 | redis 127.0.0.1:6379> SET key-with-expire-and-NX "hello" EX 10086 NX 123 | OK 124 | 125 | redis 127.0.0.1:6379> GET key-with-expire-and-NX 126 | "hello" 127 | 128 | redis 127.0.0.1:6379> TTL key-with-expire-and-NX 129 | (integer) 10063 130 | 131 | redis 127.0.0.1:6379> SET key-with-pexpire-and-XX "old value" 132 | OK 133 | 134 | redis 127.0.0.1:6379> SET key-with-pexpire-and-XX "new value" PX 123321 135 | OK 136 | 137 | redis 127.0.0.1:6379> GET key-with-pexpire-and-XX 138 | "new value" 139 | 140 | redis 127.0.0.1:6379> PTTL key-with-pexpire-and-XX 141 | (integer) 112999 142 | 143 | 144 | # EX 和 PX 可以同时出现,但后面给出的选项会覆盖前面给出的选项 145 | 146 | redis 127.0.0.1:6379> SET key "value" EX 1000 PX 5000000 147 | OK 148 | 149 | redis 127.0.0.1:6379> TTL key 150 | (integer) 4993 # 这是 PX 参数设置的值 151 | 152 | redis 127.0.0.1:6379> SET another-key "value" PX 5000000 EX 1000 153 | OK 154 | 155 | redis 127.0.0.1:6379> TTL another-key 156 | (integer) 997 # 这是 EX 参数设置的值 157 | 158 | 159 | 160 | 161 | 使用模式 162 | --------------- 163 | 164 | 命令 ``SET resource-name anystring NX EX max-lock-time`` 是一种在 Redis 中实现锁的简单方法。 165 | 166 | 客户端执行以上的命令: 167 | 168 | - 如果服务器返回 ``OK`` ,那么这个客户端获得锁。 169 | 170 | - 如果服务器返回 ``NIL`` ,那么客户端获取锁失败,可以在稍后再重试。 171 | 172 | 设置的过期时间到达之后,锁将自动释放。 173 | 174 | 可以通过以下修改,让这个锁实现更健壮: 175 | 176 | - 不使用固定的字符串作为键的值,而是设置一个不可猜测(non-guessable)的长随机字符串,作为口令串(token)。 177 | 178 | - 不使用 :ref:`DEL` 命令来释放锁,而是发送一个 Lua 脚本,这个脚本只在客户端传入的值和键的口令串相匹配时,才对键进行删除。 179 | 180 | 这两个改动可以防止持有过期锁的客户端误删现有锁的情况出现。 181 | 182 | 以下是一个简单的解锁脚本示例: 183 | 184 | .. code-block:: lua 185 | 186 | if redis.call("get",KEYS[1]) == ARGV[1] 187 | then 188 | return redis.call("del",KEYS[1]) 189 | else 190 | return 0 191 | end 192 | 193 | 这个脚本可以通过 ``EVAL ...script... 1 resource-name token-value`` 命令来调用。 194 | -------------------------------------------------------------------------------- /string/setbit.rst: -------------------------------------------------------------------------------- 1 | .. _setbit: 2 | 3 | SETBIT 4 | ======= 5 | 6 | **SETBIT key offset value** 7 | 8 | 对 ``key`` 所储存的字符串值,设置或清除指定偏移量上的位(bit)。 9 | 10 | 位的设置或清除取决于 ``value`` 参数,可以是 ``0`` 也可以是 ``1`` 。 11 | 12 | 当 ``key`` 不存在时,自动生成一个新的字符串值。 13 | 14 | 字符串会进行伸展(grown)以确保它可以将 ``value`` 保存在指定的偏移量上。当字符串值进行伸展时,空白位置以 ``0`` 填充。 15 | 16 | ``offset`` 参数必须大于或等于 ``0`` ,小于 2^32 (bit 映射被限制在 512 MB 之内)。 17 | 18 | .. warning:: 对使用大的 ``offset`` 的 `SETBIT`_ 操作来说,内存分配可能造成 Redis 服务器被阻塞。具体参考 :ref:`SETRANGE` 命令,warning(警告)部分。 19 | 20 | **可用版本:** 21 | >= 2.2.0 22 | 23 | **时间复杂度:** 24 | O(1) 25 | 26 | **返回值:** 27 | 指定偏移量原来储存的位。 28 | 29 | :: 30 | 31 | redis> SETBIT bit 10086 1 32 | (integer) 0 33 | 34 | redis> GETBIT bit 10086 35 | (integer) 1 36 | 37 | redis> GETBIT bit 100 # bit 默认被初始化为 0 38 | (integer) 0 39 | -------------------------------------------------------------------------------- /string/setex.rst: -------------------------------------------------------------------------------- 1 | .. _setex: 2 | 3 | SETEX 4 | ====== 5 | 6 | **SETEX key seconds value** 7 | 8 | 将值 ``value`` 关联到 ``key`` ,并将 ``key`` 的生存时间设为 ``seconds`` (以秒为单位)。 9 | 10 | 如果 ``key`` \ 已经存在, `SETEX`_ 命令将覆写旧值。 11 | 12 | 这个命令类似于以下两个命令: 13 | 14 | :: 15 | 16 | SET key value 17 | EXPIRE key seconds # 设置生存时间 18 | 19 | 不同之处是, `SETEX`_ 是一个原子性(atomic)操作,关联值和设置生存时间两个动作会在同一时间内完成,该命令在 Redis 用作缓存时,非常实用。 20 | 21 | **可用版本:** 22 | >= 2.0.0 23 | 24 | **时间复杂度:** 25 | O(1) 26 | 27 | **返回值:** 28 | | 设置成功时返回 ``OK`` 。 29 | | 当 ``seconds`` 参数不合法时,返回一个错误。 30 | 31 | :: 32 | 33 | # 在 key 不存在时进行 SETEX 34 | 35 | redis> SETEX cache_user_id 60 10086 36 | OK 37 | 38 | redis> GET cache_user_id # 值 39 | "10086" 40 | 41 | redis> TTL cache_user_id # 剩余生存时间 42 | (integer) 49 43 | 44 | 45 | # key 已经存在时,SETEX 覆盖旧值 46 | 47 | redis> SET cd "timeless" 48 | OK 49 | 50 | redis> SETEX cd 3000 "goodbye my love" 51 | OK 52 | 53 | redis> GET cd 54 | "goodbye my love" 55 | 56 | redis> TTL cd 57 | (integer) 2997 58 | -------------------------------------------------------------------------------- /string/setnx.rst: -------------------------------------------------------------------------------- 1 | .. _setnx: 2 | 3 | SETNX 4 | ===== 5 | 6 | **SETNX key value** 7 | 8 | 将 ``key`` 的值设为 ``value`` ,当且仅当 ``key`` 不存在。 9 | 10 | 若给定的 ``key`` 已经存在,则 `SETNX`_ 不做任何动作。 11 | 12 | `SETNX`_ 是『SET if Not eXists』(如果不存在,则 SET)的简写。 13 | 14 | **可用版本:** 15 | >= 1.0.0 16 | 17 | **时间复杂度:** 18 | O(1) 19 | 20 | **返回值:** 21 | | 设置成功,返回 ``1`` 。 22 | | 设置失败,返回 ``0`` 。 23 | 24 | :: 25 | 26 | redis> EXISTS job # job 不存在 27 | (integer) 0 28 | 29 | redis> SETNX job "programmer" # job 设置成功 30 | (integer) 1 31 | 32 | redis> SETNX job "code-farmer" # 尝试覆盖 job ,失败 33 | (integer) 0 34 | 35 | redis> GET job # 没有被覆盖 36 | "programmer" 37 | 38 | .. 39 | 模式:将 SETNX 用于加锁(locking) 40 | ---------------------------------------- 41 | .. warning:: 已经证实这个加锁算法带有竞争条件,在特定情况下会造成错误,请不要使用这个加锁算法,具体请参考 `http://huangz.iteye.com/blog/1381538 `_ 。 42 | `SETNX`_ 可以用作加锁原语(locking primitive)。比如说,要对关键字(key) ``foo`` 加锁,客户端可以尝试以下方式: 43 | ``SETNX lock.foo `` 44 | 如果 `SETNX`_ 返回 ``1`` ,说明客户端已经获得了锁, ``key`` 设置的unix时间则指定了锁失效的时间。之后客户端可以通过 ``DEL lock.foo`` 来释放锁。 45 | 如果 `SETNX`_ 返回 ``0`` ,说明 ``key`` 已经被其他客户端上锁了。如果锁是非阻塞(non blocking lock)的,我们可以选择返回调用,或者进入一个重试循环,直到成功获得锁或重试超时(timeout)。 46 | **处理死锁(deadlock)** 47 | 上面的锁算法有一个问题:如果因为客户端失败、崩溃或其他原因导致没有办法释放锁的话,怎么办? 48 | 这种状况可以通过检测发现——因为上锁的 ``key`` 保存的是 unix 时间戳,假如 ``key`` 值的时间戳小于当前的时间戳,表示锁已经不再有效。 49 | 但是,当有多个客户端同时检测一个锁是否过期并尝试释放它的时候,我们不能简单粗暴地删除死锁的 ``key`` ,再用 `SETNX`_ 上锁,因为这时竞争条件(race condition)已经形成了: 50 | * C1 和 C2 读取 ``lock.foo`` 并检查时间戳, `SETNX`_ 都返回 ``0`` ,因为它已经被 C3 锁上了,但 C3 在上锁之后就崩溃(crashed)了。 51 | * C1 向 ``lock.foo`` 发送 :ref:`DEL` 命令。 52 | * C1 向 ``lock.foo`` 发送 `SETNX`_ 并成功。 53 | * C2 向 ``lock.foo`` 发送 :ref:`del` 命令。 54 | * C2 向 ``lock.foo`` 发送 `SETNX`_ 并成功。 55 | * 出错:因为竞争条件的关系,C1 和 C2 两个都获得了锁。 56 | 幸好,以下算法可以避免以上问题。来看看我们聪明的 C4 客户端怎么办: 57 | * C4 向 ``lock.foo`` 发送 `SETNX`_ 命令。 58 | * 因为崩溃掉的 C3 还锁着 ``lock.foo`` ,所以 Redis 向 C4 返回 ``0`` 。 59 | * C4 向 ``lock.foo`` 发送 :ref:`GET` 命令,查看 ``lock.foo`` 的锁是否过期。如果不,则休眠(sleep)一段时间,并在之后重试。 60 | * 另一方面,如果 ``lock.foo`` 内的 unix 时间戳比当前时间戳老,C4 执行以下命令: 61 | ``GETSET lock.foo `` 62 | * 因为 :ref:`GETSET` 的作用,C4 可以检查看 :ref:`GETSET` 的返回值,确定 ``lock.foo`` 之前储存的旧值仍是那个过期时间戳,如果是的话,那么 C4 获得锁。 63 | * 如果其他客户端,比如 C5,比 C4 更快地执行了 :ref:`GETSET` 操作并获得锁,那么 C4 的 :ref:`GETSET` 操作返回的就是一个未过期的时间戳(C5 设置的时间戳)。C4 只好从第一步开始重试。 64 | | 注意,即便 C4 的 :ref:`GETSET` 操作对 ``key`` 进行了修改,这对未来也没什么影响。 65 | .. warning:: 为了让这个加锁算法更健壮,获得锁的客户端应该常常检查过期时间以免锁因诸如 :ref:`DEL` 等命令的执行而被意外解开,因为客户端失败的情况非常复杂,不仅仅是崩溃这么简单,还可能是客户端因为某些操作被阻塞了相当长时间,紧接着 :ref:`DEL` 命令被尝试执行(但这时锁却在另外的客户端手上)。 66 | -------------------------------------------------------------------------------- /string/setrange.rst: -------------------------------------------------------------------------------- 1 | .. _setrange: 2 | 3 | SETRANGE 4 | ========= 5 | 6 | **SETRANGE key offset value** 7 | 8 | 用 ``value`` 参数覆写(overwrite)给定 ``key`` 所储存的字符串值,从偏移量 ``offset`` 开始。 9 | 10 | 不存在的 ``key`` 当作空白字符串处理。 11 | 12 | `SETRANGE`_ 命令会确保字符串足够长以便将 ``value`` 设置在指定的偏移量上,如果给定 ``key`` 原来储存的字符串长度比偏移量小(比如字符串只有 ``5`` 个字符长,但你设置的 ``offset`` 是 ``10`` ),那么原字符和偏移量之间的空白将用零字节(zerobytes, ``"\x00"`` )来填充。 13 | 14 | 注意你能使用的最大偏移量是 2^29-1(536870911) ,因为 Redis 字符串的大小被限制在 512 兆(megabytes)以内。如果你需要使用比这更大的空间,你可以使用多个 ``key`` 。 15 | 16 | .. warning:: 17 | 当生成一个很长的字符串时,Redis 需要分配内存空间,该操作有时候可能会造成服务器阻塞(block)。在2010年的Macbook Pro上,设置偏移量为 536870911(512MB 内存分配),耗费约 300 毫秒, 18 | 设置偏移量为 134217728(128MB 内存分配),耗费约 80 毫秒,设置偏移量 33554432(32MB 内存分配),耗费约 30 毫秒,设置偏移量为 8388608(8MB 内存分配),耗费约 8 毫秒。 19 | 注意若首次内存分配成功之后,再对同一个 ``key`` 调用 `SETRANGE`_ 操作,无须再重新内存。 20 | 21 | **可用版本:** 22 | >= 2.2.0 23 | 24 | **时间复杂度:** 25 | | 对小(small)的字符串,平摊复杂度O(1)。(关于什么字符串是"小"的,请参考 :ref:`APPEND` 命令) 26 | | 否则为O(M), ``M`` 为 ``value`` 参数的长度。 27 | 28 | **返回值:** 29 | 被 `SETRANGE`_ 修改之后,字符串的长度。 30 | 31 | :: 32 | 33 | # 对非空字符串进行 SETRANGE 34 | 35 | redis> SET greeting "hello world" 36 | OK 37 | 38 | redis> SETRANGE greeting 6 "Redis" 39 | (integer) 11 40 | 41 | redis> GET greeting 42 | "hello Redis" 43 | 44 | 45 | # 对空字符串/不存在的 key 进行 SETRANGE 46 | 47 | redis> EXISTS empty_string 48 | (integer) 0 49 | 50 | redis> SETRANGE empty_string 5 "Redis!" # 对不存在的 key 使用 SETRANGE 51 | (integer) 11 52 | 53 | redis> GET empty_string # 空白处被"\x00"填充 54 | "\x00\x00\x00\x00\x00Redis!" 55 | 56 | 模式 57 | ------- 58 | 59 | 因为有了 `SETRANGE`_ 和 :ref:`GETRANGE` 命令,你可以将 Redis 字符串用作具有O(1)随机访问时间的线性数组,这在很多真实用例中都是非常快速且高效的储存方式,具体请参考 :ref:`APPEND` 命令的『模式:时间序列』部分。 60 | -------------------------------------------------------------------------------- /string/strlen.rst: -------------------------------------------------------------------------------- 1 | .. _strlen: 2 | 3 | STRLEN 4 | ======= 5 | 6 | **STRLEN key** 7 | 8 | 返回 ``key`` 所储存的字符串值的长度。 9 | 10 | 当 ``key`` 储存的不是字符串值时,返回一个错误。 11 | 12 | **可用版本:** 13 | >= 2.2.0 14 | 15 | **复杂度:** 16 | O(1) 17 | 18 | **返回值:** 19 | | 字符串值的长度。 20 | | 当 ``key`` 不存在时,返回 ``0`` 。 21 | 22 | :: 23 | 24 | # 获取字符串的长度 25 | 26 | redis> SET mykey "Hello world" 27 | OK 28 | 29 | redis> STRLEN mykey 30 | (integer) 11 31 | 32 | 33 | # 不存在的 key 长度为 0 34 | 35 | redis> STRLEN nonexisting 36 | (integer) 0 37 | -------------------------------------------------------------------------------- /tdir.include: -------------------------------------------------------------------------------- 1 | .. note:: 2 | 3 | .. image:: cover.jpg 4 | :align: left 5 | :scale: 27% 6 | 7 | 由本文档的翻译者 huangz 创作的《Redis 设计与实现》一书正在销售中, 8 | 该书详细地介绍了 Redis 内部的运作原理以及各项功能的实现原理, 9 | 是一本致力于帮助 Redis 使用者加深对 Redis 的理解, 10 | 并且更高效地使用 Redis 的书籍。 11 | 12 | 欢迎访问 `RedisBook.com `_ 并了解《Redis 设计与实现》的更多相关信息。 13 | -------------------------------------------------------------------------------- /topic/pubsub.rst: -------------------------------------------------------------------------------- 1 | 发布与订阅(pub/sub) 2 | ========================== 3 | 4 | .. note:: 5 | 6 | 本文档翻译自: http://redis.io/topics/pubsub 。 7 | 8 | :ref:`SUBSCRIBE` 、 :ref:`UNSUBSCRIBE` 和 :ref:`PUBLISH` 三个命令实现了\ `发布与订阅信息泛型 `_\ (Publish/Subscribe messaging paradigm), 9 | 在这个实现中, 10 | 发送者(发送信息的客户端)不是将信息直接发送给特定的接收者(接收信息的客户端), 11 | 而是将信息发送给频道(channel), 12 | 然后由频道将信息转发给所有对这个频道感兴趣的订阅者。 13 | 14 | 发送者无须知道任何关于订阅者的信息, 15 | 而订阅者也无须知道是那个客户端给它发送信息, 16 | 它只要关注自己感兴趣的频道即可。 17 | 18 | 对发布者和订阅者进行解构(decoupling), 19 | 可以极大地提高系统的扩展性(scalability), 20 | 并得到一个更动态的网络拓扑(network topology)。 21 | 22 | 比如说, 23 | 要订阅频道 ``foo`` 和 ``bar`` , 24 | 客户端可以使用频道名字作为参数来调用 :ref:`SUBSCRIBE` 命令: 25 | 26 | :: 27 | 28 | redis> SUBSCRIBE foo bar 29 | 30 | 当有客户端发送信息到这些频道时, 31 | Redis 会将传入的信息推送到所有订阅这些频道的客户端里面。 32 | 33 | 正在订阅频道的客户端不应该发送除 :ref:`SUBSCRIBE` 和 :ref:`UNSUBSCRIBE` 之外的其他命令。 34 | 其中, 35 | :ref:`SUBSCRIBE` 可以用于订阅更多频道, 36 | 而 :ref:`UNSUBSCRIBE` 则可以用于退订已订阅的一个或多个频道。 37 | 38 | :ref:`SUBSCRIBE` 和 :ref:`UNSUBSCRIBE` 的执行结果会以信息的形式返回, 39 | 客户端可以通过分析所接收信息的第一个元素, 40 | 从而判断所收到的内容是一条真正的信息, 41 | 还是 :ref:`SUBSCRIBE` 或 :ref:`UNSUBSCRIBE` 命令的操作结果。 42 | 43 | 44 | 信息的格式 45 | -------------------------- 46 | 47 | 频道转发的每条信息都是一条带有三个元素的多条批量回复(multi-bulk reply)。 48 | 49 | 信息的第一个元素标识了信息的类型: 50 | 51 | - ``subscribe`` : 52 | 表示当前客户端成功地订阅了信息第二个元素所指示的频道。 53 | 而信息的第三个元素则记录了目前客户端已订阅频道的总数。 54 | 55 | - ``unsubscribe`` : 56 | 表示当前客户端成功地退订了信息第二个元素所指示的频道。 57 | 信息的第三个元素记录了客户端目前仍在订阅的频道数量。 58 | 当客户端订阅的频道数量降为 ``0`` 时, 59 | 客户端不再订阅任何频道, 60 | 它可以像往常一样, 61 | 执行任何 Redis 命令。 62 | 63 | - ``message`` : 64 | 表示这条信息是由某个客户端执行 :ref:`PUBLISH` 命令所发送的, 65 | 真正的信息。 66 | 信息的第二个元素是信息来源的频道, 67 | 而第三个元素则是信息的内容。 68 | 69 | 举个例子, 70 | 如果客户端执行以下命令: 71 | 72 | :: 73 | 74 | redis> SUBSCRIBE first second 75 | 76 | 那么它将收到以下回复: 77 | 78 | :: 79 | 80 | 1) "subscribe" 81 | 2) "first" 82 | 3) (integer) 1 83 | 84 | 1) "subscribe" 85 | 2) "second" 86 | 3) (integer) 2 87 | 88 | 如果在这时, 89 | 另一个客户端执行以下 :ref:`PUBLISH` 命令: 90 | 91 | :: 92 | 93 | redis> PUBLISH second Hello 94 | 95 | 那么之前订阅了 ``second`` 频道的客户端将收到以下信息: 96 | 97 | :: 98 | 99 | 1) "message" 100 | 2) "second" 101 | 3) "hello" 102 | 103 | 当订阅者决定退订所有频道时, 104 | 它可以执行一个无参数的 :ref:`UNSUBSCRIBE` 命令: 105 | 106 | :: 107 | 108 | redis> UNSUBSCRIBE 109 | 110 | 这个命令将接到以下回复: 111 | 112 | :: 113 | 114 | 1) "unsubscribe" 115 | 2) "second" 116 | 3) (integer) 1 117 | 118 | 1) "unsubscribe" 119 | 2) "first" 120 | 3) (integer) 0 121 | 122 | 123 | 订阅模式 124 | -------------------- 125 | 126 | Redis 的发布与订阅实现支持模式匹配(pattern matching): 127 | 客户端可以订阅一个带 ``*`` 号的模式, 128 | 如果某个/某些频道的名字和这个模式匹配, 129 | 那么当有信息发送给这个/这些频道的时候, 130 | 客户端也会收到这个/这些频道的信息。 131 | 132 | 比如说,执行命令 133 | 134 | :: 135 | 136 | redis> PSUBSCRIBE news.* 137 | 138 | 的客户端将收到来自 ``news.art.figurative`` 、 ``news.music.jazz`` 等频道的信息。 139 | 140 | 客户端订阅的模式里面可以包含多个 glob 风格的通配符, 141 | 比如 ``*`` 、 ``?`` 和 ``[...]`` , 142 | 等等。 143 | 144 | 执行命令 145 | 146 | :: 147 | 148 | redis> PUNSUBSCRIBE news.* 149 | 150 | 将退订 ``news.*`` 模式, 151 | 其他已订阅的模式不会被影响。 152 | 153 | 通过订阅模式接收到的信息, 154 | 和通过订阅频道接收到的信息, 155 | 这两者的格式不太一样: 156 | 157 | - 通过订阅模式而接收到的信息的类型为 ``pmessage`` : 158 | 这代表有某个客户端通过 :ref:`PUBLISH` 向某个频道发送了信息, 159 | 而这个频道刚好匹配了当前客户端所订阅的某个模式。 160 | 信息的第二个元素记录了被匹配的模式, 161 | 第三个元素记录了被匹配的频道的名字, 162 | 最后一个元素则记录了信息的实际内容。 163 | 164 | 客户端处理 :ref:`PSUBSCRIBE` 和 :ref:`PUNSUBSCRIBE` 返回值的方式, 165 | 和客户端处理 :ref:`SUBSCRIBE` 和 :ref:`UNSUBSCRIBE` 的方式类似: 166 | 通过对信息的第一个元素进行分析, 167 | 客户端可以判断接收到的信息是一个真正的信息, 168 | 还是 :ref:`PSUBSCRIBE` 或 :ref:`PUNSUBSCRIBE` 命令的返回值。 169 | 170 | 171 | 通过频道和模式接收同一条信息 172 | --------------------------------------------- 173 | 174 | 如果客户端订阅的多个模式匹配了同一个频道, 175 | 或者客户端同时订阅了某个频道、以及匹配这个频道的某个模式, 176 | 那么它可能会多次接收到同一条信息。 177 | 178 | 举个例子, 179 | 如果客户端执行了以下命令: 180 | 181 | :: 182 | 183 | SUBSCRIBE foo 184 | PSUBSCRIBE f* 185 | 186 | 那么当有信息发送到频道 ``foo`` 时, 187 | 客户端将收到两条信息: 188 | 一条来自频道 ``foo`` ,信息类型为 ``message`` ; 189 | 另一条来自模式 ``f*`` ,信息类型为 ``pmessage`` 。 190 | 191 | 192 | 订阅总数 193 | ------------------------------------------------------------------ 194 | 195 | 在执行 :ref:`SUBSCRIBE` 、 :ref:`UNSUBSCRIBE` 、 :ref:`PSUBSCRIBE` 和 :ref:`PUNSUBSCRIBE` 命令时, 196 | 返回结果的最后一个元素是客户端目前仍在订阅的频道和模式总数。 197 | 198 | 当客户端退订所有频道和模式, 199 | 也即是这个总数值下降为 ``0`` 的时候, 200 | 客户端将退出订阅与发布状态。 201 | 202 | 203 | 编程示例 204 | --------------------------- 205 | 206 | Pieter Noordhuis 提供了一个使用 EventMachine 和 Redis 编写的 `高性能多用户网页聊天软件 `_ , 207 | 这个软件很好地展示了发布与订阅功能的用法。 208 | 209 | 210 | 客户端库实现提示 211 | ------------------------------------------ 212 | 213 | 因为所有接收到的信息都会包含一个信息来源: 214 | 215 | - 当信息来自频道时,来源是某个频道; 216 | 217 | - 当信息来自模式时,来源是某个模式。 218 | 219 | 因此, 220 | 客户端可以用一个哈希表, 221 | 将特定来源和处理该来源的回调函数关联起来。 222 | 当有新信息到达时, 223 | 程序就可以根据信息的来源, 224 | 在 O(1) 复杂度内, 225 | 将信息交给正确的回调函数来处理。 226 | -------------------------------------------------------------------------------- /topic/replication.rst: -------------------------------------------------------------------------------- 1 | .. _replication_topic: 2 | 3 | 复制(Replication) 4 | ======================= 5 | 6 | .. note:: 7 | 8 | 本文档翻译自: http://redis.io/topics/replication 。 9 | 10 | Redis 支持简单且易用的主从复制(master-slave replication)功能, 11 | 该功能可以让从服务器(slave server)成为主服务器(master server)的精确复制品。 12 | 13 | 以下是关于 Redis 复制功能的几个重要方面: 14 | 15 | - Redis 使用异步复制。 16 | 从 Redis 2.8 开始, 17 | 从服务器会以每秒一次的频率向主服务器报告复制流(replication stream)的处理进度。 18 | 19 | - 一个主服务器可以有多个从服务器。 20 | 21 | - 不仅主服务器可以有从服务器, 22 | 从服务器也可以有自己的从服务器, 23 | 多个从服务器之间可以构成一个图状结构。 24 | 25 | - 复制功能不会阻塞主服务器: 26 | 即使有一个或多个从服务器正在进行初次同步, 27 | 主服务器也可以继续处理命令请求。 28 | 29 | - 复制功能也不会阻塞从服务器: 30 | 只要在 ``redis.conf`` 文件中进行了相应的设置, 31 | 即使从服务器正在进行初次同步, 32 | 服务器也可以使用旧版本的数据集来处理命令查询。 33 | 34 | 不过, 35 | 在从服务器删除旧版本数据集并载入新版本数据集的那段时间内, 36 | 连接请求会被阻塞。 37 | 38 | 你还可以配置从服务器, 39 | 让它在与主服务器之间的连接断开时, 40 | 向客户端发送一个错误。 41 | 42 | - 复制功能可以单纯地用于数据冗余(data redundancy), 43 | 也可以通过让多个从服务器处理只读命令请求来提升扩展性(scalability): 44 | 比如说, 45 | 繁重的 :ref:`SORT` 命令可以交给附属节点去运行。 46 | 47 | - 可以通过复制功能来让主服务器免于执行持久化操作: 48 | 只要关闭主服务器的持久化功能, 49 | 然后由从服务器去执行持久化操作即可。 50 | 51 | 52 | 复制功能的运作原理 53 | ------------------------------- 54 | 55 | 无论是初次连接还是重新连接, 56 | 当建立一个从服务器时, 57 | 从服务器都将向主服务器发送一个 :ref:`SYNC` 命令。 58 | 59 | 接到 :ref:`SYNC` 命令的主服务器将开始执行 :ref:`BGSAVE` , 60 | 并在保存操作执行期间, 61 | 将所有新执行的写入命令都保存到一个缓冲区里面。 62 | 63 | 当 :ref:`BGSAVE` 执行完毕后, 64 | 主服务器将执行保存操作所得的 ``.rdb`` 文件发送给从服务器, 65 | 从服务器接收这个 ``.rdb`` 文件, 66 | 并将文件中的数据载入到内存中。 67 | 68 | 之后主服务器会以 Redis 命令协议的格式, 69 | 将写命令缓冲区中积累的所有内容都发送给从服务器。 70 | 71 | 你可以通过 telnet 命令来亲自验证这个同步过程: 72 | 首先连上一个正在处理命令请求的 Redis 服务器, 73 | 然后向它发送 :ref:`SYNC` 命令, 74 | 过一阵子, 75 | 你将看到 telnet 会话(session)接收到服务器发来的大段数据(\ ``.rdb`` 文件), 76 | 之后还会看到, 77 | 所有在服务器执行过的写命令, 78 | 都会重新发送到 telnet 会话来。 79 | 80 | 即使有多个从服务器同时向主服务器发送 :ref:`SYNC` , 81 | 主服务器也只需执行一次 :ref:`BGSAVE` 命令, 82 | 就可以处理所有这些从服务器的同步请求。 83 | 84 | 从服务器可以在主从服务器之间的连接断开时进行自动重连, 85 | 在 Redis 2.8 版本之前, 86 | 断线之后重连的从服务器总要执行一次完整重同步(full resynchronization)操作, 87 | 但是从 Redis 2.8 版本开始, 88 | 从服务器可以根据主服务器的情况来选择执行完整重同步还是部分重同步(partial resynchronization)。 89 | 90 | 91 | 部分重同步 92 | ---------------------------------------- 93 | 94 | 从 Redis 2.8 开始, 95 | 在网络连接短暂性失效之后, 96 | 主从服务器可以尝试继续执行原有的复制进程(process), 97 | 而不一定要执行完整重同步操作。 98 | 99 | 这个特性需要主服务器为被发送的复制流创建一个内存缓冲区(in-memory backlog), 100 | 并且主服务器和所有从服务器之间都记录一个复制偏移量(replication offset)和一个主服务器 ID (master run id), 101 | 当出现网络连接断开时, 102 | 从服务器会重新连接, 103 | 并且向主服务器请求继续执行原来的复制进程: 104 | 105 | - 如果从服务器记录的主服务器 ID 和当前要连接的主服务器的 ID 相同, 106 | 并且从服务器记录的偏移量所指定的数据仍然保存在主服务器的复制流缓冲区里面, 107 | 那么主服务器会向从服务器发送断线时缺失的那部分数据, 108 | 然后复制工作可以继续执行。 109 | 110 | - 否则的话, 111 | 从服务器就要执行完整重同步操作。 112 | 113 | Redis 2.8 的这个部分重同步特性会用到一个新增的 :ref:`PSYNC` 内部命令, 114 | 而 Redis 2.8 以前的旧版本只有 :ref:`SYNC` 命令, 115 | 不过, 116 | 只要从服务器是 Redis 2.8 或以上的版本, 117 | 它就会根据主服务器的版本来决定到底是使用 :ref:`PSYNC` 还是 :ref:`SYNC` : 118 | 119 | - 如果主服务器是 Redis 2.8 或以上版本,那么从服务器使用 :ref:`PSYNC` 命令来进行同步。 120 | 121 | - 如果主服务器是 Redis 2.8 之前的版本,那么从服务器使用 :ref:`SYNC` 命令来进行同步。 122 | 123 | 124 | 配置 125 | ------------------- 126 | 127 | 配置一个从服务器非常简单, 128 | 只要在配置文件中增加以下的这一行就可以了: 129 | 130 | :: 131 | 132 | slaveof 192.168.1.1 6379 133 | 134 | 当然, 135 | 你需要将代码中的 ``192.168.1.1`` 和 ``6379`` 替换成你的主服务器的 IP 和端口号。 136 | 137 | 另外一种方法是调用 :ref:`SLAVEOF` 命令, 138 | 输入主服务器的 IP 和端口, 139 | 然后同步就会开始: 140 | 141 | :: 142 | 143 | 127.0.0.1:6379> SLAVEOF 192.168.1.1 10086 144 | OK 145 | 146 | 147 | 只读从服务器 148 | -------------------- 149 | 150 | 从 Redis 2.6 开始, 151 | 从服务器支持只读模式, 152 | 并且该模式为从服务器的默认模式。 153 | 154 | 只读模式由 ``redis.conf`` 文件中的 ``slave-read-only`` 选项控制, 155 | 也可以通过 :ref:`CONFIG_SET` 命令来开启或关闭这个模式。 156 | 157 | 只读从服务器会拒绝执行任何写命令, 158 | 所以不会出现因为操作失误而将数据不小心写入到了从服务器的情况。 159 | 160 | 即使从服务器是只读的, 161 | ``DEBUG`` 和 ``CONFIG`` 等管理式命令仍然是可以使用的, 162 | 所以我们还是不应该将服务器暴露给互联网或者任何不可信网络。 163 | 不过, 164 | 使用 ``redis.conf`` 中的命令改名选项, 165 | 我们可以通过禁止执行某些命令来提升只读从服务器的安全性。 166 | 167 | 你可能会感到好奇, 168 | 既然从服务器上的写数据会被重同步数据覆盖, 169 | 也可能在从服务器重启时丢失, 170 | 那么为什么要让一个从服务器变得可写呢? 171 | 172 | 原因是, 173 | 一些不重要的临时数据, 174 | 仍然是可以保存在从服务器上面的。 175 | 比如说, 176 | 客户端可以在从服务器上保存主服务器的可达性(reachability)信息, 177 | 从而实现故障转移(failover)策略。 178 | 179 | 180 | 从服务器相关配置 181 | ----------------------------------------------- 182 | 183 | 如果主服务器通过 ``requirepass`` 选项设置了密码, 184 | 那么为了让从服务器的同步操作可以顺利进行, 185 | 我们也必须为从服务器进行相应的身份验证设置。 186 | 187 | 对于一个正在运行的服务器, 188 | 可以使用客户端输入以下命令: 189 | 190 | :: 191 | 192 | config set masterauth 193 | 194 | 要永久地设置这个密码, 195 | 那么可以将它加入到配置文件中: 196 | 197 | :: 198 | 199 | masterauth 200 | 201 | 另外还有几个选项, 202 | 它们和主服务器执行部分重同步时所使用的复制流缓冲区有关, 203 | 详细的信息可以参考 Redis 源码中附带的 ``redis.conf`` 示例文件。 204 | 205 | 206 | 主服务器只在有至少 N 个从服务器的情况下,才执行写操作 207 | ------------------------------------------------------- 208 | 209 | 从 Redis 2.8 开始, 210 | 为了保证数据的安全性, 211 | 可以通过配置, 212 | 让主服务器只在有至少 N 个当前已连接从服务器的情况下, 213 | 才执行写命令。 214 | 215 | 不过, 216 | 因为 Redis 使用异步复制, 217 | 所以主服务器发送的写数据并不一定会被从服务器接收到, 218 | 因此, 219 | 数据丢失的可能性仍然是存在的。 220 | 221 | 以下是这个特性的运作原理: 222 | 223 | - 从服务器以每秒一次的频率 PING 主服务器一次, 224 | 并报告复制流的处理情况。 225 | 226 | - 主服务器会记录各个从服务器最后一次向它发送 PING 的时间。 227 | 228 | - 用户可以通过配置, 229 | 指定网络延迟的最大值 ``min-slaves-max-lag`` , 230 | 以及执行写操作所需的至少从服务器数量 ``min-slaves-to-write`` 。 231 | 232 | 如果至少有 ``min-slaves-to-write`` 个从服务器, 233 | 并且这些服务器的延迟值都少于 ``min-slaves-max-lag`` 秒, 234 | 那么主服务器就会执行客户端请求的写操作。 235 | 236 | 你可以将这个特性看作 CAP 理论中的 C 的条件放宽版本: 237 | 尽管不能保证写操作的持久性, 238 | 但起码丢失数据的窗口会被严格限制在指定的秒数中。 239 | 240 | 另一方面, 241 | 如果条件达不到 ``min-slaves-to-write`` 和 ``min-slaves-max-lag`` 所指定的条件, 242 | 那么写操作就不会被执行, 243 | 主服务器会向请求执行写操作的客户端返回一个错误。 244 | 245 | 以下是这个特性的两个选项和它们所需的参数: 246 | 247 | - ``min-slaves-to-write `` 248 | 249 | - ``min-slaves-max-lag `` 250 | 251 | 详细的信息可以参考 Redis 源码中附带的 ``redis.conf`` 示例文件。 252 | -------------------------------------------------------------------------------- /transaction/discard.rst: -------------------------------------------------------------------------------- 1 | .. _discard: 2 | 3 | DISCARD 4 | ========= 5 | 6 | **DISCARD** 7 | 8 | 取消事务,放弃执行事务块内的所有命令。 9 | 10 | 如果正在使用 :ref:`WATCH` 命令监视某个(或某些) key,那么取消所有监视,等同于执行命令 :ref:`UNWATCH` 。 11 | 12 | **可用版本:** 13 | >= 2.0.0 14 | 15 | **时间复杂度:** 16 | O(1)。 17 | 18 | **返回值:** 19 | 总是返回 ``OK`` 。 20 | 21 | :: 22 | 23 | redis> MULTI 24 | OK 25 | 26 | redis> PING 27 | QUEUED 28 | 29 | redis> SET greeting "hello" 30 | QUEUED 31 | 32 | redis> DISCARD 33 | OK 34 | -------------------------------------------------------------------------------- /transaction/exec.rst: -------------------------------------------------------------------------------- 1 | .. _exec: 2 | 3 | EXEC 4 | ====== 5 | 6 | **EXEC** 7 | 8 | 执行所有事务块内的命令。 9 | 10 | 假如某个(或某些) key 正处于 :ref:`WATCH` 命令的监视之下,且事务块中有和这个(或这些) key 相关的命令,那么 `EXEC`_ 命令只在这个(或这些) key 没有被其他命令所改动的情况下执行并生效,否则该事务被打断(abort)。 11 | 12 | **可用版本:** 13 | >= 1.2.0 14 | 15 | **时间复杂度:** 16 | 事务块内所有命令的时间复杂度的总和。 17 | 18 | **返回值:** 19 | | 事务块内所有命令的返回值,按命令执行的先后顺序排列。 20 | | 当操作被打断时,返回空值 ``nil`` 。 21 | 22 | :: 23 | 24 | # 事务被成功执行 25 | 26 | redis> MULTI 27 | OK 28 | 29 | redis> INCR user_id 30 | QUEUED 31 | 32 | redis> INCR user_id 33 | QUEUED 34 | 35 | redis> INCR user_id 36 | QUEUED 37 | 38 | redis> PING 39 | QUEUED 40 | 41 | redis> EXEC 42 | 1) (integer) 1 43 | 2) (integer) 2 44 | 3) (integer) 3 45 | 4) PONG 46 | 47 | 48 | # 监视 key ,且事务成功执行 49 | 50 | redis> WATCH lock lock_times 51 | OK 52 | 53 | redis> MULTI 54 | OK 55 | 56 | redis> SET lock "huangz" 57 | QUEUED 58 | 59 | redis> INCR lock_times 60 | QUEUED 61 | 62 | redis> EXEC 63 | 1) OK 64 | 2) (integer) 1 65 | 66 | 67 | # 监视 key ,且事务被打断 68 | 69 | redis> WATCH lock lock_times 70 | OK 71 | 72 | redis> MULTI 73 | OK 74 | 75 | redis> SET lock "joe" # 就在这时,另一个客户端修改了 lock_times 的值 76 | QUEUED 77 | 78 | redis> INCR lock_times 79 | QUEUED 80 | 81 | redis> EXEC # 因为 lock_times 被修改, joe 的事务执行失败 82 | (nil) 83 | -------------------------------------------------------------------------------- /transaction/index.rst: -------------------------------------------------------------------------------- 1 | Transaction(事务) 2 | ======================= 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | 7 | discard 8 | exec 9 | multi 10 | unwatch 11 | watch 12 | -------------------------------------------------------------------------------- /transaction/multi.rst: -------------------------------------------------------------------------------- 1 | .. _multi: 2 | 3 | MULTI 4 | ====== 5 | 6 | **MULTI** 7 | 8 | 标记一个事务块的开始。 9 | 10 | 事务块内的多条命令会按照先后顺序被放进一个队列当中,最后由 :ref:`EXEC` 命令原子性(atomic)地执行。 11 | 12 | **可用版本:** 13 | >= 1.2.0 14 | 15 | **时间复杂度:** 16 | O(1)。 17 | 18 | **返回值:** 19 | 总是返回 ``OK`` 。 20 | 21 | :: 22 | 23 | redis> MULTI # 标记事务开始 24 | OK 25 | 26 | redis> INCR user_id # 多条命令按顺序入队 27 | QUEUED 28 | 29 | redis> INCR user_id 30 | QUEUED 31 | 32 | redis> INCR user_id 33 | QUEUED 34 | 35 | redis> PING 36 | QUEUED 37 | 38 | redis> EXEC # 执行 39 | 1) (integer) 1 40 | 2) (integer) 2 41 | 3) (integer) 3 42 | 4) PONG 43 | -------------------------------------------------------------------------------- /transaction/unwatch.rst: -------------------------------------------------------------------------------- 1 | .. _unwatch: 2 | 3 | UNWATCH 4 | ======== 5 | 6 | **UNWATCH** 7 | 8 | 取消 :ref:`WATCH` 命令对所有 key 的监视。 9 | 10 | 如果在执行 :ref:`WATCH` 命令之后, :ref:`EXEC` 命令或 :ref:`DISCARD` 命令先被执行了的话,那么就不需要再执行 `UNWATCH`_ 了。 11 | 12 | 因为 :ref:`EXEC` 命令会执行事务,因此 :ref:`WATCH` 命令的效果已经产生了;而 :ref:`DISCARD` 命令在取消事务的同时也会取消所有对 key 的监视,因此这两个命令执行之后,就没有必要执行 `UNWATCH`_ 了。 13 | 14 | **可用版本:** 15 | >= 2.2.0 16 | 17 | **时间复杂度:** 18 | O(1) 19 | 20 | **返回值:** 21 | 总是 ``OK`` 。 22 | 23 | :: 24 | 25 | redis> WATCH lock lock_times 26 | OK 27 | 28 | redis> UNWATCH 29 | OK 30 | -------------------------------------------------------------------------------- /transaction/watch.rst: -------------------------------------------------------------------------------- 1 | .. _watch: 2 | 3 | WATCH 4 | ====== 5 | 6 | **WATCH key [key ...]** 7 | 8 | 监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。 9 | 10 | **可用版本:** 11 | >= 2.2.0 12 | 13 | **时间复杂度:** 14 | O(1)。 15 | 16 | **返回值:** 17 | 总是返回 ``OK`` 。 18 | 19 | :: 20 | 21 | redis> WATCH lock lock_times 22 | OK 23 | --------------------------------------------------------------------------------