代码改变世界

redis入门笔记

2022-03-13 20:09  wang03  阅读(150)  评论(0编辑  收藏  举报

尚硅谷redis笔记

技术的分类:

  1. 解决功能性的问题:Java,Jsp,RDBMS,Tomcat,HTML,Linux,JDBC,SVN
  2. 解决扩展性的问题:Struts,Spring,SpringMVC,Hibernate,Mybatis
  3. 解决性能的问题:NoSQL,Java线程,Hadoop,Nginx,MQ,ElasticSearch

redis安装
  1. 下载redis安装包,解压后,进入目录,依次执行makemake install就可以进行安装。

  2. 默认安装后文件位置/usr/local/bin/

redis-benchmark:性能测试工具,可以在自己本子运行,看看自己本子性能如何

redis-check-aof:修复有问题的AOF文件,rdb和aof后面讲

redis-check-rdb:修复有问题的dump.rdb文件

redis-sentinel:Redis集群使用

redis-server:Redis服务器启动命令

redis-cli:客户端,操作入口


redis启动
  • 前台启动,直接执行redis-server

  • 后台启动

    1. 使用redis安装包中的redis.conf修改参数:

      daemonize yes  #设置后台启动
      

​ 2. 使用 redis-server redis.conf的路径启动

​ 如 redis-server /root/redis.conf


redis中key的操作

keys *查看当前库所有key (匹配:keys *1)

exists key判断某个key是否存在

type key 查看你的key是什么类型

del key 删除指定的key数据

unlink key 根据value选择非阻塞删除(仅将keys从keyspace元数据中删除,真正的删除会在后续异步操作。)

expire key 10 10秒钟:为给定的key设置过期时间

ttl key 查看还有多少秒过期,-1表示永不过期,-2表示已过期

select命令切换数据库

dbsize查看当前数据库的key的数量

flushdb清空当前库

flushall通杀全部库


redis数据类型

redis 命令手册

1. Redis 字符串(String)

String类型是二进制安全的,可以包含任何数据。比如jpg图片或者序列化的对象。

String类型是Redis最基本的数据类型,一个Redis中字符串value最多可以是512M。

String的数据结构为简单动态字符串(Simple Dynamic String,缩写SDS)。是可以修改的字符串。当字符串长度小于1M时,扩容都是加倍现有的空间,如果超过1M,扩容时一次只会多扩1M的空间。需要注意的是字符串最大长度为512M。

  • set为字符串键设置值

    NX选项,那么SET命令只会在键没有值的情况下执行设置操作

    XX选项只会在键已经有值的情况下执行设置操作

  • get 获取字符串键的值

  • getset 获取旧值并设置新值

  • del 删除字符串键

  • mset 一次为多个字符串键设置值

  • mget 一次获取多个字符串键的值

  • msetnx 只在键不存在的情况下,一次为多个字符串键设置值

  • strlen 获取字符串值的字节长度

  • getrange 获取字符串值指定索引范围上的内容

  • setrange 对字符串值的指定索引范围进行设置

  • append 追加新内容到值的末尾

  • incrby,decrby 对整数值执行加法操作和减法操作

  • incr,decr 对整数值执行加1操作和减1操作

  • incrbyfloat 对数字值执行浮点数加法操作

2. Redis列表(List)

单键多值、简单的字符串列表,按照插入顺序排序。可以添加一个元素到列表的头部(左边)或者尾部(右边)。

它的底层实际是个双向链表,对两端的操作性能很高,通过索引下标的操作中间的节点性能会较差。

List的数据结构为快速链表quickList。

首先在列表元素较少的情况下会使用一块连续的内存存储,这个结构是ziplist,也即是压缩列表。

它将所有的元素紧挨着一起存储,分配的是一块连续的内存。

当数据量比较多的时候才会改成quicklist。

因为普通的链表需要的附加指针空间太大,会比较浪费空间。比如这个列表里存的只是int类型的数据,结构上还需要两个额外的指针prev和next。

Redis将链表和ziplist结合起来组成了quicklist。也就是将多个ziplist使用双向指针串起来使用。这样既满足了快速的插入删除性能,又不会出现太大的空间冗余。

  • lpush 将元素推入列表左端

  • rpush 将元素推入列表右端

  • lpushxrpushx 只对已存在的列表执行推入操作.(如果给定列表并不存在,那么LPUSHX命令和RPUSHX命令将放弃执行推入操作)

  • lpoprpop 弹出列表最左端的元素,弹出列表最右端的元素

  • rpoplpush 将右端弹出的元素推入左端

  • llen 获取列表的长度

  • lindex 获取指定索引上的元素

  • lrange 获取指定索引范围上的元素

  • lset 为指定索引设置新元素

  • linsert 将元素插入列表

  • ltrim 修剪列表

  • lrem 从列表中移除指定元素

    命令格式:lrem list count element

    • 如果count参数的值等于0,那么LREM命令将移除列表中包含的所有指定元素。
    • 如果count参数的值大于0,那么LREM命令将从列表的左端开始向右进行检查,并移除最先发现的count个指定元素。
    • 如果count参数的值小于0,那么LREM命令将从列表的右端开始向左进行检查,并移除最先发现的abs(count)个指定元素(abs(count)即count的绝对值)。
  • blpopbrpop 阻塞式左端弹出操作,阻塞式右端弹出操作

  • brpoplpush 阻塞式弹出并推入操作

3.Redis集合(Set)

Redis set对外提供的功能与list类似是一个列表的功能,特殊之处是set可以自动去重,提供了判断某个成员是否在一个set集合内的重要接口。

Redis的Set是string类型的无序集合。它底层其实是一个value为null的hash表,所以添加,删除,查找的复杂度都是O(1)

Set数据结构是dict字典,字典是用哈希表实现的。

Redis的set结构类似Java的HashSet,它的内部也使用hash结构,所有的value都指向同一个内部值。

  • sadd 将元素添加到集合

  • srem 从集合中移除元素

  • smove 将元素从一个集合移动到另一个集合

  • smembers 获取集合包含的所有元素

  • scard 获取集合包含的元素数量

  • sismember 检查给定元素是否存在于集合

  • srandmember 随机获取集合中的元素

  • spop 随机地从集合中移除指定数量的元素

  • sintersinterstore 对集合执行交集计算

  • sunionsunionstroe 对集合执行并集计算

  • sdiffsdiffstore 对集合执行差集计算

4.Redis哈希(Hash)

Redis hash 是一个键值对集合,是一个string类型的field和value的映射表

Hash类型对应的数据结构是两种:ziplist(压缩列表),hashtable(哈希表)。当field-value长度较短且个数较少时,使用ziplist,否则使用hashtable。

  • hset 为字段设置值,也可以为多个字段设置值

  • hsetnx 只在字段不存在的情况下为它设置值

  • hget 获取字段的值

  • hincrby 对字段存储的整数值执行加法或减法操作

  • hincrbyfloat 对字段存储的数字值执行浮点数加法或减法操作

  • hstrlen 获取字段值的字节长度

  • hexists 检查字段是否存在

  • hdel 删除字段

  • hlen 获取散列包含的字段数量

  • hmset 一次为多个字段设置值 (Redis 4.0.0 HMSET被视为已弃用,推荐使用HSET)。

  • hmget 一次获取多个字段的值

  • hkeyshvalshgetall 获取所有字段、所有值、所有字段和值

5.Redis有序集合Zset(sorted set)

Redis有序集合zset与普通集合set非常相似,是一个没有重复元素的字符串集合。

不同之处是有序集合的每个成员都关联了一个评分(score),这个评分(score)被用来按照从最低分到最高分的方式排序集合中的成员。集合的成员是唯一的,但是评分可以是重复了 。

zset底层使用了两个数据结构

(1)hash,hash的作用就是关联元素value和权重score,保障元素value的唯一性,可以通过元素value找到相应的score值。

(2)跳跃表,跳跃表的目的在于给元素value排序,根据score的范围获取元素列表。

  • zadd 添加或更新成员

  • zrem 移除指定的成员

  • zscore 获取成员的分值

  • zincrby 对成员的分值执行自增或自减操作

  • zcard 获取有序集合的大小

  • zrankzrevrank 获取成员在有序集合中的排名

  • zrangezrevrange 获取指定索引范围内的成员

  • zrangebyscorezrevrangebyscore 获取指定分值范围内的成员

  • zcount 统计指定分值范围内的成员数量

  • zremrangebyrank 移除指定排名范围内的成员

  • zremrangebyscore 移除指定分值范围内的成员

  • zunionstorezinterstore 有序集合的并集运算和交集运算

  • zrangebylexzrerangebylex 返回指定字典序范围内的成员

    命令格式:zrangebylex sort_set min max

    命令的min参数和max参数用于指定用户想要获取的字典序范围,它们的值可以是以下4种值之一:

    • 带有[符号的值表示在结果中包含与给定值具有同等字典序大小的成员。
    • 带有(符号的值表示在结果中不包含与给定值具有同等字典序大小的成员。
    • 加号+表示无穷大。
    • 减号-表示无穷小。
  • zlexcout 统计位于字典序指定范围内的成员数量

  • zremrangebylex 移除位于字典序指定范围内的成员

  • bzpopmaxbzpopmin 弹出分值最高和最低的成员

  • bzpopmaxbzpopmin 阻塞式最大/最小元素弹出操作


6.Bitmaps

Redis提供了Bitmaps这个“数据类型”可以实现对位的操作:

(1)Bitmaps本身不是一种数据类型, 实际上它就是字符串(key-value) , 但是它可以对字符串的位进行操作。

(2)Bitmaps单独提供了一套命令, 所以在Redis中使用Bitmaps和使用字符串的方法不太相同。 可以把Bitmaps想象成一个以位为单位的数组, 数组的每个单元只能存储0和1, 数组的下标在Bitmaps中叫做偏移量

  • setbit 设置二进制位的值

  • getbit 获取二进制位的值

  • bitcount 统计被设置的二进制位数量(可以指定字节范围)

  • bitpos 查找第一个指定的二进制位值

  • bitop 执行二进制位运算

    当BITOP命令在对两个长度不同的位图执行运算时,会将长度较短的那个位图中不存在的二进制位的值看作0。

  • bitfield

    • 命令格式:bitfield bitmap set type offset value 根据偏移量对区域进行设置

      • offset参数用于指定设置的起始偏移量。这个偏移量从0开始计算,偏移量为0表示设置从位图的第1个二进制位开始,偏移量为1则表示设置从位图的第2个二进制位开始,以此类推。如果被设置的值长度不止一位,那么设置将自动延伸至之后的二进制位。
      • type参数用于指定被设置值的类型,这个参数的值需要以i或者u为前缀,后跟被设置值的位长度,其中i表示被设置的值为有符号整数,而u则表示被设置的值为无符号整数。比如i8表示被设置的值为有符号8位整数,而u16则表示被设置的值为无符号16位整数,诸如此类。BITFIELD的各个子命令目前最大能够对64位长的有符号整数(i64)和63位长的无符号整数(u63)进行操作。
      • value参数用于指定被设置的整数值,这个值的类型应该和type参数指定的类型一致。如果给定值的长度超过了type参数指定的类型,那么SET命令将根据type参数指定的类型截断给定值。比如,如果用户尝试将整数123(二进制表示为01111011)存储到一个u4类型的区域中,那么命令会先将该值截断为4位长的二进制数字1011(即十进制数字11),然后再进行设置。
    • 命令格式:bitfield bitmap set type #index value 根据给定类型的位长度,对位图在指定索引上存储的整数值进行设置

      bitfield bitmap set u8 #132 22 对位图的第133个8位无符号整数进行设置(索引是从0开始计算的)。

    • 命令格式:bitfield bitmap get type offsetbitfield bitmap get type #index 获取区域存储的值

    • 命令格式:bitfield bitmap incrby type offset incrementbitfield bitmap incrby type #index increment 执行加法操作或减法操作

    • 命令格式:bitfield bitmap [...] overflow wrap|sat|fail [...] 处理溢出

      • WRAP表示使用回绕(wrap around)方式处理溢出,这也是C语言默认的溢出处理方式。在这一模式下,向上溢出的整数值将从类型的最小值开始重新计算,而向下溢出的整数值则会从类型的最大值开始重新计算。
      • SAT表示使用饱和运算(saturation arithmetic)方式处理溢出,在这一模式下,向上溢出的整数值将被设置为类型的最大值,而向下溢出的整数值则会被设置为类型的最小值。
      • FAIL表示让INCRBY子命令在检测到计算会引发溢出时拒绝执行计算,并返回空值表示计算失败。

7.HyperLogLog

Redis HyperLogLog 是用来做基数统计的算法,算法的标准误差仅为0.81%。

HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的。

在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。
但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。

  • pfadd 对集合元素进行计数
  • pfcount 返回集合的近似基数
  • pfmerge 计算多个HyperLogLog的并集

PFCOUNT命令在计算多个HyperLogLog的近似基数时会执行以下操作:

1)在内部调用PFMERGE命令,计算所有给定HyperLogLog的并集,并将这个并集存储到一个临时的HyperLogLog中。

2)对临时HyperLogLog执行PFCOUNT命令,得到它的近似基数(因为这是针对单个HyperLogLog的PFCOUNT,所以这个操作不会引起循环调用)。3)删除临时HyperLogLog。

4)向用户返回之前得到的近似基数

8.Geospatial

Redis 3.2 中增加了对GEO类型的支持。GEO,Geographic,地理信息的缩写。该类型,就是元素的2维坐标,在地图上就是经纬度。redis基于该类型,提供了经纬度设置,查询,范围查询,距离查询,经纬度Hash等常见操作。

  • geoadd 存储坐标
  • geopos 获取指定位置的坐标
  • geodist 计算两个位置之间的直线距离
  • georadius 查找指定坐标半径范围内的其他位置
  • georadiusbymember 查找指定位置半径范围内的其他位置
  • geohash 获取指定位置的Geohash值
9.流

流(stream)是Redis 5.0版本中新增加的数据结构。

流是一个包含零个或任意多个流元素的有序队列,队列中的每个元素都包含一个ID和任意多个键值对,这些元素会根据ID的大小在流中有序地进行排列。

  • xadd 追加新元素到流的末尾

    流元素的ID由ID和顺序编号(sequcen number)两部分组成。如果输入只包含ID,不包含序号,redis会自动将序号部分设置成0.

    同一个流中的不同元素是不允许使用相同ID的,且要求新元素的ID必须比流中所有已有元素的ID都要大。

    流元素ID可以输入特殊值*,Redis将自动为新添加的元素生成一个可用的新ID(毫秒时间(millisecond)和顺序编号(sequcen number)两部分组成)。

  • xtrim 对流进行修剪

  • xdel 移除指定元素

  • xlen 获取流包含的元素数量

  • xrangexrevrange 访问流中元素

  • xread 以阻塞或非阻塞方式获取流元素

  • xgroup 管理消费者组

  • xreadgroup 读取消费者组中的消息

  • xpending 显示待处理消息的相关信息

  • xack 将消息标记为“已处理”

  • xclaim 转移消息的归属权

  • xinfo 查看流和消费者组的相关信息


Redis的发布和订阅

1、客户端可以订阅频道如下图

2、当给这个频道发布消息后,消息就会发送给订阅的客户端


登录redis客户端,使用subscribe 频道来订阅频道;使用 publish 频道 "字符串"将字符串发布到指定频道。


Redis的事务定义

Redis事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。

Redis事务的主要作用就是串联多个命令防止别的命令插队。

1.Multi、Exec、discard

从输入Multi命令开始,输入的命令都会依次进入命令队列中,但不会执行,直到输入Exec后,Redis会将之前的命令队列中的命令依次执行。

组队的过程中可以通过discard来放弃组队。

2.事务的错误处理

组队中某个命令出现了报告错误,执行时整个的所有队列都会被取消。

如果执行阶段某个命令报出了错误,则只有报错的命令不会被执行,而其他的命令都会执行,不会回滚。


乐观锁适用于多读的应用类型,这样可以提高吞吐量。Redis就是利用这种check-and-set机制实现事务的。

3.watch key [key ...]

在执行multi之前,先执行watch key1 [key2],可以监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。

执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。

4.unwatch

取消 WATCH 命令对所有 key 的监视。

如果在执行 WATCH 命令之后,EXEC 命令或DISCARD 命令先被执行了的话,那么就不需要再执行UNWATCH 了。


Redis持久化之RDB.

Redis 提供了2个不同形式的持久化方式。

  • RDB(Redis DataBase)
  • AOF(Append Of File)

官方文档关于持久化章节


Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到 一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。 整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能 如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失


1. RDB持久化流程

2.命令save VS bgsave
  • save :save时只管保存,其它不管,全部阻塞。手动保存。不建议。
  • bgsave:Redis会在后台异步进行快照操作, 快照同时还可以响应客户端请求。
  • 可以通过lastsave 命令获取最后一次成功执行快照的时间
3.优势
  • 适合大规模的数据恢复

  • 对数据完整性和一致性要求不高更适合使用

  • 节省磁盘空间

  • 恢复速度快

4.劣势
  • Fork的时候,内存中的数据被克隆了一份,大致2倍的膨胀性需要考虑

  • 虽然Redis在fork时使用了写时拷贝技术,但是如果数据庞大时还是比较消耗性能。

  • 在备份周期在一定间隔时间做一次备份,所以如果Redis意外down掉的话,就会丢失最后一次快照后的所有修改。

5.总结


Redis持久化之AOF

AOF(Append Only File)以日志的形式来记录每个写操作(增量保存),将Redis执行过的所有写指令记录下来(读操作不记录), 只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis 重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作

1.AOF持久化流程

(1)客户端的请求写命令会被append追加到AOF缓冲区内;

(2)AOF缓冲区根据AOF持久化策略[always,everysec,no]将操作sync同步到磁盘的AOF文件中;

(3)AOF文件大小超过重写策略或手动重写时,会对AOF文件rewrite重写,压缩AOF文件容量;

(4)Redis服务重启时,会重新load加载AOF文件中的写操作达到数据恢复的目的;

2.配置

AOF默认不开启,可以在redis.conf中配置文件名称,默认为 appendonly.aof。AOF文件的保存路径,同RDB的路径一致

AOF和RDB同时开启,系统默认取AOF的数据(数据不会存在丢失)

3.AOF启动/修复/恢复

AOF的备份机制和性能虽然和RDB不同, 但是备份和恢复的操作同RDB一样,都是拷贝备份文件,需要恢复时再拷贝到Redis工作目录下,启动系统即加载。

  • 正常恢复
    修改默认的appendonly no,改为yes
    将有数据的aof文件复制一份保存到对应目录(查看目录:config get dir)
    恢复:重启redis然后重新加载

  • 异常恢复
    修改默认的appendonly no,改为yes
    如遇到AOF文件损坏,通过/usr/local/bin/redis-check-aof--fix appendonly.aof进行恢复
    备份被写坏的AOF文件
    恢复:重启redis,然后重新加载

  1. AOF同步频率设置

    appendfsync always
    始终同步,每次Redis的写入都会立刻记入日志;性能较差但数据完整性比较好
    appendfsync everysec
    每秒同步,每秒记入日志一次,如果宕机,本秒的数据可能丢失。
    appendfsync no
    redis不主动进行同步,把同步时机交给操作系统。

4.Rewrite压缩
(1)是什么:

AOF采用文件追加方式,文件会越来越大为避免出现此种情况,新增了重写机制, 当AOF文件的大小超过所设定的阈值时,Redis就会启动AOF文件的内容压缩, 只保留可以恢复数据的最小指令集.可以使用命令bgrewriteaof。

(2)重写原理,如何实现重写

AOF文件持续增长而过大时,会fork出一条新进程来将文件重写(也是先写临时文件最后再rename),redis4.0版本后的重写,是指上就是把rdb 的快照,以二级制

的形式附在新的aof头部,作为已有的历史数据,替换掉原来的流水账操作。

no-appendfsync-on-rewrite:

​ 如果 no-appendfsync-on-rewrite=yes ,不写入aof文件只写入缓存,用户请求不会阻塞,但是在这段时间如果宕机会丢失这段时间的缓存数据。(降低数据安全性,提高性能)
​ 如果 no-appendfsync-on-rewrite=no, 还是会把数据往磁盘里刷,但是遇到重写操作,可能会发生阻塞。(数据安全,但是性能降低)

触发机制,何时重写:

Redis会记录上次重写时的AOF大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发。

重写虽然可以节约大量磁盘空间,减少恢复时间。但是每次重写还是有一定的负担的,因此设定Redis要满足一定条件才会进行重写。

auto-aof-rewrite-percentage:设置重写的基准值,文件达到100%时开始重写(文件是原来重写后文件的2倍时触发)

auto-aof-rewrite-min-size:设置重写的基准值,最小文件64MB。达到这个值开始重写。

例如:文件达到70MB开始重写,降到50MB,下次什么时候开始重写?100MB

系统载入时或者上次重写完毕时,Redis会记录此时AOF大小,设为base_size,

如果Redis的AOF当前大小>= base_size +base_size*100% (默认)且当前大小>=64mb(默认)的情况下,Redis会对AOF进行重写。

(3)重写流程

(1)bgrewriteaof触发重写,判断是否当前有bgsave或bgrewriteaof在运行,如果有,则等待该命令结束后再继续执行。

(2)主进程fork出子进程执行重写操作,保证主进程不会阻塞。

(3)子进程遍历redis内存中数据到临时文件,客户端的写请求同时写入aof_buf缓冲区和aof_rewrite_buf重写缓冲区保证原AOF文件完整以及新AOF文件生成期间的新的数据修改动作不会丢失。

(4)

​ 1).子进程写完新的AOF文件后,向主进程发信号,父进程更新统计信息。

​ 2).主进程把aof_rewrite_buf中的数据写入到新的AOF文件。

(5)使用新的AOF文件覆盖旧的AOF文件,完成AOF重写。

5.优势

  • 备份机制更稳健,丢失数据概率更低。

  • 可读的日志文本,通过操作AOF稳健,可以处理误操作。

6.劣势

比起RDB占用更多的磁盘空间。

恢复备份速度要慢。

每次读写都同步的话,有一定的性能压力。

存在个别Bug,造成恢复不能。

7.总结

RDB和AOF用哪个好

官方推荐两个都启用。

如果对数据不敏感,可以选单独用RDB。

不建议单独用 AOF,因为可能会出现Bug。

如果只是做纯内存缓存,可以都不用。

官网建议:

RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储

AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redis协议追加保存每次写的操作到文件末尾.

Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大

只做缓存:如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式.

同时开启两种持久化方式

在这种情况下,当redis重启的时候会优先载入AOF文件来恢复原始的数据, 因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整.

RDB的数据不实时,同时使用两者时服务器重启也只会找AOF文件。那要不要只使用AOF呢?

建议不要,因为RDB更适合用于备份数据库(AOF在不断变化不好备份), 快速重启,而且不会有AOF可能潜在的bug,留着作为一个万一的手段。

性能建议

因为RDB文件只用作后备用途,建议只在Slave上持久化RDB文件,而且只要15分钟备份一次就够了,只保留save 900 1这条规则。

如果使用AOF,好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只load自己的AOF文件就可以了。

代价,一是带来了持续的IO,二是AOF rewrite的最后将rewrite过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。

只要硬盘许可,应该尽量减少AOF rewrite的频率,AOF重写的基础大小默认值64M太小了,可以设到5G以上。

默认超过原大小100%大小时重写可以改到适当的数值。


Redis_主从复制

主机数据更新后根据配置和策略, 自动同步到备机的master/slaver机制,Master以写为主,Slave以读为主

1.作用
  • 读写分离,性能扩展

  • 容灾快速恢复

2.搭建
  • 复制多个redis.conf配置文件,分别修改其中如下参数:

    # xxx 表示每一个redis实例的配置都不相同
    port xxx   
    protected-mode no
    daemonize yes
    pidfile /var/run/redis_xxx.pid
    dbfilename dumpxxx.rdb
    
  • 分别启动每个redis实例

为了操作简单,我本地使用单台服务器,通过不同端口号启动3个redis进程

  • 使用info replication查看redis状态

    这时每个redis进程都是主节点,3个redis没有任何关系

  • 使用slaveof redis主节点IP redis主节点端口号将当前redis作为对应redis的从节点

  • 使用info replication再查看redis状态,确认集群建立成功

3.特点

这种主从复制集群不能自动进行主从切换(主节点挂掉后,从节点不能变成主节点)。

从节点只能读,不能写。

  • 上一个Slave可以是下一个slave的Master,Slave同样可以接收其他 slaves的连接和同步请求,那么该slave作为了链条中下一个的master, 可以有效减轻master的写压力,去中心化降低风险。

    中途变更转向:会清除之前的数据,重新建立拷贝最新的

    风险是一旦某个slave宕机,后面的slave都没法备份

    主机挂了,从机还是从机,无法写数据了

    当一个master宕机后,后面的slave可以立刻升为master,其后面的slave不用做任何修改。

    slaveof no one 将从机变为主机

4.复制原理
  1. Slave启动成功连接到master后会发送一个sync命令
  1. Master接到命令启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令, 在后台进程执行完毕之后,master将传送整个数据文件到slave,以完成一次完全同步

  2. 全量复制:而slave服务在接收到数据库文件数据后,将其存盘并加载到内存中。

  3. 增量复制:Master继续将新的所有收集到的修改命令依次传给slave,完成同步

  4. 但是只要是重新连接master,一次完全同步(全量复制)将被自动执行


哨兵模式(sentinel)

还有哨兵集群模式,解决单个哨兵挂掉的问题。

能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库。

1.搭建

1). 参考主从复制章节搭建redis主从复制集群。

2). 新建sentinel.conf文件,名字绝不能错。

​ 文件内容如下(其中mymaster为监控对象起的服务器名称, 1 为至少有多少个哨兵同意迁移的数量。 )

sentinel monitor mymaster 127.0.0.1 6379 1

3). 执行redis-sentinel sentinel.conf路径

2.复制延时

由于所有的写操作都是先在Master上操作,然后同步更新到Slave上,所以从Master同步到Slave机器有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,Slave机器数量的增加也会使这个问题更加严重。


Redis集群

1.搭建

如果redis之前已经有数据,需要删除原来的rdb文件

  • 修改每个redis.conf关于集群配置的参数
# xxx 表示每一个redis实例的配置都不相同
port xxx   
protected-mode no
daemonize yes
pidfile /var/run/redis_xxx.pid
dbfilename dumpxxx.rdb
cluster-enabled yes    #打开集群模式
cluster-config-file nodes-xxx.conf  #设定节点配置文件名
cluster-node-timeout 15000   #设定节点失联时间,超过该时间(毫秒),集群自动进行主从切换。

  • 启动各个redis

  • 组合成集群

    redis-cli --cluster create --cluster-replicas 1  127.0.0.1:6380 127.0.0.1:6381 127.0.0.1:6382 127.0.0.1:6383 127.0.0.1:6384 127.0.0.1:6385
    # --cluster-replicas 1  表示1个主对应1个从
    

2.操作

在redis-cli每次录入、查询键值,redis都会计算出该key应该送往的插槽,如果不是该客户端对应服务器的插槽,redis会报错,并告知应前往的redis实例地址和端口。

redis-cli客户端提供了 –c 参数实现自动重定向。

如 redis-cli -c –p 6379 登入后,再录入、查询键值对可以自动重定向。

不在一个slot下的键值,是不能使用mget,mset等多键操作。

可以通过{}来定义组的概念,从而使key中{}内相同内容的键值对放到一个slot中去。

查询集群中的值:

CLUSTER GETKEYSINSLOT 返回 count 个 slot 槽中的键。

3.集群扩容
  1. 新创建一个redis服务

    • 按照第1步搭建中的方法新创建一个redis.conf的配置文件。

      我这里将这个文件命名为redis7.conf

    • 启动redis服务。

      对应我这里就是redis-server redis7.conf;我们这里新建的节点是127.0.0.1:6386

  2. 将新建的节点加入到原来的集群中

    #redis-cli --cluster add-node 新创建的redis服务ip:port  原redis集群中服务中任意一个ip:port
    redis-cli --cluster add-node 127.0.0.1:6386 127.0.0.1:6380
    

.png)

  1. 重新分派槽号

    • 新加入集群的节点默认是没有分配槽号的,也就是不会存放数据。

      可以使用redis-cli --cluster check 集群中服务任意一个ip:port查看

    • 分配槽号

      使用redis-cli --cluster reshard 集群中服务任意一个ip:port命令重新分配槽号

    • 查看结果

  2. 从新加入的主节点添加从节点

    • 继续按照第1步搭建中的方法新创建一个redis.conf的配置文件。

      我这里将这个文件命名为redis8.conf

    • 启动redis服务,将这个服务作为我们的要加入的从节点。

      对应我这里就是redis-server redis8.conf; 节点是127.0.0.1:6387

    • 执行命令添加从节点

      #redis-cli --cluster add-node 上一步新建的要作为从节点的ip:port     集群中任意一个节点ip:port   --cluster-slave --cluster-master-id 新主机节点ID
      
      #在我这里:
      
      #上一步新建的要作为从节点的ip:port  我这里新建的节点的ip:port   127.0.0.1:6387
      
      #集群中任意一个节点ip:port    我这里输入的是127.0.0.1:6386
      #新主机节点ID   就是127.0.0.1:6386的ID  这里551981f8a318875d5b4c0a024857b1e532a1e29e
      

    • 进行确认

4.集群缩容

这里我们删除在上面添加的集群中的127.0.0.1:6386(主节点),127.0.0.1:6387(从节点)这两个节点

#redis-cli --cluster del-node 集群中任一节点ip:port  要删除的节点id

由于主节点上分配了槽,所以这里不能直接删除主节点,

但是可以直接删除从节点。

现在来移除主节点:

1.首先执行reshard,将当前要移除的节点的槽迁移到其他主节点上去。

后面会有一步确认,直接输入yes就会进行迁移操作了。

2.下面我们确认下当前要删除的节点已经没有分配到槽,然后删除主节点就OK了。