Redis核心数据结构与高性能原理剖析

162 阅读4分钟

Redis常用的数据结构

image.png

  • 字符串----String
  • 哈希---hash
  • 列表----list
  • 集合---set
  • 有序集合----zset

当然还有数据结构:BitMap,HighLogLog,GEO

1. String结构常用的操作

字符串常用操作

  • set key value 存入字符串键值对
  • mset key value [key value...] ----批量存储字符串键值对
  • setnx(set if not exit),值不存在则设置值
  • mget -----批量获取字符串键值
  • get key -----获取一个字符串键值
  • del key -----删除一个键值
  • expire key seconds -----设置一个键的过期时间

原子加减

  • incr key --- 将key中存储的数字值加1
  • deccr key ----- 将key中存储的数字值减1
  • increby key increment ---- 将key中所存储的值 加上 increment自定义的值
  • decreby key decrement ---- 将key中所存储的值减去相应的值

redis的单线程是基于他的命令的,比如get,set,mset,mget命令等,因此在执行一条命令的时候时间不宜过长,否则在高并发场景下会影响它的性能。hash结构的大key就是会出现这样的问题,因此在开发的过程中尽量避免hash结构的大key。 大key(bigkey)指的是这个key对应得值很大,导致在对这个key查询过程中,时间太长了。这里涉及线程模型和redis的优化实践。

分段存储hash结构

hash结构应用场景

  • 电商购物车

hash结构---电商购物车

a. 用户id为key

b.商品id为field

c.商品数量为value

  • 对购物车的操作
  1. 添加商品 -->hset cart:1001 10088 1:表示对对1001这个购物车的10088这件商品添加1件进购物车
  2. 增加购物车商品中的数量--->hincrby cart:1001 10088 1 表示在购物车1001中的10088这个商品增加一件,此时购物车1001中10088这件商品有两件。
  3. 获取购物车中商品的总数:hlen cart:1001 结果为3
  4. 删除购物车中10088这件商品:hdel cart:1001 10088
  5. 获取购物车所有的商品:hgetall cart :1001

redis集群希望数据平均分配: 使用hash结构的话容易导致数据分配倾斜,一个hash结构key中存放大量的数据,是有办法去解决的,数据分片。Redis集群

list数据结构

可以实现实现常用的数据结构

  • 栈:lpush + lpop-----左近左出(与jdk中栈的区别是,可以在分布式环境下使用)
  • 队列:lpush + rpop----左近右边出
  • 阻塞队列(Blocking MQ):lpush + brpop

BitMap(String),GEO都是5种常用的数据结构的扩展

  • 应用场景

  • 微博微信公众号消息流,新浪微博重度依赖Redis

后发消息的展示在最前面。

set数据结构

boardmix.cn/app/share/C… 点击链接加入boardmix中的文件「Redis常用数据结构」

zset有序结合结构

往有序集合key中加入带分值元素 ZADD key score member [[score member]...]

集合倒叙排序取前面10条记录 ZREVRANGE hotNews:ID 0 9 withscores

Redis的单线程和高性能

  • Redis是单线程的么? redis的单线程是针对客户端发起的命令的操作-----执行命令的操作是由一个线程来执行的,其后端的持久化,过期异步删除,集群数据的同步都是由redis服务端其他线程去操作的。

Redis的单机并发是很高的。

  • Redis单线程为什么还这么快

    • 基于内存,所有的运算都是基于内存的运算----核心
    • Redis是单线程的,避免了多线程之间的切换所造成的cpu消耗
    • 基于IO多路复用
    • Redis的数据结构设计的就是以空间换时间。
  • Redis单线程如何处理那么多的并发客户端连接?

RedisIo多路复用:利用epoll来实现IO多路复用,将连接信息和事件放到队列中,依次放到文件事件分派器中,事件分派器将事件分发给事件处理器。

客户端发送过来的命令Redis全部接收放到Redis中的一个队列里面去,后端通过事件监听器,基于NIO可以一次性响应多个请求。由事件分派器一次性分派多个命令,在内存中还是按照顺序执行命令。