Redis进阶小记

排序

  • SORT命令可以对列表类型、集合类型和有序集合类型键进行排序,并且可以完成与关系数据库中的连接查询相类似的任务。
  • SORT命令还可以通过ALPHA参数实现按照字典顺序排列非数字元素,
    • 如果没有加ALPHA参数的话,SORT命令会尝试将所有元素转换成双精度浮点数来比较,如果无法转换则会提示错误。
  • SORT命令的DESC参数可以实现将元素按照从大到小的顺序排列:
  • SORT命令还支持LIMIT参数来返回指定范围的结果。用法和 SQL 语句一样,LIMIT offset count,表示跳过前 offset 个元素并获取之后的count个元素。
  • 如果提供了 BY 参数,SORT 命令将不再依据元素自身的值进行排序,而是对每个元素使用元素的值替换参考键中的第一个“*”并获取其值,然后依据该值对元素排序。
  • 参考键虽然支持散列类型,但是“*”只能在“->”符号前面(即键名部分)才有用,在“->”后(即字段名部分)会被当成字段名本身而不会作为占位符被元素的值替换,即常量键名。
  • GET参数不影响排序,它的作用是使 SORT命令的返回结果不再是元素自身的值,而是GET参数中指定的键值
  • GET #会返回元素本身的值。
  • SORT命令的时间复杂度是O(n+mlog(m)),其中n表示要排序的列表(集合或有序集合)中的元素个数,m表示要返回的元素个数。当n较大的时候SORT命令的性能相对较低,并且Redis在排序前会建立一个长度为n 的容器来存储待排序的元素,虽然是一个临时的过程,但如果同时进行较多的大数据量排序操作则会严重影响性能。
  • 开发中使用SORT命令时需要注意以下几点。
    • 尽可能减少待排序键中元素的数量(使N尽可能小)
    • 使用LIMIT参数只获取需要的数据(使M尽可能小)
    • 如果要排序的数据数量较大,尽可能使用STORE参数将结果缓存

事务

  • 事务的命令发送给Redis,然后再让Redis依次执行这些命令。
  • Redis的事务没有关系数据库事务提供的回滚(rollback) 功能。为此开发者必须在事务执行出错后自己收拾剩下的摊子
  • WATCH 命令可以监控一个或多个键,一旦其中有一个键被修改(或删除),之后的事务就不会执行。监控一直持续到 EXEC 命令(
    • 由于WATCH命令的作用只是当被监控的键值被修改后阻止之后一个事务的执行,而不能保证其他客户端不修改这一键值,所以我们需要在EXEC执行失败后重新执行整个函数。
    • 如果使用 WATCH命令监测了一个拥有过期时间的键,该键时间到期自动删除并不会被WATCH命令认为该键被改变。
  • 可以限制 Redis 能够使用的最大内存,并让Redis按照一定的规则淘汰不需要的缓存键,这种方式在只将Redis用作缓存系统时非常实用。
    • 修改配置文件的maxmemory参数,限制Redis最大可用内存大小(单位是字节),当超出了这个限制时Redis会依据maxmemory-policy参数指定的策略来删除不需要的键直到Redis占用的内存小于指定内存。
    • LRU(Least Recently Used)算法即“最近最少使用”,其认为最近最少使用的键在未来一段时间内也不会被用到,即当需要空间时这些键是可以被删除的。

管道

  • 根据网络性能不同,往返时延也不同,大致来说到本地回环地址(loop back address)的往返时延在数量级上相当于 Redis 处理一条简单命令(如 LPUSH list 1 2 3)的时间。如果执行较多的命令,每个命令的往返时延累加起来对性能还是有一定影响的。
  • 通过管道可以一次性发送多条命令并在执行完后一次性将结果返回
  • 当一组命令中每条命令都不依赖于之前命令的执行结果时就可以将这组命令一起通过管道发出。管道通过减少客户端与 Redis 的通信次数来实现降低往返时延累计值的目的,

脚本

  • 减少网络开销:使用脚本功能完成同样的操作只需要发送一个请求即可,减少了网络往返时延。
  • 原子操作:Redis 会将整个脚本作为一个整体执行,中间不会被其他命令插入。换句话说在编写脚本的过程中无需担心会出现竞态条件,也就无需使用事务。事务可以完成的所有功能都可以用脚本来实现。
  • 复用:客户端发送的脚本会永久存储在 Redis 中,这就意味着其他客户端(可以是其他语言开发的项目)可以复用这一脚本而不需要使用代码完成同样的逻辑。

持久化

  • Redis支持两种方式的持久化,一种是RDB方式,另一种是AOF方式。
    • 前者会根据指定的规则“定时”将内存中的数据存储在硬盘上,而后者在每次执行命令后将命令本身记录下来。两种持久化方式可以单独使用其中一种,但更多情况下是将二者结合使用。
  • 当符合一定条件时Redis会自动将内存中的所有数据生成一份副本并存储在硬盘上,这个过程即为“快照”。
  • Redis会在以下几种情况下对数据进行快照:
    • 根据配置规则进行自动快照;
    • 用户执行 SAVE或 BGSAVE命令;
    • 执行 FLUSHALL命令;
    • 执行复制(replication)时。
  • 进行快照的条件可以由用户在配置文件中自定义,由两个参数构成:时间窗口M和改动的键的个数N。每当时间M内被更改的键的个数大于N时,即符合自动快照条件
    • save 900 1
    • save 300 10
    • save 60 10000
  • 当执行SAVE命令时,Redis同步地进行快照操作,
  • BGSAVE 命令可以在后台异步地进行快照操作,快照的同时服务器还可以继续响应来自客户端的请求。
  • 如果想知道快照是否完成,可以通过 LASTSAVE命令获取最近一次成功执行快照的时间
  • 当执行 FLUSHALL 命令时,Redis 会清除数据库中的所有数据。需要注意的是,不论清空数据库的过程是否触发了自动快照条件,只要自动快照条件不为空,Redis就会执行一次快照操作,当没有定义自动快照条件时,执行FLUSHALL则不会进行快照。
  • Redis默认会将快照文件存储在Redis当前进程的工作目录中的dump.rdb文件中,可以通过配置dir和dbfilename两个参数分别指定快照文件的存储路径和文件名
  • 为此需要确保 Linux 系统允许应用程序申请超过可用内存(物理内存和交换分区)的空间,方法是在/etc/sysctl.conf 文件加入 vm.overcommit_memory = 1,然后重启系统或者执行 sysctl vm.overcommit_memory=1 确保设置生效。
    • 当进行快照的过程中,如果写入操作较多,造成 fork 前后数据差异较大,是会使得内存使用量显著超过实际数据大小的,因为内存中不仅保存了当前的数据库数据,而且还保存着 fork 时刻的内存数据。进行内存用量估算时很容易忽略这一问题,造成内存用量超限。
  • 可以通过定时备份 RDB 文件来实现 Redis 数据库备份。RDB 文件是经过压缩(可以配置rdbcompression 参数以禁用压缩节省CPU占用)的二进制格式,所以占用的空间会小于内存中的数据大小,更加利于传输。
  • Redis启动后会读取RDB快照文件,将数据从硬盘载入到内存
  • 通常将一个记录1000万个字符串类型键、大小为1 GB 的快照文件载入到内存中需要花费20~30秒。
  • 一旦Redis异常退出,就会丢失最后一次快照以后更改的所有数据
  • AOF可以将Redis执行的每一条写命令追加到硬盘文件中,这一过程显然会降低Redis 的性能,但是大部分情况下这个影响是可以接受的
    • auto-aof-rewrite-percentage 100
    • auto-aof-rewrite-min-size 64mb
  • auto-aof-rewrite-percentage参数的意义是当目前的AOF文件大小超过上一次重写时的AOF文件大小的百分之多少时会再次进行重写
  • auto-aof-rewrite-min-size参数限制了允许重写的最小AOF文件大小,通常在AOF文件很小的情况下即使其中有很多冗余的命令我们也并不太关心。
  • 可以主动使用BGREWRITEAOF命令手动执行AOF重写。
  • 重写的过程只和内存中的数据有关,和之前的 AOF文件无关,这与RDB很相似,只不过二者的文件格式完全不同。
  • 在启动时Redis会逐个执行AOF文件中的命令来将硬盘中的数据载入到内存中,载入的速度相较RDB会慢一些。
  • 在默认情况下系统每30秒会执行一次同步操作,以便将硬盘缓存中的内容真正地写入硬盘,在这30秒的过程中如果系统异常退出则会导致硬盘缓存中的数据丢失。一般来讲启用AOF持久化的应用都无法容忍这样的损失,这就需要Redis在写入AOF文件后主动要求系统将缓存内容同步到硬盘中。在 Redis 中我们可以通过 appendfsync 参数设置同步的时机

哨兵

  • 在一个一主多从的Redis系统中,可以使用多个哨兵进行监控任务以保证系统足够稳健
  • 一个哨兵节点可以同时监控多个Redis主从系统,只需要提供多个sentinel monitor配置即可,
  • 哨兵会定时执行下面3个操作。
    • 每10秒哨兵会向主数据库和从数据库发送INFO命令。
    • 每 2 秒哨兵会向主数据库和从数据库的__sentinel__:hello 频道发送自己的信息。
    • 每1秒哨兵会向主数据库、从数据库和其他哨兵节点发送PING命令。
  • 当超过down-after-milliseconds选项指定时间后,如果被PING的数据库或节点仍然未进行回复,则哨兵认为其主观下线(subjectively down)
  • 询问其他哨兵节点以了解他们是否也认为该主数据库主观下线,如果达到指定数量时,哨兵会认为其客观下线
  • 选出领头哨兵后,领头哨兵将会开始对主数据库进行故障恢复
    • 首先领头哨兵将从停止服务的主数据库的从数据库中挑选一个来充当新的主数据库
    • 选出一个从数据库后,领头哨兵将向从数据库发送 SLAVEOF NO ONE命令使其升格为主数据库。而后领头哨兵向其他从数据库发送SLAVEOF命令来使其成为新主数据库的从数据库。最后一步则是更新内部的记录,将已经停止服务的旧的主数据库更新为新的主数据库的从数据库,使得当其恢复服务时自动以从数据库的身份继续服务。
  • 相对稳妥的哨兵部署方案是使得哨兵的视角尽可能地与每个节点的视角一致,即:
    • 为每个节点(无论是主数据库还是从数据库)部署一个哨兵;
    • 使每个哨兵与其对应的节点的网络环境相同或相近。

复制

  • 在 Redis 中使用复制功能非常容易,只需要在从数据库的配置文件中加入“slaveof 主数据库地址 主数据库端口”即可,主数据库无需进行任何配置。
  • 使用 SLAVEOF NO ONE命令来使当前数据库停止接收其他数据库的同步并转换成为主数据库。
  • 当一个从数据库启动后,会向主数据库发送 SYNC 命令。同时主数据库接收到 SYNC命令后会开始在后台保存快照(即RDB持久化的过程),并将保存快照期间接收到的命令缓存起来。当快照完成后,Redis会将快照文件和所有缓存的命令发送给从数据库。从数据库收到后,会载入快照文件并执行收到的缓存的命令。以上过程称为复制初始化。复制初始化结束后,主数据库每当收到写命令时就会将命令同步给从数据库
  • Redis 2.8版断线重连能够支持有条件的增量数据传输,当从数据库重新连接上主数据库后,主数据库只需要将断线期间执行的命令传送给从数据库,
  • Redis在主从数据库之间复制数据的过程本身是异步的,这意味着,主数据库执行完客户端请求的命令后会立即将命令在主数据库的执行结果返回给客户端,并异步地将命令同步给从数据库,而不会等待从数据库接收到该命令后再返回给客户端。这一特性保证了启用复制后主数据库的性能不会受到影响,但另一方面也会产生一个主从数据库数据不一致的时间窗口,
  • Redis 提供了两个配臵选项来限制只有当数据至少同步给指定数量的从数据库时,主数据库才是可写的:
    • min-slaves-to-write 3
    • min-slaves-max-lag 10
  • min-slaves-to-write表示只有当3个或3个以上的从数据库连接到主数据库时,主数据库才是可写的,
  • min-slaves-max-lag 表示允许从数据库最长失去连接的时间,如果从数据库最后与主数据库联系的时间小于这个值,则认为从数据库还在保持与主数据库的连接。
  • 可以通过复制功能建立多个从数据库节点,主数据库只进行写操作,而从数据库负责读操作。这种一主多从的结构很适合读多写少的场景,而当单个的主数据库不能够满足需求时,就需要使用Redis 3.0 推出的集群功能,
  • 手工通过从数据库数据恢复主数据库数据时,需要严格按照以下两步进行。
    • 在从数据库中使用 SLAVEOF NO ONE命令将从数据库提升成主数据库继续服务。
    • 启动之前崩溃的主数据库,然后使用SLAVEOF命令将其设置成新的主数据库的从数据库,即可将数据同步回来。
  • 当开启复制且主数据库关闭持久化功能时,一定不要使用 Supervisor 以及类似的进程管理工具令主数据库崩溃后自动重启。同样当主数据库所在的服务器因故关闭时,也要避免直接重新启动。这是因为当主数据库重新启动后,因为没有开启持久化功能,所以数据库中所有数据都被清空,这时从数据库依然会从主数据库中接收数据,使得所有从数据库也被清空,
  • 从2.8.18版本开始,Redis引入了无硬盘复制选项,开启该选项时,Redis在与从数据库进行复制初始化时将不会将快照内容存储到硬盘上,而是直接通过网络发送给从数据库,避免了硬盘的性能瓶颈。
  • 积压队列在本质上是一个固定长度的循环队列,默认情况下积压队列的大小为 1 MB,可以通过配置文件的repl-backlog-size选项来调整。很容易理解的是,积压队列越大,其允许的主从数据库断线的时间就越长。
  • 因为积压队列存储的内容是命令本身,如 SET foo bar,所以估算积压队列的大小只需要估计主从数据库断线的时间中主数据库可能执行的命令的大小即可。
  • 与积压队列相关的另一个配置选项是repl-backlog-ttl,即当所有从数据库与主数据库断开连接后,经过多久时间可以释放积压队列的内存空间。默认时间是1小时。

集群

  • 即使使用哨兵,此时的 Redis 集群的每个数据库依然存有集群中的所有数据,从而导致集群的总数据存储量受限于可用存储内存最小的数据库节点,
  • Redis 3.0版的一大特性就是支持集群
    • 集群的特点在于拥有和单机实例同样的性能,同时在网络分区后能够提供一定的可访问性以及对主数据库故障恢复的支持。另外集群支持几乎所有的单机实例支持的命令,对于涉及多键的命令(如MGET),如果每个键都位于同一个节点中,则可以正常支持,否则会提示错误。
    • 集群还有一个限制是只能使用默认的0号数据库,如果执行SELECT切换数据库则会提示错误。
  • 使用集群,只需要将每个数据库节点的cluster-enabled配置选项打开即可。每个集群中至少需要3个主数据库才能正常运行。
  • 集群会将当前节点记录的集群状态持久化地存储在指定文件中,这个文件默认为当前工作目录下的nodes.conf文件。每个节点对应的文件必须不同,否则会造成启动失败,所以启动节点时要注意最后为每个节点使用不同的工作目录,或者通过cluster-config-file选项修改持久化文件的名称
  • 分配主从数据库节点,分配的原则是尽量保证每个主数据库运行在不同的IP地址上,同时每个从数据库和主数据库均不运行在同一IP地址上,以保证系统的容灾能力。
  • 分配完成后,会为每个主数据库分配插槽,分配插槽的过程其实就是分配哪些键归哪些节点负责,
  • 对每个要成为子数据库的节点发送 CLUSTER REPLICATE主数据库的运行 ID来将当前节点转换成从数据库并复制指定运行 ID 的节点(主数据库)。
  • 在一个集群中,所有的键会被分配给16384个插槽,而每个主数据库会负责处理其中的一部分插槽
  • Redis 将每个键的键名的有效部分使用CRC16算法计算出散列值,然后取对16384的余数。这样使得每个键都可以分配到16384个插槽中,进而分配的指定的一个节点中处理
  • 如果命令涉及多个键(如MGET),只有当所有键都位于同一个节点时 Redis 才能正常支持。利用键的分配规则,可以将所有相关的键的有效部分设置成同样的值使得相关键都能分配到同一个节点以支持多键操作。比如,{ser102}:first.name 和{ser102}:last.name 会被分配到同一个节点
  • 如果一个至少负责一个插槽的主数据库下线且没有相应的从数据库可以进行故障恢复,则整个集群默认会进入下线状态无法继续工作。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值