美文网首页
redis通用命令以及数据结构之字符串

redis通用命令以及数据结构之字符串

作者: tracy_668 | 来源:发表于2018-09-03 22:21 被阅读10次

    redis基本命令

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

    • 查看所有的键 keys *, keys * 命令会去遍历所有键,它的时间复杂度是O(n), 当redis保存了大量键时,很占cpu,线上环境禁止使用
    • 键总数 dbsize , dbsize命令不会去遍历所有的键,而是直接获取Redis内置的键总数变量,时间复杂度为O(1)
    • 检查键是否存在 exists key , 如果键存在则返回1,不存在返回0
    • 删除键 del key1 key2 删除键,返回结果为成功删除键的个数,如果删除一个不存在的键,返回0
    • 对键添加过期时间 expire key seconds, 当超过过期时间后,会自动删除键。ttl key命令返回键剩余过期时间,它有三种返回值,大于等于0的整数,表示键剩余的过期时间。-1表示 键没设置过期时间。-2 表示键不存在。
    • 键的数据结构类型 type key。 type key命令实际返回的是当前键的数据结构类型,有string、hash、list、set、zset有序集合,但这些只是redis对外的数据结构,而每种数据结构都有自己底层的内部编码实现,这通过object encoding key命令查询。一种类型的数据结构可能对应着不同的内部编码,这样可以做到改进内部编码,而对外的数据结构和命令没有影响,多种内部编码实现可以在不同的场景下发挥各自的优势,redis可以根据不同场景切换内部实现。

    redis单线程架构

     redis是使用单线程来处理命令的,所以一条命令从客户端到服务端是不会立刻被执行,所有命令都会进入到一个队列中,然后逐个被执行。通常来说,单线程处理能力要比多线程差,为啥redis使用单线程模型能够达到每秒万级别的处理能力?原因如下:

    • 纯内存访问,redis将所有数据都放在内存,而内存的响应时间时长大约为100纳秒,这是redis访问如此快的重要基础。
    • redis使用epoll作为io多路复用技术的实现,并且redis自身的事件处理模型将epoll中的连接、读写、关闭都转换为事件,不在网络io上浪费过多时间。


      image.png
    • 单线程避免了线程切换和竞态产生的消耗。

    数据结构类型

    字符串

    • 字符串类型是redis最基础的数据结构,redis所有的key都是字符串类型,其他的几种数据结构都是在字符串类型基础上构建的。字符串类型的值可以是字符串、数字、二进制数据、但大小限制在512MB。
    • 字符串常用命令:设置值 set key value ex px nx | xx,ex表示为键设置秒级过期时间,px表示为键设置毫秒级过期时间。nx表示键必须不存在,才能设置成功,用于添加。xx与nx相反,键必须存在才可以设置成功,用于更新。
    • 除了set外,redis还提供了setex和setnx两个命令, setex key seconds value, setnx key value,其作用与ex和nx选项一样。
    • 获取键的值: get key,若键不存在返回nil。批量设置值: mset key1 value1 key2 value2,批量获取值 mget key1 key2 key3。批量操作命令大大提高了开发效率,如果没有mget这样的命令,执行n次get命令要n次网络时间+n次命令时间。使用mget后,执行n次命令操作只需要1次网络时间+n次命令时间。
    • incr命令用于对值做自增操作,如果值不是整数,返回错误; 值是整数就返回自增后的结果;键不存在,按照值为0自增,返回1。很多存储系统和编程语言实现计数功能常常使用消耗cpu的cas机制(比如java的AtomicInteger),但在redis中由于其单线程架构,完全不存在这种消耗。
    • 一些不常见的命令。追加值: append key value, 想字符串尾部追加。求字符串长度 strlen key。 getset key value, 设置值同时返回原值。 get range key start end 获取部分字符串,start和end分别是开始和结束的偏移量。

    setnx和setxx的使用场景

    由于redis的单线程命令处理机制,如果有多个客户端同时执行setnx key value,根据setnx的特性只有一个客户端能够设置成功,这使得setnx可以作为分布式锁的一种实现方案。

    字符串内部编码

     我们知道redis是使用对象来表示数据库中的键和值,每次我们向redis数据库中新创建一个键值对时,都会创建两个对象,键对象和值对象。而redis中的每个对象都由一个redisobject结构表示。


    image.png

    type属性记录了对象对外的类型,为下图5种类型中的一种,encoding表示对象的底层编码。


    image.png image.png

    字符串类型的内存编码有三种,Redis会根据当前值的类型和长度决定使用哪种编码

    1. int 8个字节的长整型
    2. embstr 小于等于39字节的字符串
    3. raw 大于39个字节的字符串

    如果一个字符串对象保存的是整数值,并且这个整数值可以用long类型来表示,那么字符串对象会将整数值保存在字符串对象结构的ptr属性里面,也即将void*直接转换成long类型,并将字符串对象的编码设置为int。


    image.png

    如果字符串对象保存的是一个字符串长度大于32字节的字符串值,redis将使用一个简单动态字符串(sds)来保存这个字符串值,并将对象的编码设置为raw。


    image.png

    如果字符串对象保存的是一个字符串值,并且该字符串值的长度小于32字节,那么字符串对象将使用embstr编码方式保存这个字符串值。embstr编码是专门用于保存短字符串的一种优化编码方式,它和raw编码一样,也是使用redisobject和sdshdr结构来表示字符串对象。但raw编码创建字符串对象会调用两次内存分配函数来分别创建redisobject结构和sdshdr结构,而embstr编码只需要调用一次内存分配函数来分配一块连续的空间,依次包含redisobject结构和sdshdr结构。这


    image.png image.png

    编码的转换

    int编码的字符串和embstr编码的字符串在一定条件下会被转换为raw编码的字符串对象。
    对于int编码的字符串对象,若我们对对象执行了一些命令使得这个对象保存的不再是整数值,而是一个字符串值,该字符串对象的编码将由int变成raw。


    image.png

    对于embstr编码的字符串对象,redis并没有给其提供相应的修改接口,本质上embstr编码的字符串只是可读的,对其的任何修改命令redis都是先将其转化为raw,再执行修改命令。


    image.png

    相关文章

      网友评论

          本文标题:redis通用命令以及数据结构之字符串

          本文链接:https://www.haomeiwen.com/subject/hyguwftx.html