本文共 2873 字,大约阅读时间需要 9 分钟。
1.1查看所有键
keys *
下面插入了3对字符串类型的键值对:
127.0.0.1:6379> set hello world OK 127.0.0.1:6379> set java jedis OK 127.0.0.1:6379> set python redis-py OK keys*命令会将所有的键输出: 127.0.0.1:6379> keys * 1) "python" 2) "java" 3) "hello" 1.2键总数dbsize
下面插入一个列表类型的键值对(值是多个元素组成) :
127.0.0.1:6379>rpush mylist a b c d e f g(integer) 7
dbsize命令会返回当前数据库中键的总数。 例如当前数据库有4个键, 分别是hello、 java、 python、 mylist, 所以dbsize的结果是4: 127.0.0.1:6379> dbsize (integer) 4 dbsize命令在计算键总数时不会遍历所有键, 而是直接获取Redis内置的 键总数变量, 所以dbsize命令的时间复杂度是O(1) 。 而keys命令会遍历所有键, 所以它的时间复杂度是O(n) , 当Redis保存了大量键时, 线上环境 禁止使用。 1.3检查键是否存在exists key
如果键存在则返回1, 不存在则返回0:
127.0.0.1:6379> exists java (integer) 1 127.0.0.1:6379> exists not_exist_key (integer) 01.4 删除键
del key [key ...]
127.0.0.1:6379> del java
(integer) 1 127.0.0.1:6379> exists java (integer) 0 127.0.0.1:6379> del mylist (integer) 1 127.0.0.1:6379> exists mylist (integer) 0 返回结果为成功删除键的个数, 假设删除一个不存在的键, 就会返回0: 27.0.0.1:6379> del not_exist_key (integer) 0 同时del命令可以支持删除多个键: 127.0.0.1:6379> set a 1 OK 127.0.0.1:6379> set b 2 OK 127.0.0.1:6379> set c 3 OK 127.0.0.1:6379> del a b c (integer) 3 5.键过期 expire key seconds Redis支持对键添加过期时间, 当超过过期时间后, 会自动删除键, 例如为键hello设置了10秒过期时间: 127.0.0.1:6379> set hello world OK 127.0.0.1:6379> expire hello 10(integer) 1
ttl命令会返回键的剩余过期时间, 它有3种返回值:
·大于等于0的整数: 键剩余的过期时间。 ·-1: 键没设置过期时间。 ·-2: 键不存在 可以通过ttl命令观察键hello的剩余过期时间: #还剩7秒 127.0.0.1:6379> ttl hello(integer) 7
#还剩1秒 127.0.0.1:6379> ttl hello (integer) 1 #返回结果为-2, 说明键hello已经被删除 127.0.0.1:6379> ttl hello (integer) -2 127.0.0.1:6379> get hello (nil) 有关键过期更为详细的使用以及原理会在2.7节介绍。 6.键的数据结构类型 type key 例如键hello是字符串类型, 返回结果为string。 键mylist是列表类型, 返 回结果为list: 127.0.0.1:6379> set a b OK 127.0.0.1:6379> type a string 127.0.0.1:6379> rpush mylist a b c d e f g (integer) 7 127.0.0.1:6379> type mylistlist
如果键不存在, 则返回none:
127.0.0.1:6379> type not_exsit_key nonetype命令实际返回的就是当前键的数据结构类型, 它们分别是:
string(字符串),hash(哈希),list(列表),set(集合),zset(有序集合)
通过object encoding命令查询内部编码:
object encoding hello
object encoding mylist
每个客户端调用都经历了发送命令,执行命令,返回结果。
其中第2步是重点要讨论的, 因为Redis是单线程来处理命令的, 所以一条命令从客户端达到服务端不会立刻被执行, 所有命令都会进入一个队列
中, 然后逐个被执行。 所以上面3个客户端命令的执行顺序是不确定的(如图2-4所示) , 但是可以确定不会有两条命令被同时执行(如图2-5所示) , 所以两条incr命令无论怎么执行最终结果都是2, 不会产生并发问题, 这就是Redis单线程的基本模型。但是像发送命令、 返回结果、 命令排队肯定不像描述的这么简单, Redis使用了I/O多路复用技术来解决I/O的问题。
图2-4 所有命令在一个队列里排队等待被执行
2.2 为什么单线程还能这么快
为什么Redis使用单线程模型会达到每秒万级别的处理能力呢? 可以将其归结为三点:
第一, 纯内存访问, Redis将所有数据放在内存中, 内存的响应时长大约为100纳秒, 这是Redis达到每秒万级别访问的重要基础。 第二, 非阻塞I/O, Redis使用epoll作为I/O多路复用技术的实现, 再加上Redis自身的事件处理模型将epoll中的连接、 读写、 关闭都转换为事件, 不 在网络I/O上浪费过多的时间, 如图2-6所示。第三, 单线程避免了线程切换和竞态产生的消耗。
既然采用单线程就能达到如此高的性能, 那么也不失为一种不错的选择, 因为单线程能带来几个好处:第一, 单线程可以简化数据结构和算法的实现。 如果对高级编程语言熟悉的读者应该了解并发数据结构实现不但困难而且开发测试比较麻烦。
第二, 单线程避免了线程切换和竞态产生的消耗,对于服务端开发来说, 锁和线程切换通常是性能杀手。
但是单线程会有一个问题: 对于每个命令的执行时间是有要求的。 如果某个命令执行过长, 会造成其他命令的阻塞, 对于Redis这种高性能的服务 来说是致命的, 所以Redis是面向快速执行场景的数据库。
备注:文章参考《Redis开发与运维》,作者:付磊,张益军
转载地址:http://cnyab.baihongyu.com/