美文网首页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学习历程

    Redis初识 Redis安装与启动 Redis 常用API 理解与使用 Redis java客户端使用(单机版,...

  • Redis——API的理解和使用

    一、全局命令1、查看所有键 2、键总数 3、检查键是否存在 4、删除键 5、键过期 6、键的数据结构类型 更多命令...

  • Redis Api的使用和理解

    1.通用命令 1.1通用命令 keys *遍历所有key keys [pattern]遍历符合通配符的所有key ...

  • Redis API的理解和使用

    一、通用命令 keys:显示所有符合条件的键(一般不在生产环境使用,时间复杂度O(n)速度慢) dbsize:计算...

  • 对Redis的API理解和使用

    全局命令 数据结构和内部编码 单线程命令处理机制 键的命令 查看所有键 keys * 键总数 dbsize 检查键...

  • redis基本API的理解和使用

    前言 在正式介绍5种数据结构之前,了解一下Redis的一些全局命令、数据结构和内部编码等。 全局命令 查看所有键k...

  • Redis学习--API的理解和使用

    全局命令 1.查看所有键 keys*命令会将所有的键输出,遍历O(n),线上禁用 2.键总数 dbsize命令会返...

  • Redis-5种基本类型结构

    笔记来自:《redis开发与维护》第二章 API的理解和使用主要内容:redis 5种数据结构:string、ha...

  • Redis API 理解与使用

    本章节大致分为以下几种: 通用API的介绍 简单介绍5种不同数据结构 一、通用API 查找key 查看redis存...

  • Spring Data Redis入门示例:基于Jedis及底层

    使用底层API:RedisConnectionFactory和RedisConnection可以直接操作Redis...

网友评论

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

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