Redis 安装配置开机启动整合SpringBoot以及配置文件详解

安装 Redis

# 下载Redis
wget https://download.redis.io/releases/redis-6.0.9.tar.gz

# 解压 redis
tar -zxvf redis-6.0.9.tar.gz

# 安装 gcc 环境, 安装过 忽略
yum -y install gcc-c++

cd redis-5.0.5 

# 安装 
make && make install

Redis 配置启动脚本


# 拷贝 utils 目录下的 redis_init_script 到 /etc/init.d 目录下  redis_init_script 是启动脚本
cp utils/redis_init_script /etc/init.d

cd /etc/init.d

vim /etc/init.d/redis_init_script

# ----------------- redis_init_script start ---------------
#!/bin/sh
#
# Simple Redis init.d script conceived to work on Linux systems
# as it does use of the /proc filesystem.

### BEGIN INIT INFO
# Provides:     redis_6379
# Default-Start:        2 3 4 5
# Default-Stop:         0 1 6
# Short-Description:    Redis data structure server
# Description:          Redis data structure server. See https://redis.io
### END INIT INFO

# redis 默认端口
REDISPORT=6379
# redis 默认启动 redis-server 位置
EXEC=/usr/local/bin/redis-server
# redis redis-cli 位置
CLIEXEC=/usr/local/bin/redis-cli

# redis pid 位置 拼接了默认端口参数。 
PIDFILE=/var/run/redis_${REDISPORT}.pid
# redis 默认配置的conf 配置文件
CONF="/usr/local/redis/conf/redis.conf"

# $1 参数 为 start 或者 stop 
case "$1" in
    start)
        if [ -f $PIDFILE ]
        then
                echo "$PIDFILE exists, process is already running or crashed"
        else
                echo "Starting Redis server..."
				$EXEC $CONF
        fi
        ;;
    stop)
        if [ ! -f $PIDFILE ]
        then
                echo "$PIDFILE does not exist, process is not running"
        else
                PID=$(cat $PIDFILE)
                echo "Stopping ..."
                $CLIEXEC -p $REDISPORT shutdown
                while [ -x /proc/${PID} ]
                do
                    echo "Waiting for Redis to shutdown ..."
                    sleep 1
                done
                echo "Redis stopped"
        fi
        ;;
    *)
        echo "Please use start or stop as first argument"
        ;;
esac

# ----------------- redis_init_script end ---------------

# 保存之后启动redis 
./redis_init_script start 

# 停止 redis 
./redis_init_script stop 

配置Redis 开启自启动

# 在以下位置加上一段注释
#!/bin/sh
#
# Simple Redis init.d script conceived to work on Linux systems
# as it does use of the /proc filesystem.

### BEGIN INIT INFO
# Provides:     redis_6379
# Default-Start:        2 3 4 5
# Default-Stop:         0 1 6
# Short-Description:    Redis data structure server
# Description:          Redis data structure server. See https://redis.io
### END INIT INFO

#chkconfig: 22345 10 90
#desccription: Start and Stop redis

:wq! # 保存 

# 注册redis 到开机自启动
chkconfig redis_init_script on 

Redis 配置文件解析

# 设置后台运行  yes 后台运行, no 前台运行
daemonize yes 

# pidfile pid 目录文件
pidfile /var/run/redis_6379.pid

# dir redis 的工作空间。必须写一个目录。不能写一个文件名
dir /usr/local/redis/working

# bind 哪些ip地址可以访问 redis-server 0.0.0.0 任何地址都可以访问
bind 0.0.0.0

# requirepass 设置 redis 链接密码
requirepass 584521

SpringBoot 整合 Redis

  • 引入依赖
<dependency>
	<goupId>org.springframework.boot</goupId>
    <artifactId>spring-boot-starter-data-redis</aartifactId>
</dependency>
  • 配置 redis
spring:
	redis:
		database: 0 				# 数据库
		host: 127.0.0.1				# redis 地址
		port: 6379					# redis 端口
		password: 584521			# redis 密码
		
  • 接口测试
@ApiIgnore
@RestController
@RequestMapping("redis")
public class RedisController {
    
    @Autowired
    private RedisTemplate redisTemplate;
    
    @GetMapping("/set")
    public Object set(String key, String value) {
        redisTemplate.opsForValue().set(key, value);
        return "ok";
    }
    
    @GetMapping("get")
    public Object get(String key) {
		Object value = redisTemplate.opsForValue().get(key);
        return value;
    }
    
    @GetMapping("delete")
    public Object delete(String key) {
        redisTemplate.delete(key);
        return "ok";
    }
}
  • redis 默认使用的 JDK 的序列化机制

Redis 持久化机制

Redis RDB 机制 Redis DataBase

  • 每隔一段时间,把内存中的数据写入到磁盘的临时文件,作为快照。恢复的时候把快照文件读进内存。如果 redis 宕机重启,那么内存中的数据肯定会没有的。 重启 redis 时。从 RDB 文件中读取恢复数据
# 打开 redis.conf 文件
vim redis.conf 

# redis 工作空间
dir /usr/local/redis/working 

# rdb 持久化文件名
dbfilename dump.rdb

# save 保存到硬盘。多少时间内发生了多少次改变
save 900 1
save 300 10 
save 60 10000

# stop-writes-on-bgsave-error 保存时,发生错误停止写入操作
stop-writes-on-bgsave-error yes

# rdbcompression 压缩 rdb 文件 如果像节省cpu性能开销。 就可以关闭 no 
rdbcompression yes 

# rdbchecksum 压缩 rdb 文件以后。 是否要检验 rdb 文件。 会有百分之 10 的性能损耗
rdbchecksum yes
  • RDB 优点
    • 全量备份
    • 可以远程传输
    • 子进程备份时,主进程不会有IO操作。
  • RDB 缺点
    • rdb 持久化会有一个触发机制。如果最后的数据没有还没有触发保存。那么就有可能会导致 redis 宕机重启后,导致数据不一致

Redis AOF 机制 Append Only File

  • Redis 默认使用的是RDB模式作为持久化操作

  • 关于 AOF 的配置名称

    # 选择是否开启 aof
    
    appendonly yes
    
    # appendfilename 配置 aof 持久化文件的名称
    
    appendfilename "appendonly.aof"
    
    # appendfsync aof 文件的同步策略。 always 针对每一次的写操作。 资源占用比较大。, erverysec 每秒同步一次 no 永不同步
    
    appendfsync everysec
    
    # no-appendfsync-on-rewrite 重写的时候可以不做同步。 如果是yes 有可能会导致文件内容的不一致性
    
    bi-appendfsync-on-rewrite no
    
    # auto-aof-rewrite-percentage 100 aof 文件增长比例,指当前 aof 文件比上次重写的增长比例大小。 aof 重写即在 aof 文件在一定大小之后,重新将整个内存写道 aof 文件当中,以反应最新得状态 这样就避免了文件过大而实际内存数据小的问题。 (频繁修改问题)
    
    auto-aof-rewrite-percentage 100
    
    # auto-aof-rewrite-min-size 64mb	aof 文件重写最小得文件大小。即最开始 aof 文件必须要达到这个文件时才触发,后面的每次重写就不会根据这个变量了, 根据上一次重写完成之后的大小。 此变量仅仅只有初始化启动 redis 时有效,如果是 redis 恢复时, 则 lastSize 等于初始 aof 文件大小。
    
    auto-aof-rewrite-min-size 64mb
    
    # aof-load-truncated 指redis在恢复时,会忽略最后一条可能存在问题的指令。默认值yes。即在aof写入时,可能存在指令写错的问题(突然断电,写了一半),这种情况下,yes会log并继续,而no会直接恢复失败.
    
    aof-load-truncated yes
    
  • 不小心使用了 flushdb , flushall 。 我们可以停止 redis-server, 打开 aof 文件。 将 flushdb flushall 这种命令直接删除。重启 redis 服务

  • RDB 和 AOF 可以同时使用, 加载顺序,先加载 AOF 再加载 RDB

Redis 主从架构

  • 原来的单个Redis作为一个主 (Master),多个从 (Slave) 。读写分离架构。 主作为写库, 从作为读库,也就是说写操作操作 Mater, 大多数读操作用 Slave 。Slave 会对 Mater 做一个全量复制的数据。

    • Master 先启动,随后启动 Slave , 然后 Slave 会去 ping Master 节点,ping 通知后。 Master 会将数据提交给 Slave。Master 的数据复制是全量复制。
    • Master 会从内存中拷贝所有的 数据生成RDB文件。然后通过网络传输给我们的 Slave 节点。
    • Slave 拿到 RDB 文件后,会先下载到自己的硬盘中,然后再加载到 Slave 中。 这只是一个第一次启动时的操作
    • 后续操作 Master 会直接传输给 Slave 节点。 传输操作并不会阻塞写操作
  • 配置 一主二从机制,需要先准备三台Redis 机器 一台主,两台从

    • 主 Redis Master
    # 启动 Redis-cli
    redis-cli
    # 查看 Redis 角色信息
    info replication
    
    # Replication
    role:master			# 当前 redis 角色
    connected_slaves:0	# 当前 redis 连接数量
    master_replid:9d6bd1e0965ba650aed518034318a11c243c2d8c
    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 , Slave 第一台
    # replicaof <masterip> <masterport> 主库 ip , 主库 端口号
    replicaof 192.168.1.191 6379
    
    # masterauth <master-password> 主库 redis 密码
    masterauth 584521
    
    # replica-read-only yes  配置从主只能够读 不能写数据
    replica-read-only yes
    
    # 停止 redis 服务
    ./redis_init_script stop 
    
    # 删除 dump.rdb 和 aof 文件
    rm -rf dump.rdb *.aof
    
    # 启动 redis 服务
    ./redis_init_script start
    
    • 配置 从 Redis Slave 第二台
    # replicaof <masterip> <masterport> 主库 ip , 主库 端口号
    replicaof 192.168.1.191 6379
    
    # masterauth <master-password> 主库 redis 密码
    masterauth 584521
    
    # replica-read-only yes  配置从主只能够读 不能写数据
    replica-read-only yes
    
    # 停止 redis 服务
    ./redis_init_script stop 
    
    # 删除 dump.rdb 和 aof 文件
    rm -rf dump.rdb *.aof
    
    # 启动 redis 服务
    ./redis_init_script start
    
    • 全部启动成功之后,通过 info replication 命令查看各个 Redis 的角色状态。

    • 无磁盘化复制

      • Disk-backed : Redis 会创建一个进程。 会写入一个文件到硬盘,然后将硬盘传输到 Redis Slave 节点上。
      • Diskless: Redis 会创建一个进程,会将 RDB 文件写入到 socket 连接中,不会接触到磁盘。 可以通过 socket 传输. Redis 会在 Slave 都连接上的一段时间后, 然后将 socket 传输到 多个 Slave 节点上。
      # 当磁盘很慢,但是网络环境又很不错。 那么就可以使用无磁盘化传输 
      repl-diskless-sync no
      
      # 配置 slave 连接上多久后,才开始通过 socket 传输。
      repl-diskless-sync-delay 5
      

Redis 缓存过期处理和内存淘汰机制

  • 主动定时删除

    • 定时随机的检查过期的key,如果过期则清理删除。(每秒检查次数在redis.conf中的hz配置)
    # 每秒钟检查 10 次
    hz 10
    
  • 被动惰性删除

    • 当客户端请求一个已经过期的key的时候,那么redis会检查这个key是否过期,如果过期了,则删除,然后返回一个nil。这种策略 友好,不会有太多的损耗,但是内存占用会比较高。
  • Redis 内存满了怎么办

    • maxmemory 内存达到多少的时候。表示内存已经满了
    # maxmemory <byte> 配置redis 一共能占用多少内存 单位 byte
    maxmemory 2048 
    
    • LRU(The Least Recently Used,最近最久未使用算法)是一种常见的缓存算法,在很多分布式缓存系统(如Redis, Memcached)中都有广泛使用。

      • 如果一个数据在最近一段时间没有被访问到,那么可以认为在将来它被访问的可能性也很小。因此,当空间满时,最久没有访问的数据最先被置换(淘汰)
    • LFU(Least Frequently Used ,最近最少使用算法)也是一种常见的缓存算法。

      • 如果一个数据在最近一段时间很少被访问到,那么可以认为在将来它被访问的可能性也很小。因此,当空间满时,最小频率访问的数据最先被淘汰
    • Redis 提供了以下多种淘汰机制

      # volatile-lru -> Evict using approximated LRU among the keys with an expire set.
      # allkeys-lru -> Evict any key using approximated LRU.
      # volatile-lfu -> Evict using approximated LFU among the keys with an expire set.
      # allkeys-lfu -> Evict any key using approximated LFU.
      # volatile-random -> Remove a random key among the ones with an expire set.
      # allkeys-random -> Remove a random key, any key.
      # volatile-ttl -> Remove the key with the nearest expire time (minor TTL)
      # noeviction -> Don't evict anything, just return an error on write operations.
      

Redis 哨兵模式

原来一主二从里面, Master 节点一旦宕机。 我们就无法写入数据了。因为主节点宕机。从节点无法写入数据。只可以读取数据。

  • 配置 Redis 压缩包中的 sentinel.conf 文件
# 开启保护模式后 绑定 ip 哪个 ip 才能够连接
# bind 127.0.0.1
# yes 开启绑定模式 ,。 no 不开启
protected-mode no 
# 端口号
port 26379

# daemonize 是否开启后台
daemonize yes

# pid 文件位置。 和 redis 不是同一个进程 
pidfile /var/run/redis-sentinel.pid 

# 配置 sentinel 的日志文件
logfile /usr/local/redis/logs/sentinel/redis-sentinel.log

# dir sentinel 的工作空间
dir /usr/local/redis/sentinel

# sentinel monitor <master-group-name> <ip> <port> <quorum> 配置监听的 master 名称、 以及 ip 地址, 端口号。 
sentinel monitor xh-master 192.168.1.191 6379 2

# sentinel auth-pass mymaster MySUPER--secret-0123passw0rd
sentinel auth-pass xh-master 584521

# sentinel down-after-milliseconds <master-name> <milliseconds> master 名称。 哨兵认为master 失败的时间段
sentinel down-after-milliseconds xh-master 10000 

# sentinel parallel-syncs <master-name> <numslaves> master 名称 以及同时需要同步几个 slave 节点的数据。
sentinel parallel-syncs xh-master 1

# sentinel failover-timeout <master-name> <milliseconds> master 名称。 故障转移超时时间。 
sentinel failover-timeout xh-master 180000 

  • 下面可以直接将 sentinel 直接复制到其他两台 Redis 节点上
scp ./sentinel.conf root@192.168.1.192:/usr/local/redis/

scp ./sentinel.conf root@192.168.1.193:/usr/local/redis/
  • 启动 Redis-sentinel 哨兵
# 启动时会报一个错误 
redis-sentinel  
# 说 Sentinel 没有指定配置文件
6031:X 08 Nov 21:12:20.727 # Sentinel started without a config file. Exiting...

# 指定配置文件启动
redis-sentinel /usr/local/redis/sentinel.conf 

安装此方式启动 slave 1  和  slave 2 
  • 启动完成后, 当我们手动停止掉 redis-server 服务后。redis 哨兵,会在剩余的两个 slave 节点中。选举出一个 master 节点。

  • 当原来的master 节点重新启动之后, master 并不是master 节点了。已经转变为 slave 节点了。可以通过 info replication

4-4 解决原Master恢复后不同步问题
在本节课中,相信细心的同学会发现原来的Master(191)恢复成Slave后,他的同步状态不OK,状态为 master_link_status:down ,这是为什么呢?
这是因为我们只设置了192和193的 masterauth ,这是用于同步master的数据,但是191一开始是master是不受影响的,当master转变为slave后,由于他没有
auth ,所以他不能从新的master同步数据,随之导致 info replication 的时候,同步状态为 down ,所以只需要修改 redis.conf 中的 masterauth 为 584521
一般master数据无法同步给slave的方案检查为如下:
1. 网络通信问题,要保证互相ping通,内网互通。
2. 关闭防火墙,对应的端口开发(虚拟机中建议永久关闭防火墙,云服务器的话需要保证内网互通)。
3. 统一所有的密码,不要漏了某个节点没有设置。

# 查看xh-master下的master节点信息
sentinel master xh-master
# 查看xh-master下的slaves节点信息
sentinel slaves xh-master
# 查看xh-master下的哨兵节点信息
sentinel sentinels xh-master

Redis 使用 哨兵模式整合 SpringBoot 中

  • 配置 ymal 文件
spring:
	redis:
		database: 1
		password: 584521
		sentinel: 
			master: xh-master  	# 配置 master 的名称
			nodes: 192.168.1.191:26379,192.168.1.192:26379,192.168.1.193:26379	# 配置 redis 哨兵的 端口号以及 ip

Redis Cluster集群

  • 是单个master容量有限,数据达到一定程度会有瓶颈,这个时候可以通过水平扩展为多master 集群。
  • redis-cluster:他可以支撑多个master-slave,支持海量数据,实现高可用与高并发。 哨兵模式其实也是一种集群,他能够提高读请求的并发,但是容错方面可能会有一些问题,比如master同步数据给slave的时候,这其实是异步复制吧,这个时候 了,那么slave上的数据就没有master新,数据同步需要时间的,1-2秒的数据会丢失。master恢复并转换成slave后,新数据则丢失。
    • 每个节点知道彼此之间的关系,也会知道自己的角色,当然他们也会知道自己存在与一个集群环境中,他们彼此之间可以交互和通信, ong。那么这些关系都会保存到某个配置文件中,每个节点都有,这个我们在搭建的时候会做配置的。
    • 客户端要和集群建立连接的话,只需要和其中一个建立关系就行。
    • 某个节点挂了,也是通过超过半数的节点来进行的检测,客观下线后主从切换,和我们之前在哨兵模式中提到的是一个道理。
    • Redis中存在很多的插槽,又可以称之为槽节点,用于存储数据,这个先不管,后面再说。

搭建 Redis-cluster 集群

  • 修改 201 节点下 Redis 配置文件
# 开启 cluster 集群  yes 开启, no 关闭
cluster-enabled yes

# cluster-config-file nodes-6379.conf cluster-config-file cluster 节点配置文件
cluster-config-file nodes-6379.conf

# cluster-node-timeout 15000 配置 redis-cluster 超时时间
cluster-node-timeout 1500
# 开启 aof 持久化
appendonly yes

# 修改万配置文件后。删除 aof 和 rbd 文件 如果不删除可能就会报错
rm -rf *.aof 
rm -rf *.rdb 

# 停止 redis 
/etc/init.d/redis_init_script stop 

# 启动 redis
/etc/init.d/redis_init_script start
  • 重复操作 202, 203, 204, 205, 206
  • 通过 redis-cli 创建 cluster 集群
# 如果设置密码了记得设置密码
redis-cli -a 584521 --cluster create 192.168.1.201:6379 192.168.1.202:6379 192.168.1.203:6379 192.168.1.204:6379 192.168.1.205:6379 192.168.1.206:6379 --cluster-replicas 1 
Redis 安装配置开机启动整合SpringBoot以及配置文件详解
  • 以上就是 三主三从的关系了。 M 为 master . S 为 Slave 。 205 分配到 201 , 206 分配到 202 。 204 分配到 203
# 上面最后会询问你是否要配置该集群了 
Can I set the above configuration? (type 'yes' to accept) : yes 
  • 检查 cluster 集群信息
redis-cli -a 584521 --cluster check 192.168.1.201:6379

Redis Slots 概念

  • 一共是有 16384 个槽节点分配
[OK] All 16384 slots covered
  • 如何分配的槽节点呢
    • 将 16384 平均分配给三个Master
Redis 安装配置开机启动整合SpringBoot以及配置文件详解
  • 槽 slot 如何存储

    • redis 会对每个存储的数据的 key 进行一个 hash 然后对 16384 取模 , 计算公式 hash(key) % 16384
  • 进入到集群的控制台

# 查看集群的信息
redis-cli-c -a 584521 -h 192.168.1.202 -p6379 
# 查看节点的信息
cluster nodes

Redis SpringBoot 中整合 Cluster 集群

  • 配置 yaml 文件
spring:
	redis:
		password: 584521
		cluster: 
			nodes: 192.168.1.201:6379 192.168.1.202:6379 192.168.1.203:6379 192.168.1.204:6379 192.168.1.205:6379 192.168.1.206:6379

缓存穿透

  • 缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,比如说发起一个 id 为 ‘-1’ 的数据, 或者 id 特别大 又不存在的数据。 这时因为缓存中没有数据,就会导致每一次的请求都会落在数据库上。导致数据库压力过大。
    • 接口层增加校验,如用户鉴权校验,对请求参数做逻辑校验
    • 从缓存中取不到的数据,在数据库中也取不到的数据。 这个时候也可以写入到缓存中。k - null 的方式。 缓存有效期设置短点。 如果设置的过长,就会导致正常情况无法使用。

缓存击穿

  • 缓存击穿是指缓存中没有,但是数据库中有的数据,一般是 缓存时间到期,这个时候由于并发用户过多, 同时缓存没有读到数据,导致请求全部落在数据库中,造成数据库压力过大。
    • 设置热点数据永不过期
    • 加锁去读。对 key 加锁。 当缓存中拿不到数据的时候。放开一个线程去数据库中去读数据。

缓存雪崩

  • 缓存雪崩是指缓存中数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至down机。和缓存击穿不同的是, 缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。
    • 缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
    • 如果缓存数据库是分布式部署,将热点数据均匀分布在不同缓存数据库中。
    • 设置热点数据永远不过期。
上一篇:Redis 常见面试题


下一篇:linux cmake安装方法