美文网首页
redis 详解系列之一(基础知识)

redis 详解系列之一(基础知识)

作者: 落羽归尘 | 来源:发表于2019-08-11 20:51 被阅读0次

    本文内容

    • redis概述
    • redis应用场景
    • 单线程架构简介
    • 全局命令讲解
    • 五种数据类型讲解

    redis概述

            redis是一种键值对的nosql数据库,值可以支持字符串(string),哈希(hash),列表(list),集合(set),有序集合(zset)等数据结构。redis是将数据存放到内存中,因此读写速度很快,另外还能将内存中数据持久化到硬盘,保证数据不会丢失。除了redis支持的5中数据结构,还有许多额外的额功能,比如键过期功能实现缓存,发布订阅功能实现消息系统等。
            redis之所以速度快,官方数据是读写性能10万/秒,原因在于:1,redis是用C语言实现的;2,redis是单线程架构,减少了多线程竞争的开销,避免线程切换和锁机制;3,非阻塞IO,redis使用epoll多路复用技术,使得不会在网络IO上浪费太多时间。
            redis对外有五种数据结构(string,hash,list,set,zset),每种数据结构都有两种以上的内部编码实现,可以通过命令object encoding查看

    127.0.0.1:6379> object encoding h
    "embstr"
    

    这样的设计有两个好处,1,改进内部编码时,对外部无影响;2,不同的编码在不同的场景下有不同的优势。

    redis使用场景

            1,redis可用于缓存,大部分的大型网站都需要缓存层,为了保护存储层,使用缓存能加快访问速度,降低后端服务器数据源的压力,2,可用于排行榜系统,可根据list和zset数据结构,方便的构建排行榜系统,3,可应用于计数器应用,4,订阅发布,消息系统

    redis单线程

            redis使用的是单线程架构和IO多路复用实现高性能的内存数据库,每次客户端调用命令都是经过三个过程:发送命令、执行命令、返回结果。由于单线程架构,一条命令达到服务端的时候不会立刻执行,所有的命令都会进入到一个队列中排队执行,不会有两个命令同时执行的情况。但是注意,单线程情况下,如果一个命令执行时间过长,会对其他命令造成阻塞,对整个redis服务造成影响。

    redis常用命令

    全局命令

            RedisDesktopManager是一种redis的可视化工具,使用非常简单。

    • 查看所有键keys *
    127.0.0.1:6379> keys *
     1) "a,1"
     2) "a:2"
     3) "aa"
     4) "z"
     5) "a:1"
     6) "b"
     7) "z1"
     8) "c"
     9) "s1"
    10) "s"
    11) "h"
    
    • 键总数dbsize
      dbsize不会遍历所有的键,而是直接获取redis内置的键总数变量,时间复杂度O(1),而keys 命令会遍历所有键,时间复杂度O(n),请谨慎使用。
    127.0.0.1:6379> dbsize
    (integer) 11
    
    • 检查键是否存在exists
      1 代表存在,0代表不存在
    127.0.0.1:6379> exists a
    (integer) 0
    127.0.0.1:6379> exists b
    (integer) 1
    
    • 删除键 del
      若删除一个不存在的键会返回0,也可以同时删除多个键
    127.0.0.1:6379> exists d
    (integer) 1
    127.0.0.1:6379> del d
    (integer) 1
    127.0.0.1:6379> exists d
    (integer) 0
    127.0.0.1:6379> del a b c
    (integer) 3
    
    • 键过期 expire
      为键添加有效期,如以下 10秒后自动删除键。
    127.0.0.1:6379> expire c 10
    (integer) 1
    127.0.0.1:6379> exists c
    (integer) 0
    
    • 键的数据结构类型 type,如果键不存在,返回none
    127.0.0.1:6379> type h
    string
    

    字符串(string)

            字符串是redis数据结构中最基础的,其他数据结构都是在其之上构建的。字符串类型的值,可以是字符串(string,json,xml等),数字(int,float),二进制等,但是请注意,最大不能超过512MB

    常用命令
    • 设置值 set
      set key value [ex seconds] [px milliseconds] [nx|xx]
    127.0.0.1:6379> set hello world
    OK
    

    选项:
    -ex 设置秒级别的过期时间
    -px 设置毫秒级别的过期时间
    -nx:键必须不存在,才可以设置成功,用于添加。
    -xx:与nx相反,键必须存在,才可以设置成功,用于更新。
    除set命令,还有setnx,setex,作用和选项-ex,-nx作用一样。

    setex key seconds value
    setnx key value
    
    127.0.0.1:6379> set a test
    OK
    127.0.0.1:6379> setnx a test   # 由于a键已经存在,所以设置失败
    (integer) 0
    127.0.0.1:6379> set a test1 XX # 由于a键已经存在,所以更新成功
    OK
    
    • 获取值 get
    127.0.0.1:6379> get a
    "test1"
    127.0.0.1:6379> get a1
    (nil)
    
    • 批量设置值 mset
      mset key value [key value ...]
    127.0.0.1:6379> mset k1 v1 k2 v2
    OK
    
    • 批量获取值 mget
      mget key [key ...]
    127.0.0.1:6379> mget k1 k2
    1) "v1"
    2) "v2"
    

    批量操作能提高效率,执行时间较短,但是使用批量操作时,要注意数量,防止过多造成网络阻塞,或者redis阻塞。

    • 计数 incr
      incr命令用于自增操作,键不存在时,创建一个,返回1。除了自增,还有自减命令(decr)
    127.0.0.1:6379> incr key1
    (integer) 1
    127.0.0.1:6379> incr key1
    (integer) 2
    

    字符串类型的内部编码有三种,int:8字节的长整形,embstr:小于等于39字节的字符串,raw:大于39字节的字符串。
    redis根据具体场景选择不同的编码。

    使用场景
    • 缓存
      通过设置键的过期时间等作为后端的缓存层,降低后端压力
    • 计数
      字符串类型有incr自增,可作为计数器使用
    • 共享数据
      如分布式web服务器共享session
    • 限制
      SET key value EX 60 NX
      通过过期时间和NX选项达到限速功能,比如每分钟最多访问多少次,可以结合应用代码实现。

    哈希(hash)

            hash是形如键值对的类型,比如python中的字典。

    常用命令
    • 设置值 hset
      时间复杂度O(1)
      hset key field value
    127.0.0.1:6379> hset user:1 name z
    (integer) 1
    

    同样,也有hsetnx命令,作用同string的setnx

    • 获取值 hget
      时间复杂度O(1)
      hget key field
    127.0.0.1:6379> hget user:1 name
    "z"
    
    • 删除 hdel
      时间复杂度O(n)
      hdel key field [field ...]
      删除指定key下的一个或者多个field。
    • 计算filed的个数 hlen
      hlen key
    • 批量设置和获取
      时间复杂度O(k)
      hmget key field [field ...] # 可以获取指定key下的一个或者多个field。
      hmset key field value [field value ...] # 可以设置指定key下的一个或者多个field。
    • 判断field是否存在 hexists
      时间复杂度O(1)
      hexists key field
    • 获取所有field
      时间复杂度O(n)
      hkeys key
    127.0.0.1:6379> hkeys user:1
    1) "name"
    
    • 获取所有value
      时间复杂度O(n)
      hvals key
    127.0.0.1:6379> hvals user:1
    1) "z"
    
    • 获取所有field-value
      时间复杂度O(n)
      hgetall key
      注意,使用hgetall时,如果元素过多,存在阻塞redis的风险,如果一定要使用,可以使用hscan命令,渐进遍历。
    127.0.0.1:6379> hgetall user:1
    时间复杂度O(n)
    1) "name"
    2) "z"
    

    同样,hash也有好几种内部编码,根据不同场景选择合适的。

    使用场景
    • 缓存
      比如缓存用户信息时,每个用户有很多属性,比字符串更加直观,但是会消耗更多的内存。

    列表(list)

            list可以用于存储多个有序的字符串,一个list最多可以存储2**32-1个元素。可以充当队列和栈。开发中有很多使用场景。

    常用命令
    • 添加 插入 查找
      rpush key value [value ...] #从右边插入n个元素 时间复杂度O(n)
      lpush key value [value ...] #从左边插入n个元素 时间复杂度O(n)
      linsert key before|after p value # 向元素为p的前或者后插入value 时间复杂度O(n)
      lrange key start end # 查找元素 时间复杂度O(s+n) s是start的偏移量,n是范围值
      lindex key index # 获取指定下标元素 时间复杂度O(n)
      llen key # 获取list长度 时间复杂度O(1)
    127.0.0.1:6379> rpush l a s 1
    (integer) 3
    127.0.0.1:6379> lpush l k n
    (integer) 5
    127.0.0.1:6379> linsert l before k k1
    (integer) 6
    
    127.0.0.1:6379> lrange l 0 -1
    1) "n"
    2) "k1"
    3) "k"
    4) "a"
    5) "s"
    6) "1"
    
    • 删除
      lpop key # list左侧弹出 时间复杂度O(1)
      rpop key # list右侧弹出 时间复杂度O(1)
      lrem key count value # 删除指定元素 count>0:从左到右,删除最多count个元素;
      count<0:从右到左,删除最多count的绝对值个元素;count,删除所有。 时间复杂度O(n)
      ltrim key start end # 按照范围裁剪,保留start到end的元素 时间复杂度O(n)
      lset key index newValue # 修改指定index的元素 时间复杂度O(n)
    127.0.0.1:6379> lpop l
    "n"
    127.0.0.1:6379> rpop l
    "1"
    127.0.0.1:6379> lrem l 1 k
    (integer) 1
    127.0.0.1:6379> lrange l 0 -1
    1) "k1"
    2) "a"
    3) "s"
    127.0.0.1:6379> ltrim l 0 1
    OK
    127.0.0.1:6379> lrange l 0 -1
    1) "k1"
    2) "a"
    127.0.0.1:6379> lset l 0 k2
    OK
    127.0.0.1:6379> lrange l 0 -1
    1) "k2"
    2) "a"
    

    阻塞操作:
    blpop key [key ...] timeout #list空时,timeout时间内返回,当timeout=0,无限阻塞下去. 时间复杂度O(1)
    brpop key [key ...] timeout
    如在一个客户端执行
    127.0.0.1:6379> brpop list:test 3
    另一个客户端做插入动作,观察第一个客户端情况。

    使用场景
    • 消息队列
      lpush+brpop组合命令可以实现阻塞队列。
      lpush+lpop组合命令可以实现栈等

    集合(set)

            set也是可以用于存储多个有序的字符串,但是里面的元素是无序的,而且没有重复的。一个set里最多有2**32-1个元素,set除了增删改查,还有交集并集的操作。

    常用命令
    • 添加 删除 查找 判断
      sadd key element [element ...] #往集合添加n个元素。时间复杂度O(n)
      srem key element [element ...] #删除集合中n个元素。时间复杂度O(n)
      scard key #计算元素个数。 时间复杂度为O(1)
      sismember key element # 判断元素是否在集合中。时间复杂度O(1)
      srandmember key [count] # 随机返回count个元素 默认为1。时间复杂度O(count)
      spop key # 弹出元素。时间复杂度O(1)
      smembers key # 获取所有元素。时间复杂度O(n)
    127.0.0.1:6379> sadd s a b c 1 2 3
    (integer) 6
    127.0.0.1:6379> srem s b
    (integer) 1
    127.0.0.1:6379> scard s
    (integer) 5
    127.0.0.1:6379> sismember s a
    (integer) 1
    127.0.0.1:6379> srandmember s 3
    1) "c"
    2) "3"
    3) "a"
    127.0.0.1:6379> spop s
    "1"
    127.0.0.1:6379> smembers s
    1) "c"
    2) "2"
    3) "3"
    4) "a"
    
    • 集合间操作
      sinter key [key ...] # 多个集合交集。时间复杂度O(m*k),m是键数,k是多个set中元素最少的个数
      suinon key [key ...] # 多个集合并集。时间复杂度O(n)
      sdiff key [key ...] # 多个集合差集。时间复杂度O(n)
      sinterstore destination key [key ...] # 保存交集结果到destination
      suionstore destination key [key ...] # 保存并集结果到destination
      sdiffstore destination key [key ...] # 保存差集结果到destination
    
    127.0.0.1:6379> smembers s
    1) "c"
    2) "2"
    3) "3"
    4) "a"
    127.0.0.1:6379> sadd s1 1 2 3 a b c
    (integer) 4
    127.0.0.1:6379> sinter s s1
    1) "c"
    2) "2"
    3) "3"
    4) "a"
    127.0.0.1:6379> sunion s s1
    1) "6"
    2) "1"
    3) "c"
    4) "5"
    5) "2"
    6) "3"
    7) "b"
    8) "a"
    127.0.0.1:6379> sdiff s s1
    (empty list or set)
    127.0.0.1:6379> sdiff s1 s
    1) "6"
    2) "5"
    3) "1"
    4) "b"
    127.0.0.1:6379> sinterstore d1 s s1
    (integer) 4
    127.0.0.1:6379> smembers d1
    1) "2"
    2) "3"
    3) "c"
    4) "a"
    
    使用场景
    • 用户标签(无重复特性)
    • 随机数
      spop/srandmember 命令组合生成随机数

    有序集合(zset)

            有序集合保留了set的无重复特性,但是比之多一个特点是有序,给每个元素设置一个score作为排行依据,score的值可以重复。

    常用命令
    • 添加
      zadd key [NX|XX] [CH] [INCR] score member [score member ...] # 添加n个成员。复杂度为O(log(n))
      nx和xx选项和string上面的等意义一样
      ch选项返回此次操作,有序集合元素和分数发生变化的个数
      incr选项对score做增加
    127.0.0.1:6379> zadd zs 2 a 20 b 200 c
    (integer) 3
    
    • 计算成员
      zcard key # 获取元素个数。复杂度为O(1)
      zscore key member # 获取元素的分数
      zrank key member # 获取元素排名
      zrevrank key member # 获取元素排名反向
      zincrby key increment member # 增加元素分数
      zrange key start end [withscores] # 返回指定排名范围的成员
      zrevrange key start end [withscores]
    127.0.0.1:6379> zadd zs 2 a 20 b 200 c
    (integer) 3
    127.0.0.1:6379> zcard zs
    (integer) 3
    127.0.0.1:6379> zscore zs b
    "20"
    127.0.0.1:6379> zrank zs b
    (integer) 1
    127.0.0.1:6379> zincrby zs 30 b
    "50"
    127.0.0.1:6379> zrange zs 1 3
    1) "b"
    2) "c"
    
    • 删除
      zrem key member [member ...] # 删除n个元素

    • 集合操作
      交集并集差集

    参考书

    《redis开发与运维(付磊)》

    相关文章

      网友评论

          本文标题:redis 详解系列之一(基础知识)

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