Redis缓存中间件
一、什么是Redis?
高性能的内存Key-Value数据库。
二、应用场景?
1、数据缓存
2、会话共享
3、秒杀场景
4、抢红包场景
5、预约排号
6、消息队列
7、分布式锁场景
8、分布式事务场景
9、分布式唯一ID生成
10、附近的人场景
三、Redis的安装
第一步:官网下载安装包
官网地址:https://redis.io/
第二步:上传安装包到linux系统
第三步:解压安装包
tar -zxvf redis-6.0.8.tar.gz
第四步:编译Redis源文件
make PREFIX=/usr/local/redis install
###如果编译出现问题可以执行以下命令清理后重新编译###########
make clean ##清理编译文件
如果出现以下编译错误,则需要升级或安装编译依赖库。
error: ‘struct redisServer’ has no member named ‘masterhost
解决该问题依次执行以下命令:
yum -y install centos-release-scl
yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils
scl enable devtoolset-9 bash
如果缺少GCC编译库执行以下命令安装:
yum install cpp
yum install binutils
yum install glibc
yum install glibc-kernheaders
yum install glibc-common
yum install glibc-devel
yum install gcc
yum install make
第五步:拷贝配置文件
cd /etc
mkdir redis
cp /opt/redis-6.0.8/redis.conf /etc/redis/
cp /opt/redis-6.0.8/sentinel.conf /etc/redis/
第六步:启动Redis服务
cd /usr/local/redis/bin
./redis-server /etc/redis/redis.conf
######查看Redis启动进程信息可以使用以下方式#########
./redis-cli -p 6379
#或者
ps -ef|grep redis
#或者
netstat -an|grep 6379
第七步:开放Redis端口
firewall-cmd --zone=public --add-port=6379/tcp --permanent
systemctl restart firewalld.service
firewall-cmd --reload
第八步:编写Redis启动脚本,注册开机启动
#!/bin/bash
#
# Redis Starts redisd
#
#
# chkconfig: 123456 99 01
# description: Redis server
### BEGIN INIT INFO
# Provides: $redisd
### END INIT INFO
# Source function library.
if [ -f /etc/init.d/functions ]; then
. /etc/init.d/functions
fi
PRG=/usr/local/redis/bin/redis-server #指定Redis的启动命令脚本位置, 如果是其他的则指定相应的启动命令脚本位置
CONF=/etc/redis/redis.conf #指定Redis的配置文件所在位置
if [ ! -f $PRG ]; then
echo "file $PRG does not exist!"
exit 2
fi
##如果没有配置文件则以下可以删除
if [ ! -f $CONF ]; then
echo "file $CONF does not exist!"
exit 2
fi
######
CMD="$PRG $CONF" ##如果没有配置文件 则修改为 CMD="$PRG"
RETVAL=0
start() {
echo -n $"Starting Redis server: " ##设置启动后显示的提示信息
$CMD &
RETVAL=$?
echo
return $RETVAL
}
stop() {
$CMD stop
RETVAL=$?
return $RETVAL
}
rhstatus() {
status redisd #注意该处需要指定成启动脚本的名称,例如:redisd
}
restart() {
$CMD restart &
}
case "$1" in
start)
start
;;
stop)
stop
;;
status)
rhstatus
;;
restart|reload)
restart
;;
condrestart)
restart
;;
*)
echo $"Usage: $0 {start|stop|status|restart|condrestart}"
exit 1
esac
将编写的启动脚本文件存放 /etc/rc.d/init.d目录,并注册启动服务。
cd /etc/rc.d/init.d
chmod 755 redisd
chkconfig --add redisd
service redisd start
第九步:修改Redis配置文件开启远程访问
cd /etc/redis/redis
vi redis.conf
#### 修改配置文件的以下内容########
# bind 127.0.0.1 注释掉
# protected-mode yes 修改为protected-mode no
# daemonize no 修改为daemonize yes 让redis在后台进程运行
四、Redis内建支持的数据类型
1、string 字符串类型(SDS)
- string是Redis最基本的数据类型,一个key对应一个string。
- string 类型是二进制安全的。意思是 redis 的 string 任意格式的二进制数据。比如jpg图片或者序列化的对象。
- string 类型的值最大能存储 512M
应用场景:
分布式锁;分布式ID生成器;一般常规数据的缓存。
2、list 列表集合 (ziplist 或者 linkedlist)
List是简单的字符串列表,数据结构是双向链表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边),也就是兼有栈和队列的特性。因为是链表,所以查找的复杂度就是O(n)了,但是考虑到常用的指令都是在列头和列尾操作,所以这种数据结构才是最适合的。
应用场景:
经常会被用于消息队列的服务,以完成多程序之间的消息交换。
生产者-消费者模型的实现
3、set 无序数据集 ( intset 或者 hashtable)
Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。
Redis 中集合是通过哈希表实现的,其实就是一个值为null的hashmap,所以添加,删除,查找的复杂度都是 O(1),也可以通过计算hash来排重和判断一个数据是否在集合中。
应用场景:
1、利用交集求共同好友。
2、利用唯一性,可以统计访问网站的所有独立IP。
3、好友推荐的时候根据tag求交集,大于某个threshold(临界值的)就可以推荐。
4、zset 可排序无序数据集( ziplist 或者 skiplist)
sorted set和Set一样也是string类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。
有序集合的成员是唯一的,但分数(score)却可以重复。
Redis sorted set 内部使用了ziplist和SkipList两种实现,当同时满足元素数量小于128个和所有member的长度都小于64个字节的时候会采用ziplist,如果不满足则采用SkipList的编码方式。当然可以通过Redis配置zset-max-ziplist-entries 和 zset-max-ziplist-value来修改这两个条件。
应用场景:
(1)例如存储全班同学的成绩,其集合value可以是同学的学号,而score就可以是成绩。
(2)排行榜应用,根据得分列出topN的用户等。
5、hash 类型(ziplist 或者 hashtable)
hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。通过命名很清楚的之后Hash这种数据类型时使用了哈希表作为底层实现。
应用场景:
存储一些结构化的数据,比如用户的昵称、年龄、性别、积分等,存储一个用户信息对象数据。
6、位图
7、流
五、Redis操作命令
5.1、string类型的操作命令
#最基本的缓存设置命令
set key value
#最基本的获取缓存命令
get key
set key value nx ##key不存在时 进行缓存设置;存在时不操作
set key value xx ##key存在时 进行缓存覆盖;不存在时不操作
### 当值为数字时,我们可以实现原子数值得递增递减###
incr key ##返回原子递增以后的值
incrby key incr_number ### 原子增加指定的数值 incr_number[增加的指定数值]
decr key ##返回原子递减以后的值
decrby key decr_number ### 原子递减指定的数值 decr_number[增加的指定数值]
getset key newValue ### 设置key的新缓存值,返回老的缓存值
mset key1 value1 key2 value2 ###批量一次缓存多个key-value
mget key1 key2 ###批量一次获取多个key-value
5.2、list类型的操作命令
#设置缓存值
lpush key value1 value2 value3 ##列表头部缓存
rpush key value value2 value3 ##列表尾部缓存
lrange key from to ##获取列表区间缓存值,这个特性可以实现缓存分页。注意:范围是一个闭区间,而且取值的顺序与写入顺序相反。
#获取缓存值
lpop key ##一次从列表中获取到一个值,并且该值获取以后会从列表删除
rpop key ##同上
#批量删除缓存值
ltrim key from to ##保留指定区间的缓存值,指定区间以外的全部删除
#阻塞队列操作
blpop key
brpop key
#查看列表的长度
llen key
5.3、hash类型的操作命令
#设置缓存值
hset redis-key hash-key hash-value #hash单个key-value
hmset redis-key hash-key1 hash-value1 hash-key2 hash-value2 #hash批量 key-value
#获取缓存值
hget redis-key hash-key #hash获取单个key-value
hmget redis-key hash-key1 hash-key2 #hash获取批量key-value
#设置hash键increament操作
hincrby redis-key hash-key number
5.4、set类型的操作命令
#设置缓存值
sadd key value1 value2 value3
#取值
spop key #取值后并且删除缓存
srandmember key #随机取一个值,但是不删除缓存
#查看成员
smembers key
#检测缓存是否在无序集中
sismember key value #value为需要检测的值
#求交集
sinter key1 key2
#求并集
sunionstore newkey key1 key2 # newkey是合并set以后创建的新的set的key
#获取列表size
scard key
5.5、zset类型的操作命令
#设置缓存值
zadd key score value
#按照打分排序,通过下标获取
zrange key from to #取正向区间
zrevrange key from to [withscores] #取反向区间
#按照打分排序,通过打分获取
#区间规则#
## 使用 -+表示左右区间
## 使用 (表示开区间 [表示闭区间
## 使用 inf(表示无限制)
##
zrangebyscore key -inf score #左区间无限制,右区间为具体值 ,注意:默认没有指定区间则为闭区间
zrangebyscore key score1 score2 #左右闭区间
zrangebyscore key -inf +inf #左右区间无限制
zrangebyscore key (score1 (score2 #左右开区间
zrangebyscore key (score1 [sorce2 #左开右闭
zrangebyscore key [score1 (sorce2 #左闭右开
zrangebyscore key [score1 [sorce2 #左右闭区间
#按照字符排序,通过字符获取
#区间规则不变
zrangebylex key [字符1 [字符2 #字符左右闭区间
zrevrangebylex key [字符1 [字符2 #字符反向左右闭区间
#区间移除
zremrangebyscore key score1 score2 #按打分移除, 区间规则不变
zremrangebylex key [字符1 [字符2 #按字符移除,区间规则不变
#获取元素的下标
zrank key value #升序取下标
zrevrank key value #倒序取下标
#获取字符之间存在的缓存值的数目
zlexcount key - + #不限制字符,即全部统计
zlexcount key [字符1 [字符2 #统计限定字符内的在排序集中的个数
5.6、通用的操作命令
##删除缓存
del key
##检测缓存的Key
exists key
##查看缓存的类型
type key
##获取所有配置项
config get *
##获取缓存对象使用的数据结构
object encoding key
5.7、缓存过期操作命令
##key存在后设置过期
expire key second ### 过期时间单位为秒
pexpire key milliseconds ###过期时间单位为毫秒
##缓存key-value时设置过期
set key value ex second
set key value px milliseconds
##持久化key-value
persist key ###将key-value持久存储到redis数据库,这样redis宕机或者重起缓存不会丢失
##查看key-value存活时间
ttl key ###查看存活时间,秒为单位
pttl key ###查看存活时间,毫秒为单位
5.8、分布式锁操作命令
#第一种方式
setnx key value
expire key second
#第二种方式
set key value nx ex 5
六、Redis缓存存在的问题
6.1、缓存穿透
访问的数据在缓存中和数据库都不存在。当有大量请求进行不存在数据的访问时会直接穿过缓存层访问数据库,此时缓存层如同虚设。在高并发的情况下缓存层失去屏蔽层的重要作用,直接将数据压死,导致系统崩溃。
解决方案:
1、直接缓存空值,同时要设置过期时间, 获取数据库数据的方法需要加锁。
2、使用布隆过滤器。
补充:
布隆过滤器的应用场景是海量数据中判断某些值是否存在。
6.2、雪崩效应
当有大量请求访问缓存,在访问的同一时刻需要被访问的缓存集体过期,造成请求的穿透到数据库层,瞬时将数据库压死,导致系统垮掉。
解决方案:
1、缓存预热, 同时设置过期时间时,给过期时间加一个随机值。
2、热点数据不过期。
3、缓存不过期,同时使用数据库与redis同步策略解决缓存更新问题。
6.3、缓存击穿
当有大量请求访问缓存,在访问的同一时刻需要被访问的某一个缓存过期,造成请求的穿透到数据库层,将数据库压死,导致系统垮掉。
解决方案:
1、在数据库加载数据的方法上加锁。
2、热点数据可以设置为不过期。
七、集群搭建问题解决
通过 redis-cli连接集群的某个节点时报
(error) CLUSTERDOWN Hash slot not served(不提供集群的散列槽)
说明集群节点还不在一个集群中,节点之间还不能互相发现,没有分配存储位置,就是所谓的slot(槽)。slot是redis会根据缓存key进行hash节点分布的位置,在 Redis 集群中有且仅有 16384 个 solt ,默认情况会给我们平均分配。
需要安装集群所需软件,依次执行以下命令:
yum install centos-release-scl-rh
yum install rh-ruby23 -y
scl enable rh-ruby23 bash
gem install redis
以上部分在redis的最新6.x版以上是否还是必须的?
注册创建集群:
./redis-cli --cluster create 192.168.44.128:6380 192.168.44.128:6381 192.168.44.128:6382
##或者指定集群备份,通常集群最低需要三个master,此时每个master如果设置一个备份则需要6个节点(含master)
./redis-cli --cluster create 192.168.44.128:6380 192.168.44.128:6381 192.168.44.128:6382 --cluster-relicas 1