《Redis深度历险》学习笔记:管道&事务

管道

  • Redis 的管道特性由 Redis 客户端提供,客户端通过改变了读写的顺序带来性能的巨大提升。
  • Redis 的管道命令让客户端通过对管道中的指令列表改变读写顺序就可以大幅节省 IO 时间。
  • 管道中指令越多,效果越好。
  • 管道的本质:操作系统内核从为套接字分配的缓冲区(发送缓冲 send buffer / 接收缓冲 recv buffer)中读写数据。
  • 执行命令时,系统会调用 write 和 read 进行 IO 操作:
    • write 操作只负责将数据写到本地操作系统内核的发送缓冲,如果发送缓冲满了,则等待缓冲相应就是写操作 IO 操作的真正耗时。
    • read 操作只负责将数据从本地操作系统内核的接收缓冲中取出,如果接收缓冲是空的,则等待数据到来就是读操作 IO 操作的真正耗时。
  • 对于管道来说,连续的 write 操作根本就没有耗时,之后第一个 read 操作会等待一个网络的来回开销,然后所有的响应消息就都已经回送到内核的读缓冲了,后续的 read 操作直接就可以从缓冲拿到结果,瞬间返回。
  • 管道不仅减少了 RTT,同时也减少了 IO 调用次数(IO 调用涉及到用户态到内核态之间的切换)

传统请求相应模式
(Source: 被遗忘的站点)

……

《Redis深度历险》学习笔记:线程模型&持久化

线程模型

非阻塞IO

  • Redis、Node.js、Nginx 均是单线程服务,但他们都是服务器高性能的典范。
  • Redis 4.0 版本抛弃了单线程设计,转为多线程设计,但其主处理程序依然是单线程模型
  • Redis 使用单线程进行设计的原因:
    • 更好的可维护性,方便开发和调试:多线程模型存在竞争条件 (race condition)问题,多个进行的执行顺序会对共享内存的内容造成影响,需要额外设计锁逻辑。
    • 处理并发请求:将数据库的开、关、读、写都转换成了事件,使用 I/O 多路复用 机制轮询描述符处理并发连接,同时等待多个连接发送的请求。
    • Redis 服务中运行的绝大多数操作的性能瓶颈都不是 CPU:一个 Redis 服务在 1s 内可处理 100w 个用户请求,如无法满足,应使用分片将不同的请求交给不同的 Redis 服务器来处理,而不是在同一个 Redis 服务中引入大量的多线程操作。
  • 每一个网络连接都会产生一个文件描述符,并由执行事件循环(死循环)的多路复用模块接收,然后关联指令队列,交给文件事件分配器按顺序处理。一旦期间有任何事件到来,就可以立即返回。时间过了之后还是没有任何事件到来,也会立即返回。 多路复用 (Source: Redis 和 I/O 多路复用)
……

《Redis深度历险》学习笔记:Scan

Scan 命令

  • 使用 keys 命令来查找特定前缀的 key 列表有两个缺点:
    • 没有 offsetlimit 参数,该命令会一次性输出所有满足条件的结果。
    • keys 命令的时间复杂度为 O(n),大键查询会阻塞进程,造成卡顿
  • 通常使用 scan 命令来进行大键查询:
    • scan 命令的时间复杂度为 O(n),但通过游标分步进行,不阻塞进程,游标的唯一状态为返回的游标整数。
    • 提供 limit 参数,实际数量返回可多可少
    • 返回结果可能有重复,需要自行去重。
    • 遍历查询时若有数据变动,是否会返回符合条件的数据一切随缘
    • 返回为空不一定表示无结果,要看游标是否为零
  • Scan 命令可以用于各种类型数据的操作,如 zscan 用于 zset 集合、hscan 用于 hash 字典、sscan 用于 set 集合。
  • 在集群环境下,如果某个 key 太大,会数据导致迁移卡顿。
  • 在内存分配上,如果一个 key 太大,它扩容时会申请更大内存,导致卡顿。
  • 开发中,要尽量避免大 key 的产生
……

《Redis深度历险》学习笔记:GeoHash

  • 经纬度坐标使用关系数据库 (元素 id, 经度 x, 纬度 y) 存储,可以指定一个半径 r 使用一条 SQL 圈出一定范围内的元素。

    1
    2
    3
    4
    5
    6
    7
    
     SELECT
         id 
     FROM
         positions 
     WHERE
         x0 - r < x < x0 + r 
     AND y0 - r < y < y0 + r
    
  • GeoHash 算法将二维的经纬度数据映射到一维的整数,这样所有的元素都将在挂载到一条线上,距离靠近的二维坐标映射到一维后的点之间距离也会很接近。

  • 映射算法实际是对地图进行精细切分,然后对这些方格进行整数编码。编码后每个地图元素的坐标都将变成一个整数,越是靠近的方格编码越是接近。

……