为什么Redis是单线程的
首先对于Redis的网络通信模块,它是基于I/O多路复用模型实现的,也就是说只使用一个线程就可以处理多个连接,避免了传统方案使用多线程处理多条连接时的上下文切换开销。而对于命令的执行,因为Redis是基于内存的操作,CPU不是Redis的瓶颈,单线程的处理效率就是最高的,使用多线程反而会增大切换开销,并且引入线程安全的问题,因此Redis使用单线程的方案。
那什么时候应该使用多线程呢?其实对于类似磁盘I/O读写的操作,如果使用单线程执行,当耗时较长时,后面的所有其它请求都会被阻塞在这,这时候就可以使用新的线程去异步的处理之后的一些请求,提高系统的性能。
为什么Redis这么快
- Redis是基于内存的操作
- Redis底层使用C语言实现,效率更高
- Redis使用I/O多路复用,不像传统方案开多个线程处理多个I/O,大大降低了线程切换的开销
字符串
字符串是最基础的类型,字符串长度不能超过512MB。常用的API有如下几个:
get key:获取一个key的valueset key value:设置一个key的valuedel key:删除一个keyincr key:key自增1,如果key不存在,自增后key的value为1decr key:key自减1,如果key不存在,自减后key的value为-1incrby key k:key自增k,如果key不存在,自增后key的value为kset key value:不管key是否存在,都设置valuesetnx key value:当key不存在时才设置valuemget key1 key2 key3...:批量获取key,原子操作mset key1 value1 key2 value2 key3 value3:批量设置key的value
适用场景:
- 记录某个用户的页面访问量:
incr userid:pageview - 实现分布式锁
哈希
哈希可以理解为Map中的Map,因为它每个key对应的value都是一个Map结构,每个field不能相同,但value可以相同。常用的API有如下几个:
hget key field:获取key对应的field的valuehgetall key:返回key对应所有的field和valuehset key field value:设置key对应的field的valuehdel key field:删除key对应的field的valuehmget key field1 field2 ... fieldN:批量获取key的一批field对应的valuehmset key field1 value1 field2 value2 ... fieldN valueN:批量设置key的一批field对应的value
要注意的是,哈希结构无法针对某个指定的field设置超时时间,TTL不好控制。
列表
列表(list)用来存储多个有序(插入顺序)的字符串,每个字符串称为元素,并且元素是可以重复的。常用的API有如下几个:
rpush key value1 value2 ... valuen:从列表右端插入元素lpush key value1 value2 ... valuen:从列表左端插入元素linsert key before|after value newValue:在某个key下的list指定的value前|后插入newValuelpop key:从列表左侧弹出一个元素rpop key:从列表右侧弹出一个元素lrem key count value:根据count的值,从列表中删除所有value相等的元素。当count> 0时,从左到右删除最多count个value相等的元素;当count< 0时,从右到左删除最多Math.abs(count)个value相等的元素;当count= 0时,删除所有value相等的元素。ltrim key start end:按照索引范围修剪列表,即删除索引范围之外的元素lrange key start end:获取列表索引范围内的所有元素,包含endblpop key timeout:lpop阻塞版本,timeout是阻塞超时时间,timeout为0表示永久阻塞brpop key timeout:rpop阻塞版本,timeout是阻塞超时时间,timeout为0表示永不阻塞
适用场景:
- 用户动态的时间轴:当用户更新动态的时候可以使用
lpush命令加入列表,使用lrange命令展示一定数量的动态,并且使用ltrim限制动态的数量。 - 使用
lpush+lpop实现一个栈,使用lpush+rpop实现一个队列。 - 使用
lpush+brpop实现一个消息队列。
集合
集合(set)与列表类似,都是用来保存多个字符串,但集合中的元素是无序的,因此不能通过索引来操作元素,并且集合中的元素不能有重复。常用的API有如下几个:
sadd key element:向key添加element,如果element已经存在,则添加失败srem key element:将key中的element移除掉sinter key1 key2:取交集sdiff key1 key2:取差集sunion key1 key2:取并集scard key:返回集合中元素的数量sismember key member:判断集合key中是否存在memberspop key:从集合中随机弹出一个元素
适用场景:
- 使用
sadd命令给用户添加标签,或者给标签添加用户,通过sinter命令实现共同关注等功能。
有序集合
有序集合与集合一样,元素都不能重复,但有序集合中的元素是有顺序的,与列表使用索引下标作为排序依据不同,有序集合为每个元素设置一个分数(score)作为排序依据。常用的API有如下几个:
zadd key score element:添加score和element,score是可以重复的,但element是不能重复的。zrem key element:删除元素elementzscore key element:返回元素element的分数scorezincrby key increScore element:增加或减少元素element的分数scorezcard key:返回元素的总个数zrange key start end [WITHSCORES]:返回指定索引范围内的升序元素(相当于排名)zrangebyscore key minScore maxScore [WITHSCORES]:返回指定分数范围内的升序元素zcount key minScore maxScore:返回有序集合内在指定分数范围内的个数
适用场景:
- 排行榜:可以将销售量、关注人数、时间戳作为
score进行元素的排序