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 //执行完业务释放锁
- 计数器
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
电商购物车
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
我们也可以合理利用List指令,实现公众号消息排版,新发的消息在前面:
(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应用场景:参与抽奖活动
(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应用场景:热点排行榜
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