redis系列(一)—内部结构

内部结构

前言

大家好,牧码心今天给大家推荐一篇redis系列之内部结构的文章,在实际工作中有很多应用场景,希望对你有所帮助。内容如下:

  • 全局命令
  • 内部编码
  • 单线程架构

全局命令

Redis有5种数据结构, 它们是键值对中的值, 对于键来说有一些通用的命令

  • 查询所有键值
    命令:keys *
127.0.0.1:6379> keys *
1) "python"
2) "java"
3) "hello"
  • 键总数
    命令:dbsize
127.0.0.1:6379> dbsize
(integer) 4

说明:dbsize命令在计算键总数时不会遍历所有键, 而是直接获取Redis内置的键总数变量, 所以dbsize命令的时间复杂度是O(1) 。 而keys命令会遍历所有键, 所以它的时间复杂度是O(n) , 当Redis保存了大量键时, 线上环境禁止使用。

  • 检查键是否存在
    命令:exists key
    说明:如果键存在则返回1, 不存在则返回0

  • 删除键
    命令:del key [key …]
    说明:返回结果为成功删除键的个数, 假设删除一个不存在的键, 就会返回0

  • 键过期
    命令:expire key seconds
    说明:命令会返回键的剩余过期时间, 它有3种返回值:

    • 大于等于0的整数: 键剩余的过期时间。
    • -1: 键没设置过期时间。
    • -2: 键不存在
#还剩7127.0.0.1:6379> ttl hello
(integer) 7
...
#还剩1127.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)
  • 查看键的数据类型
    命令:type key
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 mylist
list

说明:键hello是字符串类型, 返回结果为string。 键mylist是列表类型, 返回结果为list

内部编码

redis对外支持的数据结构分别是:string(字符串)/hash(哈希)/ list(列表) /set(集合)/zset(有序集合),但实际上每种数据结构都有自己底层的内部编码实现, 而且是多种实现,这样Redis会在合适的场景选择合适的内部编码。

  • 结构和编码图
    Redis数据结构和内部编码

  • 设计优势
    1、可以改进内部编码, 而对外的数据结构和命令没有影响, 这样一旦开发出更优秀的内部编码, 无需改动外部数据结构和命令。
    例如Redis3.2提供了quicklist, 结合了ziplist和linkedlist两者的优势, 为列表类型提供了一种更为优秀的内部编码实现, 而对外部用户来说基本感知不到;
    2、多种内部编码实现可以在不同场景下发挥各自的优
    势, 例如ziplist比较节省内存, 但是在列表元素比较多的情况下, 性能会有所下降, 这时候Redis会根据配置选项将列表类型的内部实现转换为linkedlist;

单线程结构

  • 实例说明
    开启了三个redis-cli客户端同时执行命令
1、客户端1设置一个字符串键值对:
127.0.0.1:6379> set hello world
2、客户端2对counter做自增操作:
127.0.0.1:6379> incr counter
3、客户端3对counter做自增操作:
127.0.0.1:6379> incr counter

Redis客户端与服务端的模型可以简化成图, 每次客户端调用都经历了发送命令、 执行命令、 返回结果三个过程:
Redis客户端与服务端请求过程
上面3个客户端命令的执行顺序是不确定的,但是可以确定不会有两条命令被同时执行,所以两条incr命令无论怎么执行最终结果都是2, 不会产生并发问题, 这就是Redis单线程的基本模型,如图所示:
Redis使用IO多路复用和自身事件模型

  • 单线程快的原因
    1、纯内存访问, Redis将所有数据放在内存中, 内存的响应时长大约为100纳秒, 这是Redis达到每秒万级别访问的重要基础;
    2、非阻塞I/O, Redis使用epoll作为I/O多路复用技术的实现, 再加上Redis自身的事件处理模型将epoll中的连接、 读写、 关闭都转换为事件, 不在网络I/O上浪费过多的时间;
    3、单线程避免了线程切换和竞态产生的消耗;

  • 存在问题
    如果某个命令执行过长, 会造成其他命令的阻塞, 对于Redis这种高性能的服务来说是致命的, 所以Redis是面向快速执行场景的数据库

参考

  • 《redis运维与开发》
发布了91 篇原创文章 · 获赞 27 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/xhwwc110/article/details/104759249
今日推荐