Redis相关东西

目录

  • Redis是什么
  • 五种数据类型
  • Redis为何这么快
  • Redis和Memcached的区别
  • 淘汰策略
  • 持久化
  • 主从复制
  • 哨兵

Redis是什么

​ Redis是由C语言编写的一个开源的高性能键值对的内存数据库,是一款NoSQL(not-only sql | no sql)数据库,可以用作缓存、数据库、消息中间件。

​ Redis作为一款内存数据库,其优势为:

	1. 性能优秀,数据都存于内存中,读写速度快,理论读取速度能达到10W/秒;
	2. 单线程操作,线程安全,采用IO多路复用实现垃圾回收和持久化;
	3. 支持丰富的数据类型:字符串(string)、列表(list)、散列(hash)、集合(set)、有序集合(zset);
	4. 支持数据持久化,并且提供RDB和AOF两种持久化方式;
	5. 可以用于分布式锁,也可以利用Redis的发布-订阅特性实现消息队列;
	6. 主从复制,哨兵,高可用。

五种数据类型

  • 字符串(string)类型:Redis的字符串类型是最基本的类型,可以理解为一个key对应一个value,value可以是字符也可以是数字,该类型可以存储图片或者序列化后的对象等二进制数据,支持的value大小最大512M,当value小于44字节(3.2版本+是44,3.0版本-是39)时,字符串编码为embstr,大于的时候字符串编码为raw,常用的命令有set、get等。
  • 散列(hash)类型:hash是一个键值对的集合,特别适合用于存储对象,可以直接获取到对象的某个属性的值,常用的命令有hset、hget、hgetall等。
  • 列表(list)类型:
  • 集合(set)类型:
  • 有序集合(zset)类型:

Redis为何那么快

​ Redis之所以是单线程的还那么快,完全是因为Redis是纯内存操作,没有CPU上下文切换带来的消耗,也没有磁盘寻址等带来的IO开销,官方理论QPS为10W+。

​ 既然Redis的性能瓶颈是内存和网络带宽,那么就没必要设计成多线程模式,否则会多出CPU切换,且只要涉及到多线程必然会因为资源竞争而衍生出资源锁的使用,频繁的加锁、释放锁还是非常浪费时间的,所以既然多线程会带来那么多问题,还是使用单线程得了,并且Redis本身就是K-V存储,查询时间复杂度限制在O(1)的情况,所以Redis才那么快。

Redis和Memcached的区别

  • 存储方式:Memcache将数据存储在内存中,若服务器出现故障,则数据全部丢失,无法持久化。Redis提供了RDB和AOF两种方式进行数据持久化,就算是服务器宕机,在恢复之后依然可以保证数据的完整性;
  • 数据类型:Memcache仅支持字符串存储,而Redis支持字符串、列表、散列、集合、有序集合等类型,使用起来更方便和多样化;
  • value大小:Redis的字符串类型可以存储512M的内容,而Memcache最高仅能存储1M的内容,不过虽然Redis支持很大的value,但是一般不会那么用;
  • 底层协议不同:Redis拥有自己的VM,Memcache使用系统函数

淘汰策略

Redis目前有6种淘汰策略,据说新版本中有8种

  • volatile-lru:从设置了过期时间的所有key中将最近最少使用(least recently used)的key淘汰掉
  • volatile-ttl:从设置了过期时间的所有key中将剩余存活时间最少(time to live)的key淘汰掉
  • volatile-random:从设置了过期时间的所有key中随机淘汰掉部分key
  • allkeys-lru:从所有的key中将最近最少使用的key淘汰掉
  • allkeys-random:从所有的key中随机淘汰掉部分key
  • noeviction:不执行数据淘汰,当内存不足时直接拒绝新的插入请求,并返回错误信息
  • volatile-lfu:从设置了过期时间的所有key中将访问频率最少(least frequently used)的key淘汰掉
  • allkeys-lfu:从所有的key中将访问频率最少的key淘汰掉

持久化

Redis支持两种持久化方式,持久化的目的是将内存中的数据写入到磁盘中,防止服务出现故障后的数据丢失的情况。

  • RDB方式:RDB是Redis的默认持久化方式,属于是定时保存,每隔一段时间将fork出一个子进程去将内存中的数据写入到一个临时dump.rdb(名字在配置文件中设置)文件中,待子进程执行完成之后,将这个临时的dump文件替换掉原来的dump文件,这样做的目的是可以实现copy-on-write,子进程运行过程中使用的内存资源与Redis主进程无关

    *通过bgsave和save命令可以手动触发执行RDB

    image-20200327015702174

    配置信息:redis.conf文件中

    解读:

    save 900 1:900秒内若至少有1个key发生变化,则触发备份

    save 300 10:300秒内若至少有10个key发生变化,则触发备份

    save 60 10000:60秒内若至少有1万个key发生变化,则触发备份

    image-20200327001846508

    劣势:

    1. RDB持久化方式适合于整库备份,dump文件用于故障恢复,但是由于RDB方式并不是实时的整库备份,所以我们拿到的dump文件总是会和内存中的数据不一致,如果你想要避免服务器发生故障的时候丢失数据,那么仅仅使用RDB是万万不行的,需要配合AOF使用。
    2. 为了使用子进程在磁盘上持久存储,RDB经常需要fork()。如果数据集很大,Fork()可能很耗时,并且可能导致Redis停止为客户端提供服务几毫秒甚至一秒钟(如果数据集很大,而且CPU性能不是很好)。AOF还需要fork(),但是您可以调整重写日志的频率,而不需要牺牲持久性。

    优势:

    1. RDB是一个非常紧凑的单文件时间点表示您的Redis数据。RDB文件非常适合备份。例如,您可能希望在最近的24小时内每小时存档一次RDB文件,并在30天内每天保存一次RDB快照。这允许您在发生灾难时轻松地恢复不同版本的数据集。

    2. RDB对于灾难恢复非常有用,它是一个紧凑的文件,可以传输到远程数据中心上。

    3. RDB最大限度地提高了Redis性能,因为为了保持Redis父进程所需做的惟一工作就是创建一个将完成所有其余工作的子进程。父实例永远不会执行磁盘I/O或类似的操作。

    4. 与AOF相比,RDB允许对大数据集进行更快的重启。

  • AOF方式:AOF方式在Redis中是默认未开启的,在开启AOF后,会将内容写入到appendonly.aof文件中,文件的内容是服务器接收到的所有对数据进行修改的命令集合,按照时间顺序追加到文件尾部,并且在故障恢复的时候,会优先读取appendonly.aof文件中的内容,因为aof的默认策略是每秒钟写入一次,所以当采用aof进行持久化的时候,最多也仅仅丢失一秒的数据。

    配置信息:redis.conf文件中

    image-20200327003834988

    劣势:

    随着服务运行时间越来越久,内存中的数据变更次数越来越多,会造成aof文件越来越大,当然我们可以在配置文件redis.conf中设置aof文件重写策略,默认当aof文件大小达到64mb且增长比例超过了之前是100%的时候进行重写,重写的规则是将内存中的数据的当前值全部以对应的set命令写入到新的aof文件中,比如当前aof文件100mb,重写之后80mb,那么只有当文件再次达到160mb(160>=80*2&&160>64)的时候才会再次进行重写,

    image-20200327005212374

AOF文件损坏修复:

​ 如果在AOF文件写入的过程中突然宕机,可能会导致aof文件损坏,我们可以使用redis-check-aof --fix命令来修复

####### 故障恢复

  • 若同时开启了RDB和AOF,那么在故障恢复的时候先使用AOF文件进行恢复,这样可以保证丢失最少的数据,但是如果我们想尽快的恢复Redis服务,可以允许丢失一部分数据,那么可以禁用AOF,只使用RDB,使用RDB之所以比AOF快,是因为AOF是一条条命令的去执行的,直到最终状态,RDB是一次性把所有数据的最终状态刷到内存的

  • AOF日志文件的命令通过可读的方式进行记录,这个特性非常适合做灾难性的误删除的紧急恢复。比如某人不小心用flushall命令清空了所有数据,只要这个时候后台rewrite还没有发生,那么就可以立即拷贝AOF文件,将最后一条flushall命令给删了,然后再将该AOF文件放回去,就可以通过恢复机制,自动恢复所有数据

主从复制

​ redis单节点存在单点故障问题,为了解决单点问题,一般都需要对redis配置从节点,然后使用哨兵来监听主节点的存活状态,如果主节点挂掉,从节点能继续提供缓存功能,从节点仅提供读操作,主节点提供写操作。对于读多写少的状况,可给主节点配置多个从节点,从而提高响应效率。

复制过程

  1. 从节点执行slaveof [masterIP] [masterPort],保存主节点信息 ;

  2. 从节点中的定时任务发现主节点信息,建立和主节点的socket连接;

  3. 从节点发送Ping信号,主节点返回Pong,两边能互相通信;

  4. 连接建立后,主节点将所有数据发送给从节点(数据同步);

  5. 主节点把当前的数据同步给从节点后,便完成了复制的建立过程;

  6. 接下来,主节点就会持续的把写命令发送给从节点,保证主从数据一致性。

哨兵

  • 主从复制存在的问题
    1. 一旦主节点宕机,从节点晋升为主节点,同时需要修改应用方的主节点地址,还需要命令所有从节点去复制新的主节点,整个过程需要人工干预;
    2. 主节点的写能力受到单机的限制;
    3. 主节点的存储能力受到单机的限制;
    4. 原生复制的弊端在早期的版本中也会比较突出,比如:redis复制中断后,从节点会发起psync。此时如果同步不成功,则会进行全量同步,主库执行全量备份的同时,可能会造成毫秒或秒级的卡顿。
  • 改善方式

哨兵模式是一种特殊的模式,Redis提供了哨兵命令,哨兵是一个独立的进程,原理是通过哨兵发送命令,然后等待Redis服务器的响应,进而实现对Redis实例的监控。

  • 运行方式

    • 通过命令的发送,Redis实例返回监控的运行状态,所有的Redis服务器

    • 当master机器宕机后,会随机选择一个slave节点作为master,然后通过发布订阅模式通知其他slave节点,修改配置信息,更改跟随的主机

    • 单哨兵模式相对来说不太可靠,毕竟会出现一言堂的情况,所以我们在使用哨兵的时候一般会采用多少兵模式,每一个哨兵都监控所有的Redis服务器,哨兵之间互相监控,当一个节点宕机后,只有指定数量的哨兵全部将其标记为下线,才会将节点移除

  • 故障切换过程

    • 主节点服务器宕机
    • 哨兵1检测到主节点宕机,然后将其标记为客观下线,这个时候主节点还是主节点,并未进行failover过程
    • 其他哨兵检测到主节点宕机,全部哨兵都会将主节点标记为客观下线
    • 标记为客观下线的哨兵数量达到指定数量(sentinel.conf中配置,尽量设置为N/2+1)的时候,由一个哨兵(Raft选举)进行投票,根据投票结果决定是否进行主节点切换(选择优先级最高的,优先级可以通过slave-priority来设置,若优先级相同,则以复制偏移量最大的为主,若偏移量也全部相同,则选择服务ID最小的那个)
    • 主节点切换完成之后,通过发布订阅模式让各个哨兵和从服务器更换主服务器配置,这个过程称为主观下线