Redis功能介绍

数据类型丰富
支持持久化
多种内存分配及回收策略
支持事务
消息队列,消息订阅
支持高可用
支持分布式集群
缓存穿透\雪崩 # 一般是因为服务端代码设计问题,运维可以了解
Redis API

企业缓存产品介绍

Memcached:
优点:高性能读写,单一数据类型,支持客户端分布式集群,一致性hash
多核结构,多线程读写性能高.
缺点:无持久化,节点故障可能出现缓存穿透,分布式需要客户端实现,跨机房数据同步困难,架构扩容复杂度高

Redis:
优点:高性能读写,多数据类型支持,数据持久化,高可用架构,支持自定义虚拟内存,支持分布式分片集群,单线程读写性能极高
缺点:多线程读写较Memcached慢
新浪,京东,直播类平台,网页游戏

memcached 与redis在读写性能的对比
memcached 适合,多用户访问,每个用户少量的rw
redis 适合,少用户访问,每个用户大量的rw

Tair(阿里云云数据库redis版可以选购Tair产品):
优点:高性能读写,支持三种存储引擎(ddb,rdb,ldb),支持高可用,支持分布式分片集群,支撑了几乎所有淘宝业务的缓存.
缺点:单机情况下,读写性能较其他两种产品较慢

Redis使用场景介绍

Memcached: 多核的缓存服务器,更加适合于多用户并发访问次数较少的应用场景
Redis: 单核的缓存服务,单节点情况下,更加适合于少量用户,多次访问的应用场景.
Redis一般是单机多实例架构,配合redis集群出现.


Redis安装部署

下载
wget http://download.redis.io/releases/redis-6.0.6.tar.gz
解压:
tar xf redis-6.0.6.tar.gz 
上传至/data
mv redis-6.0.6 /data
cd /data
mv redis-6.0.6 redis

安装依赖:
yum -y install centos-release-scl
yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils
scl enable devtoolset-9 bash
yum -y install gcc automake autoconf libtool make

安装:
cd redis
make && make install

环境变量:
vim /etc/profile 
export PATH=$PATH:/data/redis/src # 向后追加
source /etc/profile  # 环境变量加载生效

启动:
redis-server &

连接测试:
[root@localhost src]# redis-cli 
127.0.0.1:6379> set num 10
OK
127.0.0.1:6379> get num
"10"


Redis基本管理操作

基础配置文件介绍

mkdir /data/6379
cat > /data/6379/redis.conf<<EOF
daemonize yes
port 6379
logfile /data/6379/redis.log
dir /data/6379
dbfilename dump.rdb
EOF

redis-cli shutdown # redis非交互式直接关闭服务
redis-server /data/6379/redis.conf # 根据配置文件启动redis服务
netstat -lnp |grep 63  # 查看redis启动进程

+++++++++++++++++++配置文件说明+++++++++++++++++++++++
redis.conf
是否后台运行:
daemonize yes
默认端口:
port 6379  生产环境中一般会改成其他的监听端口并且加上密码认证,这样即使redis公网暴露,它所在服务器不会因为被天眼搜到而遭遇公鸡,
日志文件位置
logfile /data/6379/redis.log
持久化文件存储位置
dir /data/6379
RDB持久化数据文件
dbfilename dump.rdb
++++++++++++++++++++++++++++++++++++++++++++++++++++


redis安全配置

redis默认开启了保护模式,只允许本地回环地址登录并访问数据库.
禁止protected-mode
protected-mode yes/no (保护模式,是否只允许本地访问)
当我们安装的redis服务需要被外部调用的时候,就得关闭保护模式,当关闭保护模式后就意味着谁都可以连,所以下面我们还需要设定绑定ip地址段
允许那些ip地址段可以连,设置requirepass增加密码认证使外部调用redis更加安全

(1)Bind: 指定IP进程监听
vim /data/6379/redis.conf
bind 10.0.0.81 127.0.0.1

(2)增加requirepass {password}
vim /data/6379/redis.conf
requirepass 123456

--------------验证----------------------------
方法一:
[root@localhost src]# redis-cli -h 10.0.0.81 -p 6379 -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
10.0.0.81:6379> set name zhangsan
OK
10.0.0.81:6379> exit
方法二:
[root@localhost src]# redis-cli -h 10.0.0.81
10.0.0.81:6379> auth 123456
OK
10.0.0.81:6379> set a b
OK

在线查看和修改配置

在生产环境中在线修改配置一般是不会使用的,因为在线修改的配置在服务重启后就会失效, 一般在测试环境中进行服务调优测试的时候可能会用到

CONFIG GET *
CONFIG GET requirepass
CONFIG GET r*
CONFIG SET requirepass 123


redis持久化(内存数据保存到磁盘)

RDB, AOF

RDB 持久化
     可以在指定的时间间隔内生成数据集的时间快照(point-in-time snapshot)
     优点: 速度快,适合于用做备份,主从复制也是基于RDB持久化功能实现的.
     缺点: 会有数据丢失

rdb持久化核心配置参数:
vim /data/6379/redis.conf
dir /data/6379
dbfilename dump.rdb
save 900 1
save 300 10
save 60 10000

配置分别表示:
900秒(15分钟)内有1个更改
300秒(5分钟)内有10个更改
60秒内有10000个更改

配置策略该设置多少完全取决于你对数据丢失的容忍度,当你追求性能的时候,数据丢失势必顾及就少了,当你追求数据安全的时候那么性能追求肯定会
受到影响,如何平衡配置可以根据自己业务情况来定

AOF 持久化(append-only log file)
    记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集.
    AOF 文件中的命令全部以Redi协议的格式来保存,新命令会被追加到文件的末尾
    优点: 可以最大程度保证数据不丢
    缺点: 日志记录量级比较大,吃磁盘空间

AOF 持久化配置
appendonly yes
appendfsync always
appendfsync everysec
appendfsync no

是否打开aof日志功能
每一个命令,都立即同步到aof
每秒写1次
写入工作交给操作系统,由操作系统判断缓冲区大小,统一写入到aof

vim /data/6379/redis.conf
appendonly yes
appendfsync everysec


Redis数据类型

## 6.1 介绍
String:       字符类型
Hash:         字典类型
List:         列表
Set:          集合
Sorted set:   有序集合


KEY的通用操作

KEYS *  keys a keys a*                   查看已存在所有键的名字   ****
TYPE                                     返回键所存储值的类型     ****
EXPIRE\PEXPIRE                           以秒\毫秒设定生存时间    ***
TTL\PTTL                                 以秒\毫秒为单位返回生存时间  ***
PERSIST                                  取消生存时间设置         ***
DEL                                      删除一个key
EXISTS                                   检查key是否存在
RENAME                                   变更KEY名


Strings

应用场景
session 共享
常规计数: 微博数,粉丝数,订阅,礼物

计数器
每点一次关注,都执行以下命令一次
10.0.0.81:6379> incr num
(integer) 1
显示粉丝数量:
10.0.0.81:6379> get num
"1"

暗箱操作
10.0.0.81:6379> INCRBY num 10000
(integer) 10001
10.0.0.81:6379> get num
"10001"
10.0.0.81:6379> DECRBY num 10000
(integer) 1
10.0.0.81:6379> get num
"1"


hash类型(字典类型)

应用场景:
存储部分变更的数据,如用户信息等.
最接近mysql表结构的一种类型
主要是可以做数据库缓存

存数据:
hmset stu id 101 name zhangsan  age 20 gender m

取数据:
hmget stu id name age gender

LIST(列表)

应用场景
消息队列系统
比如snina微博
但在Redis中我们的最新微博ID使用了常驻缓存,这是一直更新的
但是做了限制不超过5000个ID,因此获取ID的函数会一直询问Redis.
只有在start/count参数超出了这个范围的时候,才需要去访问数据库.
系统不会像传统方式那样"刷新"缓存,Redis实例中的信息永远是一致的
sql数据(或是硬盘上的其他类型数据库)只是在用户需要获取"很远"的数据时才会被触发,
而主页或第一个评论页是不会麻烦到硬盘上的数据库了.

朋友圈:
0.0.0.81:6379> LPUSH wechat "today is nice day"
(integer) 1
10.0.0.81:6379> LPUSH wechat "today is bad day"
(integer) 2
10.0.0.81:6379> LPUSH wechat "today is good day"
(integer) 3
10.0.0.81:6379> LPUSH wechat "today is rainy day"
(integer) 4
10.0.0.81:6379> LPUSH wechat "today is Friday day"
(integer) 5
10.0.0.81:6379> LRANGE wechat 0 -1
1) "today is Friday day"
2) "today is rainy day"
3) "today is good day"
4) "today is bad day"
5) "today is nice day"
10.0.0.81:6379> LRANGE wechat 0 0
1) "today is Friday day"
10.0.0.81:6379> LRANGE wechat 1 1
1) "today is rainy day"
10.0.0.81:6379> LRANGE wechat 2 2
1) "today is good day"
10.0.0.81:6379>


set集合类型(join union)

应用场景:
案例:在微博应用中,可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合.
Redis还未集合提供了求交集,并集,差集等操作,可以非常方便的实现如共同关注,共同喜好,二度好友等功能.
对上面的所有集合操作,你还可以使用不同的命令选择将结果返回给客户端还是存集到一个新的集合中.

存储:sadd key value
 
获取:smembers  key
 
删除:srem key value 
        删除set集合中的某个元素

其他操作
sismember <key> <member>
        判断集合<key>是否为含有该<member>值,有1,没有0
 
scard <key>
        返回该集合的元素个数。
 
spop <key>
        随机从该集合中吐出一个值。
 
srandmember <key> <n>
        随机从该集合中取出n个值。不会从集合中删除 。
 
smove <source> <destination> <member>
        把集合中一个值从一个集合移动到另一个集合
 
sinter <key1> <key2>
        返回两个集合的交集元素。
 
sunion <key1> <key2>
        返回两个集合的并集元素。
 
sdiff <key1> <key2>
        返回两个集合的差集元素(key1中的,不包含key2中的)


SortedSet(有序集合)

应用场景:
排行榜应用,取TOP N操作
这个需求与上面需求的不同之处在于,前面操作以时间为权重,这个是以某个条件为权重,比如按顶的次数排序,
这时候就需要我们sorted set出马了,讲你要排序的值设置成sorted set的score,将具体的数据设置成相应的value,
每次只需要执行一条ZADD命令即可

10.0.0.81:6379> ZADD runoobkey 1 redis
(integer) 1
10.0.0.81:6379> ZADD runoobkey 2 mongodb
(integer) 1
10.0.0.81:6379> ZADD runoobkey 3  mysql
(integer) 1
10.0.0.81:6379> ZRANGE runoobkey 0 -1 WITHSCORES
1) "redis"
2) "1"
3) "mongodb"
4) "2"
5) "mysql"
6) "3"


Redis弱事务

redis的事务是基于队列实现的,redis是乐观锁机制.
mysql的事务是基于事务日志和锁机制实现的.

开启事务功能时(multi)
multi
command1
command2
command3
command4
exec
discard

4条语句作为一个组,并没有真正执行,而是被放入同一队列中
如果,这时执行discard,会直接丢弃队列中所有的命令,而不是做回滚.
exec
当执行exec时,队列中所有操作,要么全成功要么全失败
10.0.0.81:6379> MULTI
OK
10.0.0.81:6379> set a 1
QUEUED
10.0.0.81:6379> set c d
QUEUED
10.0.0.81:6379> exec
1) OK
2) OK

watch

ACID:
A: 事务队列
C: 集群
I: watch
D: ADF always


redis(Master-Replica)

原理

副本库通过slaveof 10.0.0.81 6379命令,连接主库,并发送SYNC给主库
主库收到SYNC,会立即触发BGSAVE,后台保存RDB,发送给副本库
副本库接收到会应用RDB快照
主库会陆续将中间产生的新的操作,保存并发送给副本库
到此,我们主复制集就正常工作了
再此以后,主库只要发生新的操作,都会以命令传播的形式自动发送给副本库
所有复制相关信息,从info信息中都可以查到,即使重启任何节点,他的主从关系依然都在
如果发生主动关系断开时,从库数据库没有任何损坏,在下次重连之后,从库发送PSYNC(PSYNC2)给主库
主库只会将从库缺失部分的数据同步给从库应用,达到快速恢复主从的目的

主从数据一致性保证

min-slaves-to-write 1
min-slaves-max-lag 3


主库是否要开启持久化?

如果不开持久化,有可能主库重启操作,造成所有主从数据丢失!


主从复制实现

1,环境
准备两个或两个以上redis实例

mkdir /data/638{0..2}

配置文件示例:
cat >> /data/6380/redis.conf <<EOF
port 6380
daemonize yes
pidfile /data/6380/redis.pid
loglevel notice
logfile "/data/6380/redis.log"
dbfilename dump.rdb
dir /data/6380
requirepass 123
masterauth 123
EOF

cat >> /data/6381/redis.conf <<EOF
port 6381
daemonize yes
pidfile /data/6381/redis.pid
loglevel notice
logfile "/data/6381/redis.log"
dbfilename dump.rdb
dir /data/6381
requirepass 123
masterauth 123
EOF

cat >> /data/6382/redis.conf <<EOF
port 6382
daemonize yes
pidfile /data/6382/redis.pid
loglevel notice
logfile "/data/6382/redis.log"
dbfilename dump.rdb
dir /data/6382
requirepass 123
masterauth 123
EOF

可以看到3个实例密码都是设置一样的,其中masterauth配置项为从库连接主库所需要的验证密码,主实例也配置上masterauth项是为了应对后面
可能出现的主从切换情况

启动
redis-server /data/6380/redis.conf
redis-server /data/6381/redis.conf
redis-server /data/6382/redis.conf

主节点:6380
从节点: 6381, 6382

开启主从:
6381/6382命令行:

redis-cli -p 6381 -a 123 SLAVEOF 127.0.0.1 6380
redis-cli -p 6382 -a 123 SLAVEOF 127.0.0.1 6380

查询主从状态
redis-cli -p 6380 -a 123 info replication
redis-cli -p 6381 -a 123 info replication
redis-cli -p 6382 -a 123 info replication

解除主从关系
从节点上运行命令
redis-cli -p 6382 -a 123 SLAVEOF no


redis-sentinel(哨兵)

监控
自动选主,切换
2号从库(6382)指向新主库(6381)
应用透明
自动处理故障节点

sentinel搭建过程

mkdir /data/26380
cd /data/26380
vim sentinel.conf
port 26380
dir "/data/26380"
sentinel monitor mymaster 127.0.0.1 6380 1
sentinel down-after-milliseconds mymaster 5000
sentinel auth-pass mymaster 123

启动:
[root@localhost 26380]# redis-sentinel /data/26380/sentinel.conf & > /tmp/sentinel.log &

================================================================
如果有问题:
1,重新准备1主2从环境
2,kill掉sentinel进程
3,删除sentinel目录下的所有文件
4,重新搭建sentinel

================================================================

停主库测试
[root@localhost ~]# redis-cli -p 6380 -a 123 shutdown
[root@localhost ~]# redis-cli -p 6381 -a 123 info replication
[root@localhost ~]# redis-cli -p 6382 -a 123 info replication

启动源主库(6380),看状态
[root@localhost ~]# redis-server /data/6380/redis.conf 
[root@localhost ~]# redis-cli -p 6380 -a 123 info replication
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
# Replication
role:master
connected_slaves:0
master_replid:13320334c0cc2b3b1891fffd6b24cf9d1a9f0288
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0


redis cluster


Redis从基础到高阶_持久化


介绍

高性能

在多分片节点中,将16384个槽位,均匀分布到多个分片节点中
存数据时,将key做crc16(key),然后和16384进行取模,得出槽位值(0-16384)之间
根据计算得出的槽位值,找到对应的分片节点的主节点,存储到相应槽位上
如果客户端当时连接的节点不是将来要存储的分片节点,分片集群会将客户端连接切换至真正存储节点进行数据存储


高可用

在搭建集群时,会为每一个分片的主节点,对应一个从节点,实现slaveof的功能,同时当主节点down,实现类似于sentinel的自动failover的功能

redis会有多组分片构成(最小3组)
redis cluster 使用固定个数的slot存储数据(一共16384 slot)
每组分片分得1/3 slot个数
基于CRC16(key) % 16384 ==== >值 取模


规划,搭建过程

6个redis实例,一般会放到3台硬件服务器
注: 在企业规划中,一个分片的两个分到不同的物理机,防止硬件主机宕机造成的整个分片数据丢失.

集群节点准备

mkdir /data/700{0..5}
cat > /data/7000/redis.conf << EOF
port 7000
daemonize yes
pidfile /data/7000/redis.pid
loglevel notice
logfile "/data/7000/redis.log"
dbfilename dump.rdb
dir /data/7000
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
EOF

cat > /data/7001/redis.conf << EOF
port 7001
daemonize yes
pidfile /data/7001/redis.pid
loglevel notice
logfile "/data/7001/redis.log"
dbfilename dump.rdb
dir /data/7001
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
EOF

cat > /data/7002/redis.conf << EOF
port 7002
daemonize yes
pidfile /data/7002/redis.pid
loglevel notice
logfile "/data/7002/redis.log"
dbfilename dump.rdb
dir /data/7002
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
EOF
....

启动节点

redis-server /data/7000/redis.conf 
redis-server /data/7001/redis.conf 
redis-server /data/7002/redis.conf 
redis-server /data/7003/redis.conf 
redis-server /data/7004/redis.conf 
redis-server /data/7005/redis.conf
[root@localhost ~]# ps -ef |grep redis
root      3016     1  0 11月29 ?      00:20:33 redis-server *:6381
root      3022     1  0 11月29 ?      00:22:23 redis-server *:6382
root      3365 42782  0 11月29 pts/0  00:23:10 redis-sentinel *:26380 [sentinel]
root      3455     1  0 11月29 ?      00:21:41 redis-server *:6380
root     43084     1  0 11月27 ?      00:23:51 redis-server 10.0.0.81:6379
root     62023     1  0 15:59 ?        00:00:00 redis-server *:7000 [cluster]
root     62029     1  0 15:59 ?        00:00:00 redis-server *:7001 [cluster]
root     62035     1  0 15:59 ?        00:00:00 redis-server *:7002 [cluster]
root     62041     1  0 15:59 ?        00:00:00 redis-server *:7003 [cluster]
root     62047     1  0 15:59 ?        00:00:00 redis-server *:7004 [cluster]
root     62053     1  0 15:59 ?        00:00:00 redis-server *:7005 [cluster]

将节点加入集群管理

redis-cli --cluster create \
10.0.0.81:7000 10.0.0.81:7001 \
10.0.0.81:7002 10.0.0.81:7003 \
10.0.0.81:7004 10.0.0.81:7005 \
--cluster-replicas 1

集群状态查看

集群主节点状态
redis-cli -p 7000 cluster nodes |grep master
集群从节点状态
redis-cli -p 7000 cluster nodes |grep

集群节点管理

新增新节点

mkdir /data/700{6..7}
cat > /data/7006/redis.conf << EOF
port 7006
daemonize yes
pidfile /data/7006/redis.pid
loglevel notice
logfile "/data/7006/redis.log"
dbfilename dump.rdb
dir /data/7006
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
EOF

cat > /data/7007/redis.conf << EOF
port 7007
daemonize yes
pidfile /data/7007/redis.pid
loglevel notice
logfile "/data/7007/redis.log"
dbfilename dump.rdb
dir /data/7007
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
EOF

redis-server /data/7006/redis.conf 
redis-server /data/7007/redis.conf

添加主节点

redis-cli --cluster add-node 10.0.0.81:7006 10.0.0.81:7000

移动slot(重新分片)

redis-cli --cluster reshard 10.0.0.81:7000

添加一个从节点

redis-cli --cluster add-node --cluster-slave --cluster-master-id \
3de39fd16c83909d47695e08cd73b0c6452d547e 10.0.0.81:7007 10.0.0.81:7000

删除节点

将需要删除节点slot移动走

redis-cli --cluster reshard 10.0.0.81:7000

删除一个节点

redis-cli --cluster del-node 10.0.0.81:7006 3de39fd16c83909d47695e08cd73b0c6452d547e


redis的多api支持

yum install -y python36
python3 -V
yum install -y python36-pip
pip3 install redis
pip3 install redis-py-cluster

对redis单实例进行连接操作

[root@localhost ~]# redis-server /data/6379/redis.conf 
[root@localhost ~]# python3
Python 3.6.8 (default, Nov 14 2023, 16:29:52) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import redis
>>> r = redis.StrictRedis(host='10.0.0.81', port=6379, db=0, password='123456')
>>> r.set('test', 'oldpeng')
True
>>> r.get('test')
b'oldpeng'

sentinel集群连接并操作

### 导入redis sentinel包
>>> from redis.sentinel import Sentinel
## 指定sentinel的地址和端口号
>>> sentinel = Sentinel([('localhost', 26380)], socket_timeout=0.1)
### 测试,获取以下主库和从库的信息
>>> sentinel.discover_master('mymaster')
('127.0.0.1', 6382)
>>> sentinel.discover_slaves('mymaster')
[('127.0.0.1', 6380), ('127.0.0.1', 6381)]

###配置读写分离

###写节点
>>> master = sentinel.master_for('mymaster', socket_timeout=0.1, password="123")

###读节点
>>> slave = sentinel.slave_for('mymaster', socket_timeout=0.1, password="123")

###读写分离测试
>>> master.set('test', '123')
True
>>> slave.get('test')
b'123'

python连接rediscluster集群测试

>>> from rediscluster import RedisCluster
>>> startup_nodes=[{"host": "10.0.0.81", "port": "7000"}, {"host": "10.0.0.81", "port": "7001"}, {"host": "10.0.0.81", "port": "7002"}]
>>> rc = RedisCluster(startup_nodes=startup_nodes, decode_responses=True)
>>> rc.set("foo", "bar")
True
>>> print(rc.get("foo"))
bar


redis常见运维操作

批量删除key

redis-cli -h redis地址 -p 6379 -a 'redis密码' keys 'au:*' | xargs redis-cli -h redis地址 -p 6379 -a 'redis密码' del


查询大key

redis-cli --bigkeys


通过info命令将redis单实例,redis主从,redis集群 信息收集做监控

redis-cli info
redis-cli info replication
redis-cli cluster info