1、Redis高性能原理

Redis之所以性能高效,主要因为以下三点:

  • 基于内存读写

它所有的数据都在内存中,所有的运算都是内存级别的运算,而且单线程避免了多线程的切换性能损耗问题。正因为 Redis 是单线程,所以要小心使用 Redis 指令,对于那些耗时的指令(比如 keys),一定要谨慎使用,一不小心就可能会导致 Redis 卡顿。
Redis的服务全都是单线程吗?不是。Redis 的单线程主要是指 Redis 的网络 IO 和键值对读写是由一个线程来完成的,这也是 Redis 对外 提供键值存储服务的主要流程。但 Redis 的其他功能,比如持久化、异步删除、集群数据同步等,其实是由额外的线程执行的。

  • 采用的多路复用

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

  • 高效率的数据结构

常用的五大Redis的数据结构,及他们各自的底层实现结构:
string:底层实现是简单动态字符串(SDS -simple dynamic string)
hash:底层实现是hash表或则压缩列表(ziplist)
list:底层实现是双向列表(quicklist)或者压缩列表
set:底层实现是hash表(hashtable)或者整数数组
sortset(zset):底层实现是压缩列表或者跳表

2、五种基本数据结构

String

String常用操作:

命令 描述 例子
SET key value 存入字符串键值对 set test 123
GET key 获取一个字符串键值 get test
MSET key value [key value …] 批量存储字符串键值对 mset test1 123 test2 456
MGET key [key …] 批量获取字符串键值 mget test1 test2
SETNX key value 只有在 key 不存在时设置 key 的值(存在时返回0) setnx test3 123
DEL key [key …] 删除一个键 del test
EXPIRE key seconds 设置一个键的过期时间(秒) expire test1 5
INCR key 将key中储存的数字值加1 incr test2
DECR key 将key中储存的数字值减1 DECR test2
INCRBY key increment 将key所储存的值加上increment INCRBY test2 10
DECRBY key decrement 将key所储存的值减去decrement DECRBY test2 10

String应用场景:

  • 缓存对象

MSET user:1:name liwq user:1:balance 1888
SET user:1 value(对象的json格式数据)

  • 分布式锁

SETNX product:10001 true //返回1代表获取锁成功
SETNX product:10001 true //返回0代表获取锁失败
。。。执行业务操作
DEL product:10001 //执行完业务释放锁

  • 计数器

image.png
INCR article:readcount:{文章id}
GET article:readcount:{文章id}

  • Web集群session共享

spring session + redis实现session共享

  • 分布式系统全局序列号

INCRBY orderId 1000 //redis批量生成序列+号提升性能

Hash

优点 1)同类数据归类整合储存,方便数据管理 2)相比string操作消耗内存与cpu更小 3)相比string储存更节省空间 缺点 过期功能不能使用在field上,只能用在key上 Redis集群架构下不适合大规模使用

Hash常用操作:

命令 描述 例子
HSET key field value 存储一个哈希表key的键值 HSET myhash field1 “foo”
HGET key field 获取哈希表key对应的field键值 HGET myhash field1
HSETNX key field value 只有在字段 field 不存在时,设置哈希表字段的值 HSETNX myhash field1 “foo”
HMSET key field value [field value …] 在一个哈希表key中存储多个键值对 HMSET myhash name liwq pwd 123456
HMGET key field [field …] 批量获取哈希表key中多个field键值 HMGET myhash name pwd
HDEL key field [field …] 删除哈希表key中的field键值 HDEL myhash name
HLEN key 返回哈希表key中field的数量 HLEN myhash
HGETALL key 返回哈希表key中所有的键值 HGETALL myhash
HINCRBY key field increment 为哈希表key中field键的值加上增量increment HINCRBY myhash pwd 10

Hash应用场景:
缓存对象
HMSET user name liwq balance 1888
电商购物车
image.png
1)以用户id为key
2)商品id为field
3)商品数量为value
购物车操作对应Redis指令:
添加商品:hset cart:1001 10088 1
增加数量:hincrby cart:1001 10088 1
商品总数:hlen cart:1001
删除商品:hdel cart:1001 10088
获取购物车所有商品:hgetall cart:1001

List

List常用操作:

命令 描述 例子
LPUSH key value [value …] 将一个或多个值value插入到key列表的表头(最左边) LPUSH mylist zhangsan lisi wangwu
RPUSH key value [value …] 将一个或多个值value插入到key列表的表尾(最右边) RPUSH mylist zhangsan lisi wangwu
LPOP key 移除并返回key列表的头元素 LPOP mylist
RPOP key 移除并返回key列表的尾元素 RPOP mylist
LRANGE key start stop 返回列表key中指定区间内的元素,区间以偏移量start和stop指定 LRANGE mylist 1 3
BLPOP key [key …] timeout 从key列表表头移除一个元素,若列表中没有元素,阻塞等待 timeout秒,如果timeout=0,一直阻塞等待 BLPOP mylist 10
BRPOP key [key …] timeout 从key列表表尾移除一个元素,若列表中没有元素,阻塞等待 timeout秒,如果timeout=0,一直阻塞等待 BRPOP mylist 10

List应用场景:微博和公众号消息
利用List的命令,可以实现类似栈(先进后出),队列(先进先出)的功能:
Stack(栈) = LPUSH + LPOP
Queue(队列)= LPUSH + RPOP
image.png
我们也可以合理利用List指令,实现公众号消息排版,新发的消息在前面:
image.png
(1)订阅号发布消息,消息ID为1001
LPUSH msg:{用户ID} 1001
(2)订阅号又发布新消息,消息ID为1002
LPUSH msg:{用户ID} 1002
(3)查看最新微博消息
LRANGE msg:{用户ID} 0 4

Set

Set常用操作:

命令 描述 例子
SADD key member [member …] 往集合key中存入元素,元素存在则忽略,若key不存在则新建 SADD myset “hello” “I” “am” “liwq”
SREM key member [member …] 从集合key中删除元素 SREM myset “hello”
SMEMBERS key 获取集合key中所有元素 SMEMBERS myset
SCARD key 获取集合key的元素个数 SCARD myset
SISMEMBER key member 判断member元素是否存在于集合key中 SISMEMBER myset “hello”
SRANDMEMBER key [count] 从集合key中选出count个元素,元素不从key中删除 SRANDMEMBER myset 2
SPOP key [count] 从集合key中选出count个元素,元素从key中删除 SPOP myset 1
SINTER key [key …] 交集运算 SINTER myset myset2
SINTERSTORE destination key [key ..] 将交集结果存入新集合destination中 SINTERSTORE myset3 myset myset2
SUNION key [key ..] 并集运算 SUNION myset myset2
SUNIONSTORE destination key [key …] 将并集结果存入新集合destination中 SUNIONSTORE myset3 myset myset2
SDIFF key [key …] 差集运算 SDIFF myset myset2
SDIFFSTORE destination key [key …] 将差集结果存入新集合destination中 SDIFFSTORE myset3 myset myset2

Set应用场景:参与抽奖活动
image.png
(1)用户点击参与抽奖,后台将用户加入集合
SADD key {userlD}
(2)后台查看参与抽奖所有用户
SMEMBERS key
(3)后台随机抽取count名中奖者
SRANDMEMBER key [count] / SPOP key [count]

ZSet

ZSet常用操作:

命令 描述 例子
ZADD key score1 member1 [score2 member2] 往有序集合key中加入带分值元素 ZADD myzset 2 “two” 3 “three”
ZREM key member [member …] 从有序集合key中删除元素 ZREM myzset two
ZSCORE key member 返回有序集合key中元素member的分值 ZSCORE myzset two
ZINCRBY key increment member 为有序集合key中元素member的分值加上increment ZINCRBY myzset 111 two
ZCARD key 返回有序集合key中元素个数 ZCARD myzset
ZRANGE key start stop [WITHSCORES] 正序获取有序集合key从start下标到stop下标的元素 ZRANGE myzset 1 2 WITHSCORES
ZREVRANGE key start stop [WITHSCORES] 倒序获取有序集合key从start下标到stop下标的元素 ZREVRANGE myzset 1 1 WITHSCORES
ZUNIONSTORE destkey numkeys key [key …] 计算给定的一个或多个有序集的并集,并存储在新的 key 中 ZUNIONSTORE outzset 2 zset1 zset2
ZINTERSTORE destkey numkeys key [key …] 计算给定的一个或多个有序集的并集,并存储在新的 key 中 ZINTERSTORE outzset 2 zset1 zset2

ZSet应用场景:热点排行榜
image.png
Zset集合操作实现排行榜
(1)点击新闻
ZINCRBY hotNews:20190819 1 守护香港
(2)展示当日排行前十
ZREVRANGE hotNews:20190819 0 9 WITHSCORES
(3)七日搜索榜单计算
ZUNIONSTORE hotNews:20190813-20190819 7
hotNews:20190813 hotNews:20190814… hotNews:20190819
(4)展示七日排行前十
ZREVRANGE hotNews:20190813-20190819 0 9 WITHSCORES