美文网首页Redis & MemCache
Redis Api的使用和理解

Redis Api的使用和理解

作者: 香沙小熊 | 来源:发表于2020-01-07 15:10 被阅读0次

    1.通用命令

    1.1通用命令
    • keys *
      遍历所有key
    123.57.251.156:6379> set hello world
    OK
    123.57.251.156:6379> set java best
    OK
    123.57.251.156:6379> set kpioneer man
    OK
    123.57.251.156:6379> keys *
    1) "java"
    2) "hello"
    3) "kpioneer"
    
    • keys [pattern]
      遍历符合通配符的所有key
    123.57.251.156:6379> mset hello world hehe haha java best javaer bad
    OK
    123.57.251.156:6379> keys he*
    1) "hello"
    2) "hehe"
    123.57.251.156:6379> keys he[h-l]*
    1) "hello"
    2) "hehe"
    123.57.251.156:6379> keys jav?
    1) "java"
    
    注意:keys命令一般不在生产环境中使用
    生产环境key较多,keys 的时间复杂度为 O(n),严格禁止在生产环境中使用

    运维人员或开发进行keys *操作,该操作比较耗时,又因为redis是单线程的,所以redis被锁住;
    此时QPS比较高,又来了几万个对redis的读写请求,因为redis被锁住,所以全部Hang在那;
    因为太多线程Hang在那,CPU严重飙升,造成redis所在的服务器宕机;
    所有的线程在redis那取不到数据,一瞬间全去数据库取数据,数据库就宕机了。

    • dbsize
      计算key的总数
    123.57.251.156:6379> FLUSHALL 
    OK
    123.57.251.156:6379> dbsize
    (integer) 0
    123.57.251.156:6379> mset k1 v1 k2 v2 k3 v3 k4 v4
    OK
    123.57.251.156:6379> dbsize
    (integer) 4
    123.57.251.156:6379> sadd myset a b c d e
    (integer) 5
    123.57.251.156:6379> dbsize
    (integer) 5
    
    • exists key
      检查key是否存在
    123.57.251.156:6379> set a b
    OK
    123.57.251.156:6379> exists a
    (integer) 1
    123.57.251.156:6379> del a
    (integer) 1
    123.57.251.156:6379> exists a
    (integer) 0
    
    • del key [key...]
      删除指定key-value
    123.57.251.156:6379> set a b
    OK
    123.57.251.156:6379> get a
    "b"
    123.57.251.156:6379> del a
    (integer) 1
    123.57.251.156:6379> get a
    (nil)
    
    • expire key seconds
      key在seconds秒后过期
    • ttl key
      查看key剩余的过期时间
    123.57.251.156:6379> set hello world
    OK
    123.57.251.156:6379> expire hello 18
    (integer) 1
    123.57.251.156:6379> ttl hello
    (integer) 9
    123.57.251.156:6379> get hello
    (nil)
    123.57.251.156:6379> expire hello 18
    (integer) 0
    123.57.251.156:6379> ttl hello
    (integer) -2
    123.57.251.156:6379> set hello world
    OK
    123.57.251.156:6379> expire hello 18
    (integer) 1
    123.57.251.156:6379> ttl hello
    (integer) 14
    123.57.251.156:6379> get hello
    "world"
    123.57.251.156:6379> ttl hello
    (integer) 2
    123.57.251.156:6379> get hello
    (nil)
    123.57.251.156:6379> ttl hello
    (integer) -2
    
    • persist key
      去掉key的过期时间
    123.57.251.156:6379> set hello world
    OK
    123.57.251.156:6379> expire hello 18
    (integer) 1
    123.57.251.156:6379> ttl hello
    (integer) 14
    123.57.251.156:6379> persist hello
    (integer) 1
    123.57.251.156:6379> ttl hello
    (integer) -1
    123.57.251.156:6379> get hello
    "world"
    
    • type key
      返回key的类型
    123.57.251.156:6379> set a b
    OK
    123.57.251.156:6379> type a
    string
    123.57.251.156:6379> sadd myset 1 2 3
    (integer) 3
    123.57.251.156:6379> type myset
    set
    

    返回值有: string、 hash、 lis、t set、 zset、 none

    1.2时间复杂度
    命令 时间复杂度
    keys O(n)
    dbsize O(1)
    del O(1)
    exists O(1)
    expire、ttl、persist O(1)
    type O(1)
    1.3数据结构和内部编码
    image.png
    1.4单线程架构
    1、Redis的单线程为什么这么快?

    1.完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1);主要原因
    2.数据结构简单,对数据操作也简单,Redis中的数据结构是专门进行设计的;
    3.采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗;
    4.使用多路I/O复用模型,非阻塞I/O;
    5.Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求;

    2、为什么不采用多进程或多线程处理?

    1.多线程处理可能涉及到锁
    2.多线程处理会涉及到线程切换而消耗CPU

    3、单线程处理的缺点?

    1.耗时的命令会导致并发的下降,不只是读并发,写并发也会下降
    2.无法发挥多核CPU性能,不过可以通过在单机开多个Redis实例来完善

    4、Redis不存在线程安全问题?

    Redis采用了线程封闭的方式,把任务封闭在一个线程,自然避免了线程安全问题,不过对于需要依赖多个redis操作(即:多个Redis操作命令)的复合操作来说,依然需要锁,而且有可能是分布式锁。

    注意事项:
    1.一次只运行一条命令
    2.拒绝长(慢)命令

    keys, flushall, flushdb, slow lua script ,mutil/exec, operate big value(collection)
    

    3.有的地方不是单线程

    fysnc file descriptor
    close file descriptor
    

    2.字符串类型(String)

    字符串类型是Redis中最基本的数据类型,它能存储任何形式的字符串,包括二进制数据。你可以用其存储用户的邮箱、JSON化的对象甚至是一张图片。一个字符串类型键允许存储的数据的最大容量是512MB。

    注释:在Redis 3.0版本中可能会放宽这一限制,但无论如何,考虑到Redis的数据是使用内存存储的, 512MB的限制已经非常宽松了。

    字符串类型是其他4种数据类型的基础,其他数据类型和字符串类型的差别从某种角度来说只是组织字符串的形式不同。例如,列表类型是以列表的形式组织字符串,而集合类型是以集合的形式组织字符串。

    如果只使用redis中的字符串类型,且不使用redis的持久化功能,那么,redis就和memcache非常非常的像了。这说明strings类型是一个很基础的数据类型,也是任何存储系统都必备的数据类型。

    基本操作
    • get key
      获取key对应的value
    • del key
      删除key-value
    123.57.251.156:6379> set hello world
    OK
    123.57.251.156:6379> get hello
    "world"
    123.57.251.156:6379> del hello
    (integer) 1
    123.57.251.156:6379> get hello
    (nil)
    
    • set key value
      不管key是否存在,都设置key-value
    • setnx key value
      key不存在时,才设置key-value
    • set key value xx
      key存在时,才设置key-value
    123.57.251.156:6379> exists java
    (integer) 0
    123.57.251.156:6379> set java best
    OK
    123.57.251.156:6379> setnx java bad
    (integer) 0
    123.57.251.156:6379> set java good xx
    OK
    123.57.251.156:6379> get java
    "good"
    123.57.251.156:6379> exists kpioneer
    (integer) 0
    123.57.251.156:6379> setnx kpioneer goodMan
    (integer) 1
    123.57.251.156:6379> exists php
    (integer) 0
    123.57.251.156:6379> set php hehe xx
    (nil)
    
    计数操作
    • incr key :
      key自增1,如果key不存在,自增后get(key)=1
    • decr key :
      key自减1,如果key不存在,自减后get(key)=-1
    • incrby key k :
      key自增k,如果key不存在,自增后get(key)=k
    • decrby key k :
      key自减k,如果key不存在,自减后get(key)=-k
    123.57.251.156:6379> get counter
    (nil)
    123.57.251.156:6379> incr counter
    (integer) 1
    123.57.251.156:6379> get counter
    "1"
    123.57.251.156:6379> incrby counter 99
    (integer) 100
    123.57.251.156:6379> decr counter
    (integer) 99
    123.57.251.156:6379> get counter
    "99"
    123.57.251.156:6379> decrby counter 99
    (integer) 0
    123.57.251.156:6379> get counter
    "0"
    
    批量操作
    • mset key1 value1 key2 value2 ...
      批量设置key-value
    • mget key1 key2 ...
      批量获取key,原子操作
    123.57.251.156:6379> mset hello world java best php bad
    OK
    123.57.251.156:6379> mset hello world java best C good
    OK
    123.57.251.156:6379> mget hello java C
    1) "world"
    2) "best"
    3) "good"
    
    其他操作
    • getset key newvalue
      设置key新值并返回旧值
    • append key value
      追加value
    • strlen key
      返回字符串的长度
    • getrange key start end
      获取字符串指定下标所有的值
    123.57.251.156:6379> set hello world
    OK
    123.57.251.156:6379> getset hello java
    "world"
    123.57.251.156:6379> get hello
    "java"
    123.57.251.156:6379> append hello ",C++"
    (integer) 8
    123.57.251.156:6379> get hello
    "java,C++"
    123.57.251.156:6379> strlen hello
    (integer) 8
    
    • incrbyfloat key 3.5
      key自增对应的值3.5
    • setrange key index value
      设置字符串指定下标所有对应的值
    123.57.251.156:6379> incr counter
    (integer) 1
    123.57.251.156:6379> incrbyfloat counter 1.2
    "2.2"
    123.57.251.156:6379> get counter
    "2.2"
    123.57.251.156:6379> set hello javabest
    OK
    123.57.251.156:6379> getrange hello 0 2
    "jav"
    123.57.251.156:6379> setrange hello 4 m
    (integer) 8
    123.57.251.156:6379> get hello
    "javamest"
    
    命令 含义 复杂度
    get key 获取key对应value O(1)
    set key value 不管key是否存在,都设置key-value O(1)
    setnx key value key不存在时,才设置key-value O(1)
    set key value xx key存在时,才设置key-value O(1)
    del key 删除key-value O(1)
    incr key
    decr key
    incrby key k
    decrby key k
    计数 O(1)
    mset key1 value1 key2 value2 ... 批量设置key-value O(n)
    mget key1 key2 ... 批量获取key,原子操作 O(n)

    3.哈希类型(Hash)

    基本操作
    • hget key field
      获取hash key对应field的value
    • hset key field value
      设置hash key对应field的value
    • hdel key field
      删除hash key对应field的value
    123.57.251.156:6379> hset user:1:info age 23
    (integer) 1
    123.57.251.156:6379> hget user:1:info age
    "23"
    123.57.251.156:6379> hset user:1:info name kpioneer
    (integer) 1
    123.57.251.156:6379> hgetall user:1:info
    1) "age"
    2) "23"
    3) "name"
    4) "kpioneer"
    123.57.251.156:6379> hdel user:1:info age
    (integer) 1
    123.57.251.156:6379> hgetall user:1:info 
    1) "name"
    2) "kpioneer"
    
    • hexists key field
      判断hash key是否有field
    • hlen key
      获取hash key的field数量
    123.57.251.156:6379> hgetall  user:1:info
    1) "name"
    2) "kpioneer"
    3) "age"
    4) "23"
    123.57.251.156:6379> hexists user:1:info name
    (integer) 1
    123.57.251.156:6379> hlen user:1:info 
    (integer) 2
    
    批量操作

    hmget key field1 field2 ... :批量获取hash key的一批field对应值
    hmset key field1 value1 field2 value2 ... :批量设置hash key的一批field value

    123.57.251.156:6379> hmset user:2:info age 28 name Jack page 48
    OK
    123.57.251.156:6379> hlen user:2:info 
    (integer) 3
    123.57.251.156:6379> hmget user:2:info age name page
    1) "28"
    2) "Jack"
    3) "48"
    
    其他操作

    hgetall key :返回hash key对应所有的field和value
    hvals key :返回hash key对应所有的field的value
    hkeys key :返回hash key对应所有的field

    123.57.251.156:6379> hgetall user:2:info
    1) "age"
    2) "28"
    3) "name"
    4) "Jack"
    5) "page"
    6) "48"
    123.57.251.156:6379> hvals user:2:info
    1) "28"
    2) "Jack"
    3) "48"
    123.57.251.156:6379> hkeys user:2:info
    1) "age"
    2) "name"
    3) "page"
    
    其他操作
    • hsetnx key field value
      设置hash key对应field的value(如field已经存在,则失败)
    • hincrby key field intCounter
      hash key对应的field的value自增intCounter
    • hincrbyfloat key field floatCounter
      hincrby浮点数版

    时间复杂度

    命令 复杂度
    hget
    hset
    hdel
    O(1)
    hexists
    hlen
    O(1)
    hsetnx
    hincrby
    hincrbyfloat
    O(1)
    hgetall
    hvals
    hkeys
    O(n)
    hmget
    hmset
    O(n)

    4.列表类型(List)

    • rpush key value1 value2...valueN
      从列表右端插入值(1-N个)
    • lpush key value1 value2...valueN
      从列表左端插入值(1-N个)
    • lrange key start end
      获取链表中从start到end的元素的值,start、end可为负数,若为-1则表示链表尾部的元素,-2则表示倒数第二个,依次类推…
    123.57.251.156:6379> rpush list1 1 2 3 4
    4
    123.57.251.156:6379> lrange list1 0 -1
    1
    2
    3
    4
    123.57.251.156:6379> lpush list1 7 8 9
    7
    123.57.251.156:6379> lrange list1 0 -1
    9
    8
    7
    1
    2
    3
    4
    
    • linsert key after value newValue
      在list指定的元素之后插入newValue这个元素。
    • linsert key before value newValue
      在list指定的元素之前插入newValue这个元素。
    123.57.251.156:6379> linsert list1 after 4 a
    8
    123.57.251.156:6379> lrange list1 0 -1
    9
    8
    7
    1
    2
    3
    4
    a
    123.57.251.156:6379> linsert list1 after 4 b
    9
    123.57.251.156:6379> lrange list1 0 -1
    9
    8
    7
    1
    2
    3
    4
    b
    a
    
    • lpop key
      返回并删除指定key的链表中的第一个元素,即头元素。

    • rpop key
      返回并删除指定key的链表中的最后一个元素,即尾元素。

    123.57.251.156:6379> lpop list1
    9
    123.57.251.156:6379> rpop list1
    a
    123.57.251.156:6379> lrange list1 0 -1
    8
    7
    1
    2
    3
    4
    
    • lrem key count value
      删除count个值为value的元素
      (1)count>0,从头向尾遍历并删除count个值为value的元素
      (2)count<0,从尾向头遍历并删除Math.abs(count)个值为value的元素
      (3)count=0,删除链表中所有等于value的元素。
    123.57.251.156:6379> rpush list a c a c b f
    6
    123.57.251.156:6379> lrem list -1 c
    1
    123.57.251.156:6379> lrange list 0 -1
    a
    c
    a
    b
    f
    123.57.251.156:6379> lrem list 0 a
    2
    123.57.251.156:6379> lrange list 0 -1
    c
    b
    f
    
    • ltrim key start end
    123.57.251.156:6379> rpush list a b c d e f
    6
    123.57.251.156:6379> ltrim list 1 4
    OK
    123.57.251.156:6379> lrange list 0 -1
    b
    c
    d
    e
    
    • lindex key index
      通过索引获取列表中的元素
    123.57.251.156:6379> rpush list a b c d e 
    5
    123.57.251.156:6379> lindex list 1
    b
    123.57.251.156:6379> lindex list -1
    e
    
    • llen key
      获取列表长度
    • lset key index value
      通过索引设置列表元素的值
    123.57.251.156:6379> rpush list a b c d e 
    5
    123.57.251.156:6379> lset list 2 java
    OK
    123.57.251.156:6379> lrange list 0 -1
    a
    b
    java
    d
    
    • blpop key1 [key2 ] timeout
      移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
    • brpop key1 [key2 ] timeout
      移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
    使用列表api组合实现其它数据结构
    1. lpush + lpop = Stack
    2. lpush + rpop = Queue
    3. lpush + ltrim = Capped Collection(有界集合)
    4. lpush + brpop = Message Queue

    5.集合类型(Set)

    Redis的Set是string类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。

    • sadd key member1 [member2]
      向集合添加一个或多个成员
    • srem key member1 [member2]
      移除集合中一个或多个成员
    • smembers key
      返回集合中的所有成员
      smembers 无序,数据量大时,造成redis阻塞
    123.57.251.156:6379> sadd myset "hello" "world" 
    2
    123.57.251.156:6379> sadd myset "hello"
    0
    123.57.251.156:6379> smembers myset
    hello
    world
    123.57.251.156:6379> srem myset "hello"
    1
    123.57.251.156:6379> smembers myset
    world
    123.57.251.156:6379> 
    
    • scard key
      获取集合的成员数
    • sismember key member
      判断 member 元素是否是集合 key 的成员
    • srandmember key [count]
      返回集合中一个或多个随机数
    • spop key
      移除并返回集合中的一个随机元素
    123.57.251.156:6379>  sadd myset 1 2 3 4 5 6 7 8
    8
    123.57.251.156:6379> scard myset
    8
    123.57.251.156:6379> sismember myset 2
    1
    123.57.251.156:6379> sismember myset 100
    0
    123.57.251.156:6379> srandmember myset 3
    2
    7
    5
    123.57.251.156:6379> spop myset 2
    7
    2
    123.57.251.156:6379> smembers myset
    1
    3
    4
    5
    6
    8
    
    • sdiff key1 [key2]
      返回给定所有集合的差集
    • sinter key1 [key2]
      返回给定所有集合的交集
    • sunion key1 [key2]
      返回所有给定集合的并集
    • sdiffstore destination key1 [key2]
      返回给定所有集合的差集并存储在 destination 中
    • sinterstore destination key1 [key2]
      返回给定所有集合的交集并存储在 destination 中
    • sunionstore destination key1 [key2]
      所有给定集合的并集存储在 destination 集合中
    123.57.251.156:6379> sadd myset1  1 3 5 7 9 10
    6
    123.57.251.156:6379> sadd myset2  1 2 4 6 8 10
    6
    123.57.251.156:6379> sdiff myset1 myset2
    3
    5
    7
    9
    123.57.251.156:6379> sinter myset1 myset2 
    1
    10
    123.57.251.156:6379> sunion myset1 myset2
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    123.57.251.156:6379> sunionstore dest myset1 myset2
    10
    123.57.251.156:6379> smembers dest
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    • sscan key cursor [MATCH pattern] [COUNT count]
      迭代集合中的元素
      redis 127.0.0.1:6379> SADD myset1 "hello"
      (integer) 1
      redis 127.0.0.1:6379> SADD myset1 "hi"
      (integer) 1
      redis 127.0.0.1:6379> SADD myset1 "bar"
      (integer) 1
      redis 127.0.0.1:6379> sscan myset1 0 match h*
    1. "0"
      1. "hello"
      2. "h1"
    集合类型(Set)实际运用

    SADD = Tagging 给用户加标签
    SPOP/SANDMEMBER = Random item
    SADD + SINTER = Social Graph 社交图谱 如微博共同兴趣爱好

    6.有序集合类型(Sorted Set)

    Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。
    不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。
    有序集合的成员是唯一的,但分数(score)却可以重复。

    数据类型对比
    集合 有序集合
    无重复元素 无重复元素
    无序 有序
    element element + score
    列表 有序集合
    可以有重复元素 无重复元素
    有序 有序
    element element + score
    • zadd key score1 member1 [score2 member2]
      向有序集合添加一个或多个成员,或者更新已存在成员的分数
    • zcard key
      获取有序集合的成员数
    阿里云redis:0>ZADD myset 1 "hello"
    1
    
    阿里云redis:0>ZADD myset 1 "foo"
    1
    
    阿里云redis:0>ZADD myset 2 "world" 3 "bar"
    2
    
    阿里云redis:0>ZRANGE my阿里云redis:0>set 0 -1 WITHSCORES
    1) foo
    2) 1
    3) hello
    4) 1
    5) world
    6) 2
    7) bar
    8) 3
    
    • zcount key min max
      计算在有序集合中指定区间分数的成员数
    • zincrby key increment member
      有序集合中对指定成员的分数加上增量 increment
    • zinterstore destination numkeys key [key ...]
      计算给定的一个或多个有序集的交集并将结果集存储在新的有序集合 key 中
    • zlexcount key min max
      在有序集合中计算指定字典区间内成员数量
    • zrange key start stop [withscores]
      通过索引区间返回有序集合成指定区间内的成员
    • zrangebylex key min max [limit offset count]
      通过字典区间返回有序集合的成员
    • zrangebyscore key min max [withscores] [limit]
      通过分数返回有序集合指定区间内的成员
    • zrank key member
      返回有序集合中指定成员的索引
    • zrem key member [member ...]
      移除有序集合中的一个或多个成员
    • zremrangebylex key min max
      移除有序集合中给定的字典区间的所有成员
    • zremrangebyrank key start stop
      移除有序集合中给定的排名区间的所有成员
    • zremrangebyscore key min max
      移除有序集合中给定的分数区间的所有成员
    • zrevrange key start stop [withscores]
      返回有序集中指定区间内的成员,通过索引,分数从高到底
    • zrevrangebyscore key max min [withscores]
      返回有序集中指定分数区间内的成员,分数从高到低排序
    • zrevrank key member
      返回有序集合中指定成员的排名,有序集成员按分数值递减(从大到小)排序
    • zscore key member
      返回有序集中,成员的分数值
    • zunionstore destination numkeys key [key ...]
      计算给定的一个或多个有序集的并集,并存储在新的 key 中
    • zscan key cursor [match pattern] [count count]
      迭代有序集合中的元素(包括元素成员和元素分值)
    方法 时间复杂度
    zadd key score element o(logN)
    zscore key element o(1)
    zincrby key increScore element o(1)
    zcard key o(1)
    zrank key element O(log(N))
    zrevrank key member O(log(N))
    zrange key start end [withscores] o(log(n)+m)
    zrevrange key start stop [withscores] o(log(n)+m)
    zrangebyscore key minScore maxScore [withscores] o(log(n)+m)
    zrevrangebyscore key maxScore minScore [withscores] o(log(n)+m)
    zcount key minScore maxScore o(log(n)+m)
    zrem key element o(1)
    zremrangebyrank key start end o(log(n)+m)
    zremrangebyscore key minScore maxScore o(log(n)+m)
    特别感谢:

    Redis 教程
    一站式学习Redis 从入门到高可用分布式实践

    相关文章

      网友评论

        本文标题:Redis Api的使用和理解

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