简介

当数据量增大或者读写请求增多后,一台 Redis 服务器可能没办法再存储所有数据或者处理所有读写请求,那么就需要对 Redis 进行扩展,保证 Redis 在能存储所有数据对情况下,同时能正常处理读写请求。 P227

扩展读性能 P227

提高性能的几个途径 P228
  • 使用短结构:确保压缩列表的最大长度不会太大
  • 根据查询类型选择结构

    • 不要把列表当作集合使用
    • 不要获取整个散列,然后再客户端里面进行排序,而应使用有序集合
  • 大体积对象存储前进行压缩:减少读写所需的网络带宽。对比 lz4, gzip 和 bzip2 等压缩算法,选择对存储数据压缩效果和性能最好对压缩算法
  • 流水线和连接池:复制、处理故障、事务及性能优化 中介绍过流水线

扩展读性能最简单的方法就是添加只读服务器(复制、处理故障、事务及性能优化 中介绍过通过复制 (replication) 让一个 Redis 服务器成为从服务器及运作原理和管理方法),并只对主服务器进行写入(默认情况下,尝试对一个从服务器进行写入将引发一个错误,即使它是其他从服务器的主服务器)。 P228

添加从服务器 P228
  • 在配置文件中加上: slaveof <master-host> <master-port>
  • 向正在运行对 Redis 服务器发送: SLAVEOF <master-host> <master-port>

可以通向从服务器发送 SLAVEOF NO ONE 命令让其与主服务器断开。 P228

当一个主服务器有大量从服务器时,那么它们以前同步时就会耗尽大部分带宽,导致主服务器延迟变高,甚至导致主服务器断开和从服务器的连接。 P229

解决从服务器重同步 (resync) 问题的方法 P229

  • 构建树状的从服务器群组:通过构建二级从服务器降低主服务器需要传递给从服务器的数据量
  • 对网络连接进行压缩:使用带压缩带 SSH 隧道 (tunnel) 进行连接可以明显地降低带宽(注意使用 SSH 提供的选项让 SSH 连接在断线后自动连接)
故障转移 P230

Redis Sentinel 可以配合 Redis 的复制功能使用,并对下线的主服务器进行故障转移。 Redis Sentinel 是运行在特殊模式下的 Redis 服务器,它会监视一系列主服务器以及它们的从服务器,通过向主服务器发送 PUBLISH 命令和 SUBSCRIBE 命令,并向主服务器和从服务器发送 PING 命令,各个 Sentinel 进程可以自主识别可用的从服务器和其他 Sentinel 。当主服务器失效时,监视这个主服务器的所有 Sentinel 就会基于彼此共有的信息选出一个 Sentinel ,并从现有的从服务器中选择一个新的主服务器。然后被选中的 Sentinel 就会让剩余的其他从服务器去复制这个新的主服务器(默认设置下, Sentinel 会一个接一个地迁移从服务器,但这个数量可以通过配置选项进行修改)。 P230

Redis Sentinel 还提供了可选的故障转移通知功能,这个功能可以通过调用用户提供的脚本来执行配置更新等操作。 P230

扩展写性能和内存容量 P230

降低内存占用,减少需写入的数据 P231
  • 减少程序需要读取的数据量
  • 无关功能迁移至其他服务器
  • 写入 Redis 前,尝试内存中进行聚合(可以应用于分析和统计计算)
  • 使用锁或者 Lua 脚本代替 WATCH/MULTI/EXEC 事务
  • 使用 AOF 持久化会将写入的所有数据存储起来,可以考虑配置重写 AOF 或使用 RDB

当使用上述方法无法继续降低内存并提升性能之后,就说明已经遇到了只使用一台机器带来的瓶颈,那么就需要将数据分片到多台机器上面。我们介绍使用固定分片数量的方法,使得分片方案能够满足未来几年的预期,假设分片为 256 片。那么前期在数据量非常小的情况下没必要每个 Redis 服务器都使用独立的机器,可以多个 Redis 服务器共用一台机器,或者每个 Redis 服务器使用多个 Redis 数据库。 (注意:每台机器上运行多个 Redis 服务器时,确保监听不同的端口,并确保服务器写入的都是不同的快照文件/ AOF 文件。)P231

分片方法可以直接采用 降低内存占用 中提到的先使用散列函数计算出一个数字散列值,然后使用分片数量计算出当前采用哪个连接即可,即不再对 key 进行分片,而是转换为对连接进行分片。 P234

如果执行复杂查询时,感觉性能受到了 Redis 单线程设计的限制,并且机器有更多的计算核心、更多的通信网络资源,以及更多用于存储快照文件和 AOF 文件的磁盘 I/O ,那么可以考虑在单台机器上面运行多个 Redis 服务器。(当然也需要注意:确保一台机器上的多个 Redis 服务器监听不同的端口,并确保服务器写入的都是不同的快照文件/ AOF 文件。) P234

所思

如果网络 I/O 成为瓶颈的话,那么也可以考虑 Redis 6.0 的多线程特性。多线程特性主要是改进读写缓冲区的性能,因为这部分时间占比较大,而命令执行部分仍然使用单线程处理。这样既能提高整体性能,又可以保持设计简单,也不会引入新的并发问题。

对于一些全局唯一的数据,例如:唯一访问计数器等,可以额外使用一个连接专门存储类似的数据。

扩展复杂查询 P234
扩展搜索查询量 P235

实现内容搜索、定向广告和职位搜索 中提到的各种搜索方法都使用了类似 SUNIONSTORE, SINTERSTORE, SDIFFSTORE, ZINTERSTORE, ZUNIONSTORE 等命令,而这些命令都需要对 Redis 进行写入,所以前面介绍的只读从服务器将无法处理这些搜索。 P235

为了执行上述搜索,需要开启对从服务器对写入功能。 Redis 对配置文件中, slave-read-only 选项控制能否对从服务器进行写入,默认值为 yes 。所以只要将 slave-read-only 设置为 no 并重启从服务器,上述搜索即可正常执行。 P235

当机器拥有足够多的内存,并且它执行的都是只读操作(或者说这些操作不会修改其他查询所使用的底层数据)的时候,添加从服务器能够帮助我们实现横向扩展 (scale out) 。

扩展搜索索引大小 P235

为了对搜索查询进行连接分片,我们必须先对搜索索引进行连接分片,确保对于每个被索引的文档来说,同一个文档的所有数据都会被存储到同一个连接分片里面。 P236

分片搜索实际流程大致分为以下三个操作:

  • 编写能够在单个分片上面执行对查询程序,让它进行搜索并获取待排序对搜索结果
  • 在所有分片执行上面提到的查询程序
  • 对各个分片对查询结果进行合并,然后选出想要的那部分结果

注意:由于无法确定分页结果中的每条数据分别来自哪个分片,所以为了确保返回的数据在 [start, start + num] 内,程序需要从每个分片获取 [0, start + num] 内的数据,然后在内存中选出最终结果。 P236

所思

分片其实也就两种形式:

  • 对键进行分片:适用于大量类似键,但每个键对应的数据量不大的情况
  • 对数据进行分片:适用于每个键对应对数据量很大的情况

对键进行分片基本和连接分片绑定了,因为大量键只有在多连接对情况下分片才有用;而对数据进行分片既可以在单个连接中变成多个键,也可以转化成连接分片。

本文首发于公众号:满赋诸机(点击查看原文) 开源在 GitHub :reading-notes/redis-in-action

满赋诸机
12 声望3 粉丝