redis 基础、主从复制、哨兵机制、redis集群

缓存方案对比

Ehchache

优点:

  • 基于java开发
  • 基于jvm缓存
  • 简单、轻巧、方便

缺点:

  • 不支持集群
  • 不支持分布式(适用于单体应用)

Memcache

优点:

  • 简单的key-value存储(只能存储String类型数据)
  • 内存使用率较高
  • 多核处理,多线程

缺点:

  • 无法容灾
  • 无法持久化

Redis

优点:

  • 丰富的数据结构
  • 可以持久化
  • 支持主从同步、故障转移
  • 内存数据库

缺点:

  • 单线程(数据量过大后效率低)
  • 单核

Redis安装

http://redisdoc.com/ redis命令百科地址

  • 下载安装包:https://redis.io/download/

  • 安装依赖:yum install gcc-c++

  • 编译:make

  • 安装:make install

  • 修改启动脚本:cp ./utils/redis_init_script /etc/init.d/

    .....
    #开机自启动命令
    #chkconfig: 22345 10 90
    #description: Start and Stop redis
    
    
    REDISPORT=6379
    EXEC=/usr/local/bin/redis-server
    CLIEXEC=/usr/local/bin/redis-cli
    
    PIDFILE=/var/run/redis_${REDISPORT}.pid
    #配置文件地址:
    CONF="/usr/local/redis/redis.conf"
    ...
        stop)
            if [ ! -f $PIDFILE ]
            then
                    echo "$PIDFILE does not exist, process is not running"
            else
                    PID=$(cat $PIDFILE)
                    echo "Stopping ..."
                    #如果设置了密码需要在这里添加密码,才能使用脚本进行停止
                    $CLIEXEC -a "lhy" -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"
    
  • 修改配置文件:

    mkdir /usr/local/redis -p
    cp redis.conf /usr/local/redis/
    
    #redis 后台运行
    daemonize yes
    #工作目录
    dir /usr/local/redis/db
    #绑定启动ip,允许外部机器链接
    bind 0.0.0.0
    #链接密码
    requirepass lhy
    #启动端口
    port 6379
    #默认有16个数据库。默认使用的是第0个
    databases 16
    
  • 通过启动脚本启动redis:./redis_init_script start

  • 加入开机自动启动:

    chkconfig redis_init_script on

客户端工具命令

  • 链接客户端:redis-cli
  • 密码认证:AUTH lhy
  • 查看远程服务器上redis是否存活: redis-cli -a password ping ,响应 PONG 为存货状态
  • 关闭redis:redis-cli -a password shutdown
  • 通过脚本停止:./redis_init_script stop
  • SELECT index 切换数据库
  • FLUSHDB 清空当前数据库所有数据
  • FLUSHALL 清空所有数据库的数据
  • TYPE key 查询key的数据类型

数据类型

5大数据类型:String,hash,list,set,zset

  • String

    • set key value 添加数据
    • get key 获取key的value
    • del key 删除key
    • setnx key value 如果key不存在才会设置值
    • ttl key 查询key的过期时间。值如果为 -1 永不过期
    • EXPIRE key time 给key设置过期时间
    • APPEND key value 给key的值尾部拼接value
    • incr key 值递增1
    • decr key 值递减1
    • INCRBY key value 值累加value
    • DECRBY key value 值累减value
    • GETRANGE key start end 截取值然后返回
    • SETRANGE key offset value 替换值,将offset处的字符替换成value
    • mset key value [key value …] 同时设置多个键值对
    • mget key [key …] 同时获取多个key的值
  • hash (类似map,或者类似java中的一个对象)

    • hset key field value 设置一个hash,名为key,属性为field,值为value例如: hset user name luohengyi age 10
    • hget key field 获取key的field 属性的值
    • HMGET key field [field …] 获取hash的多个属性值
    • HGETALL key 获取hash的所有属性
    • HKEYS key 获取某个hash所有的属性名称
    • HVALS key 获取某个hash所有的属性值
    • HEXISTS key field 判断hash是否拥有某个属性
    • HDEL key field 删除
    • HDEL key field [field …] 删除hash的属性
  • list

    • LPUSH key value [value …] 从左侧放入元素
    • RPUSH key value [value …] 从右侧放入元素
    • LPOP key 从左侧拿出一个元素
    • RPOP key 从右侧拿出一个元素
    • LLEN key 获取list的长度
    • LINDEX key index 查询list的某个下标的元素
    • lset key index value 替换list某个下表的值
    • LINSERT key BEFORE|AFTER pivot value 在某个值的前方/后方插入一个值
    • LREM key count value 如果有相同值,删除一个的方式,count删除第几个,value要删除的值
    • LTRIM key start stop 保留截取的元素
  • set 无需不重复数组

    • SADD key member [member …] 添加元素
    • SMEMBERS key 查询集合中的所有元素
    • SISMEMBER key member 查询元素是否存在于集合
    • SREM key member 删除某个元素
    • SPOP key 从尾部拿出一个元素
    • SRANDMEMBER key [count] 随机查询出count个元素
    • SMOVE source destination member 移动元素,将source 中的member 移动到destination 中
    • SDIFF key [key …] 获取多个集合的差集(以第一个为准)
    • SINTER key [key …] 获取多个集合的交集
    • SUNION key [key …] 获取多个集合合并后的数据
  • zset 有序不重复

    • ZADD key score member [score member …] 添加元素,一个元素包含一个分数score 和一个数据member
    • ZRANGE key 0 -1 查询集合内所有元素
    • ZRANGE key0 -1 withscores查询集合内所有元素(包含分数)
    • ZRANK key member 获取元素下标
    • ZSCORE key member 获取元素分数
    • ZCARD key 统计集合总数
    • ZCOUNT key min max 统计分数在区间内的数量
    • ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count] 获取分数区间内的元素,LIMIT 进行分页
    • ZREM key member 删除元素

线程模型

​ IO多路复用:IO多路复用其实就是我们说的selectpollepoll,它的基本原理就是selectpoll,这个function会不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程,epoll是基于事件驱动得不需要轮询。select和poll会返回所有得socket(只不过操作系统会将准备就绪的socket做上标识,用户层将不会再有无意义的系统调用开销。),只有epoll(基于事件驱动)会返回发生了事件得链接。

select方法调用模型:

epoll方法调用模型:

redis线程模型:

SpringBoot整合

Maven

<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-data-redisartifactId>
dependency>

数据源配置

spring:
  redis:
    database: 1
    host: 172.16.100.131
    port: 6379
    password: 123123

使用方式

@Autowired
// RedisTemplate 会出现乱码 使用 StringRedisTemplate
private RedisTemplate redisTemplate;

@GetMapping("/set")
    public Object setObject(
            String key,
            String value
    ) {
			 // string 类型的 操作使用 opsForValue,其他数据类型分别对应
       // opsForHash 等
        redisTemplate.opsForValue().set(key, value);
        return null;
    }

发布和订阅

  • SUBSCRIBE channel 订阅,channel 为订阅得平道
  • PUBLISH channel message 向某个频道发送消息

持久化机制

RDB

适合大量数据的恢复,但是数据的完整性和一致性可能会不足。

时间间隔执行数据集的时间点快照。配置文件中dir /usr/local/redis/working 为备份文件地址

  • 优势

    备份的临时文件可以以时间节点的方式存储,可以恢复不同时间点的数据。

    RDB非常适合灾难恢复,它是一个可以传输到远端数据中心或Amazon S3(可能是加密的)的压缩文件。

    备份使用子进程来工作的不影响工作性能。

    RDB允许在大数据集的情况下更快地重启。

    子进程备份的时候,主进程不会有任何io操作(不会有写入修改或删除),保证备份数据的的完整性。

  • 缺点

    你通常会每5分钟或更长的时间创建一个RDB快照,如果redis非正常关闭最后一次的快照将无法形成,这回导致一部分数据丢失。

    数据大时,对cpu损耗较大。

  • 配置:

    # 这个配置可以天根据自己的需求新增修改
    # 发生至少1次更改后会在 3600秒(1个小时)后快照一次
    save 3600 1 
    # 发生至少100次更改后会在 300秒(5分钟)后快照一次
    save 300 100
    # 发生至少10000次更改后会在 60秒(1分钟)后快照一次
    save 60 10000
    
    #备份文件地址
    dir /usr/local/redis/working
    #备份文件名称
    dbfilename dump.rdb
    
    #默认值为yes。当启用了RDB且最后一次后台保存数据失败,redis会停止接收set的命令。重启后可以再次接收set命令
    stop-writes-on-bgsave-error yes
    
    #默认值是yes。对于存储到磁盘中的快照,可以设置是否进行压缩存储。如果是的话,redis会采用
    #LZF算法进行压缩。如果你不想消耗CPU来进行压缩的话,可以设置为关闭此功能,但是存储在磁盘上的#快照会比较大。
    rdbcompression yes
    
    #默认值是yes。在存储快照后,我们还可以让redis使用CRC64算法来进行数据校验,但是这样做会增
    #加大约10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能
    rdbchecksum yes
    
    
    

AOF

记录服务器接收到的每个写操作,这些操作将在服务器启动时再次播放,重建原始数据集。命令记录使用与Redis协议本身相同的格式,以一种仅附加的方式。当日志变得太大时,Redis能够在后台重写日志。

  • 优点

    • 如果不小心删除了所有数据,可以将日志中的这行删除日志删除然后重启服务器,以恢复数据

    • 日志发生意外:存储空间不足时,记录失败,也可以使用工具修复

    • 日志记录共有2个方式,没次写操作都记录日志,间隔1秒编写日志

    • 日志文件过大时会进行重写

      重写aof文件并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,替换原有的文件,这一点和快照有点相似

  • 缺点

    • 日志文件相对较大
    • 如果日志模式为没次写操作都记录一次那么io开销会很大,如果日志记录模式为每秒一次那么性能不会有太大的影响
  • 配置

    #开启 AOF 模式,默认关闭
    appendonly yes
    #日志文件名称
    appendfilename "appendonly.aof"
    #模式
    appendfsync everysec
    # always 每次写操作都去记录日志,影响效率但是很安全
    # everysec 每秒写一次日志
    # no 关闭
    # -----------#
    #
    no-appendfsync-on-rewrite no
    #当发生日志重写时,刚好发生日志写入操作会引发io冲突造成io阻塞 ,使用no-appendfsync-on-#rewrite解决:
    #no 最安全的方式,不会丢失数据,但是要忍受阻塞的问题。写入日志和重写发生io冲突从而影响效率
    #yes 则在执行重写时不写入日志但是如果发生意外可能导致日志丢失
    
    # 当前的aof文件与上次的文件比较相差多少100(1倍)并且当前文件大于65mb(kb,mb,gb)时触发重写
    auto-aof-rewrite-percentage 100
    auto-aof-rewrite-min-size 65mb
    

主重架构

主从原理,slave 端启动后发送ping包到master端,master从内存中 复制出一个rdb文件返回,slave下载到磁盘中再读取到自己的内存中,在master中随后的写操作命令都会发送到slave端,以保证数据一致,在数据同步时不会影响master写和slave的读操作,他们会使用老的数据提供服务。

​ 一般使用1主2从,使用过多的slave从库会导致,内网带宽的过多使用。压力过大时可以使用树状的结构分散复制的压力

使用redis命令:info replication 查看主从信息

# Replication
role:slave
master_host:192.168.2.118
master_port:6379
#同步状态
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:291544
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:d3d36a8a51e7c51661ffbe1976460e1b94cf54d9
master_replid2:db85919371e2ac47fa63d61cb2d0a9d755782bfe
master_repl_offset:291544
second_repl_offset:1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:291544

从节点配置:配置完了最好删除当前节点的所有数据以及备份文件

#主几点ip
replicaof 192.168.2.119 6379
#主节点密码
masterauth lhy
#从节点只读
replica-read-only yes

重启后查询主从状态:

从节点可以查看主节点信息

info replication
# Replication
role:slave
master_host:192.168.2.119
master_port:6379
master_link_status:up

主节点可以查看从节点信息

# Replication
role:master
connected_slaves:2
slave0:ip=192.168.2.118,port=6379,state=online,offset=378,lag=0
slave1:ip=192.168.2.120,port=6379,state=online,offset=378,lag=0
master_replid:bf5b7119150bb2a4635d50e3947d4a8afa635ecd
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:378
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:378

Redis复制原理

  • 基于磁盘化的复制,master的数据通过rdb的方式导出到磁盘。slave请求master节点获取到rdb文件再导入到自己的内存中。
  • 无磁盘化复制,slave直接通过socket链接到master进行数据传输(master创建一个新的进程,该进程直接将rdb复制文件直接写入socket流中,从而避免磁盘的写入)。避免数据较大时,由于服务器是机器磁盘文件读写慢的问题,处于实验阶段不建议生产上使用。使用配置开启:repl-diskless-sync yes

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WVqGSN7u-1675923490158)(…/…/image\image-20230206134728317.png)]

缓存过期机制

  1. 主动,定期删除

    默认每秒10次,随机抽查key是否过期

  2. 被动,惰性删除

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

内存淘汰机制

设置redis最大可使用的内存大小,如果不设置那么redis会一直向os一直申请内存,直到内存使用完。如果内存使用完了,redis提供了一系列的处理方式默认 noeviction ,新的缓存设置不了直接返回错误

#设置redis最大可使用的内存大小。
maxmemory 
maxmemory-policy noeviction

内存淘汰机制

  • noeviction:旧缓存永不过期,新缓存设置不了,返回错误
  • allkeys-lru:清除最少用的旧缓存,然后保存新的缓存(推荐使用)
  • allkeys-random:在所有的缓存中随机删除(不推荐)
  • volatile-lru:在那些设置了expire过期时间的缓存中,清除最少用的旧缓存,然后保存新的缓存
  • volatile-random:在那些设置了expire过期时间的缓存中,随机删除缓存
  • volatile-ttl:在那些设置了expire过期时间的缓存中,删除即将过期的

哨兵机制

将redis集群监控起来,当master挂掉以后,从slave节点中选举一个master出来从而实现redis的高可用。,为了防止哨兵的错误,将哨兵部署为集群。核心配置文件。sentinel.conf.

配置

#绑定ip,指定这个ip才能访问
# bind 127.0.0.1 192.168.1.1
#接触访问控制
protected-mode no
#访问端口
port 26379
#后台启动
daemonize yes
#日志文件地址
logfile /usr/local/redis/redis-sentinel.log
#工作空间
dir /usr/local/redis/sentinel
#核心配置,master的ip以及端口
#sentinel monitor    
#配置监听的master的ip端口并取别名(有效的字符集是A-z 0-9和三个字符.-_)
#配置指示 Sentinel 去监视一个名为 mymaster 的主服务器, 这个主服务器的 IP 地址为 127.0.0.1 , 端口号为 6379 , 而将这个主#服务器判断为失效至少需要 2 个 Sentinel 同意
sentinel monitor mymaster 127.0.0.1 6379 2
# 配置redis密码,sentinel auth-pass  ,主节点密码和slaver密码应该一致
sentinel auth-pass lhy-master lhy

#当节点失效多少毫秒 sentinel 判定该节点失效
#sentinel down-after-milliseconds   
sentinel down-after-milliseconds lhy-maste 10000

#这个配置项指定了在发生failover主备切换时最多可以有多少个slave同时对新的master进行 同步,这个数字越小,完成failover所需的时
#间就越长,但是如果这个数字越大,就意味着越 多的slave因为replication而不可用。可以通过将这个值设为 1 来保证每次只有一个slave #处于不能处理命令请求的状态。
sentinel parallel-syncs lhy-maste 1

#  failover-timeout 作用
#1. 同一个sentinel对同一个master两次failover之间的间隔时间。
#2. 当一个slave从一个错误的master那里同步数据开始计算时间。直到slave被纠正为向正确的master那里同步数据时。
#3.当想要取消一个正在进行的failover所需要的时间。  
#4.当进行failover时,配置所有slaves指向新的master所需的最大时间。不过,即使过了这个超时,slaves依然会被正确配置为指向#master,但是就不按parallel-syncs所配置的规则来了。

sentinel failover-timeout lhy-master 180000

配置范例
port 26379
pidfile "/usr/local/redis/sentinel/redis-sentinel.pid"
dir "/usr/local/redis/sentinel"
daemonize yes
protected-mode no
logfile "/usr/local/redis/sentinel/redis-sentinel.log"

# 配置哨兵
sentinel monitor mymaster 127.0.0.1 6379 2
# 密码
sentinel auth-pass mymaster password
# master被sentinel认定为失效的间隔时间
sentinel down-after-milliseconds mymaster 30000
# 剩余的slaves重新和新的master做同步的并行个数
sentinel parallel-syncs mymaster 1
# 主备切换的超时时间,哨兵要去做故障转移,这个时候哨兵也是一个进程,如果他没有去执行,超过这个时间后,会由其他的哨兵来处理
sentinel failover-timeout mymaster 180000

**启动哨兵命令:**redis-sentinel ./sentinel.conf

启动后在日志中可观察到其他哨兵节点的加入:

59071:X 08 Feb 2023 00:18:57.657 * +sentinel sentinel d1afbcd1418d46fc54b69176fdf3836d563f1d8c 192.168.2.118 26379 @ mymaster 192.168.2.119 6379
59071:X 08 Feb 2023 00:20:28.005 * +sentinel sentinel 372dbcb3b3d32a3c67e0cf53f4ad7394b41718b5 192.168.2.120 26379 @ mymaster 192.168.2.119 6379

哨兵节点管理

使用命令: redis-cli -p 26379 链接到哨兵

查看redis节点信息

  • 查看imooc-master下的master节点信息

    sentinel master imooc-master

  • 查看imooc-master下的slaves节点信息

    sentinel slaves imooc-master

  • 查看imooc-master下的哨兵节点信息

    sentinel sentinels imooc-master

查看哨兵信息

  • sentinel sentinels imooc-master

master恢复后数据不同步问题

  • 由于该节点开始是master节点不需要同步数据,挂掉后重启后会变为slave节点,此时需要配置 masterauth配置访问主节点的密码

    #主节点密码
    masterauth lhy
    

一般master数据无法同步给slave的方案检查为如下:

  • 网络通信问题,要保证互相ping通,内网互通。
  • 关闭防火墙,对应的端口开放(虚拟机中建议永久关闭防火墙,云服务器的话需要保证内网互通)。
  • 统一所有的密码,通过逐台检查机器以防某个节点被遗漏。

spring集成哨兵

配置哨兵信息后,redis的master信息会通过哨兵去获取

spring:
  redis:
    database: 1
    password: imooc
    sentinel:
      master: imooc-master
      nodes: 192.168.1.191:26379,192.168.1.192:26379,192.168.1.193:26379

你可能感兴趣的:(redis,redis,数据库,缓存)