如何使用好redis,需要理解redis的单线程工作特性,需要学习好redis的底层数据结构,以掌握各种操作命令的时间复杂度,最有效的使用redis。
(一)String类型
可以说String类型是我们最常用的类型
(1)内部编码
根据类容内部3种编码
int #c语言中long能存储下的数字
embstr #长度<=39字节的字符串
raw #长度>39字节的字符串
#可以通过如下查看内部编码
172.16.0.55:6379> set redis-key values
OK
172.16.0.55:6379> object encoding redis-key
"embstr"
(2)场景及命令
(a)存储单个值
这是最常见场景
(b)分布式锁
setnx name value #如果key不存在,则执行成功
172.16.0.55:6379> setnx redis-key 1
(integer) 1 #执行成功
172.16.0.55:6379> setnx redis-key 1
(integer) 0 #执行失败
#借助redis的单线程特性,可简单的实现分布式锁的需求
#在redis集群状态下需要考虑结点挂掉的情景,可参考官方地址:https://redis.io/topics/distlock
(c)计数器
可以使用INCR命令来完成计数器功能,由于redis单线程的原理完美保证操作的线程安全。
(d)批量操作
mset,mget
#批量操作有效减少客户端网络IO时间,有效提高程序的处理效率
#但是批量操作也需要根据数据的大小,考虑网络传输压力以及对其他命令的响应时间影响,不能不限大长度的批量操作。如果数据特别多,需要考虑分批次进行。
(3)其他
(a) set命令会把原来key设置的过期时间去掉,如果原来有过期时间的话
172.16.0.55:6379> set redis-key value ex 100000
OK
172.16.0.55:6379> ttl redis-key
(integer) 99993
172.16.0.55:6379> set redis-key values
OK
172.16.0.55:6379> ttl redis-key
(integer) -1
(二)Hash类型
常用于存储有关联的健值对
(1)内部编码
根据类容内部2种编码
ziplist(压缩列表)
hashtable(哈希表)
#以下两个条件满足时使用ziplist,否则使用hashtable存储
#hash中元素个数小于hash-max-ziplist-entires(默认512个)
#hash中每个元素的值小于hash-max-ziplist-value(默认64字节)
**这么设计主要是为了权衡存储空间和访问速度**
(2)场景及命令
(a)记录满足某种状态的用户id
HSET key field1 value1 #可以向同一个hash中添加用户,O(1)
HEXISTS key field1 #判断某个用户是否存在,O(1)
HDEL key field1 #删除一个用户,O(1)
HLEN key #查询满足用户的数量,O(1)
(3)其他
(a)O(N)命令慎用
对于时间复杂度O(N)的命令需要慎用,尤其是HGETALL,HKEYS,HVALS这种需要返回大量数据的命令,不仅需要考虑命令的时间复杂度,还需要考虑大量数据返回对于网络的压力。
(三)LIST类型
可以方便的进行列表数据的操作
(1)内部编码
根据类容内部2种编码
ziplist(压缩列表)
linkedlist(链表)
#以下两个条件满足时使用ziplist,否则使用linkedlist存储
#hash中元素个数小于list-max-ziplist-entires(默认512个)
#hash中每个元素的值小于list-max-ziplist-value(默认64字节)
(2)场景及命令
(a)消息队列
#我们程序中经常会有异步消息队列的场景,redis可以很好的满足我们的需求
LPUSH key value #向队列添加一个消息,O(1)
RPOP key #移除并返回列表 key 的尾元素,O(1)
(3)其他
(a)队列 or 栈
#由于list是双向的根据redis提供的命令我们可以按业务需求来进行队列和堆栈的使用
#队列:LPUSH+RPOP(RPUSH+LPOP同样效果)
#栈:LPUSH+LPOP(RPUSH+RPOP同样效果)
(b)阻塞 or 非阻塞
#redis出队列提供了阻塞和非阻塞版本,可以根据我们业务需要进行区分使用
#非阻塞:LPOP,RPOP
#阻塞:BLPOP,BRPOP